C# Tutorial: Saving the State of a Bootstrap Collapsible Panel Using JavaScript and Cookies

In this tutorial, I will show you how you can cause a browser to remember the state (open or closed) of a Bootstrap collapsible panel using C#, JavaScript, and cookies.  First, open a new project in Visual Studio by navigating to File -> New -> Project… (or hit Ctrl+Shift+N).

Visual Studio New Project

Next, I will select Templates -> Visual C# -> Web -> ASP.NET Empty Web Application and name the project CollapsiblePanelDemo.  I will also check the option to Create a directory for solution and hit the OK button to continue.

CollapsiblePanelDemo Project

Now, I will add an ASP.NET Web Form page to my project by right clicking the project name and selecting Add -> Web Form.  In the Specify Name of Item window, I will type in Default and then click on the OK button.

Add Web Form

In the Source view mode, I will add the following lines of code.  Place this in the HTML header section:

<title>CollapsiblePanelDemo</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.0/css/bootstrap.min.css" type="text/css" />

Source View

And place this code right above the </body> tag of the page:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="http://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>

These are the Bootstrap libraries which will allow you to create a collapsible panel using relative simple markup.  Let’s start by placing a button on the page.  Place this piece of code in between the <form> tags:

<div class="container">
<button type="button" class="btn btn-primary" data-toggle="collapse" data-target="#Panel1" id="panel1State" onclick="setCookie('Panel1')">Panel 1</button>
</div>

Let’s add another button by placing this piece of code underneath the first button:

<button type="button" class="btn btn-primary" data-toggle="collapse" data-target="#Panel2" id="panel2State" onclick="setCookie('Panel2')">Panel 2</button>

Add a line break and create the panels by adding this code right after the second button:

<br />
<div id="Panel1" class="collapse">This is Panel 1.</div>
<div id="Panel2" class="collapse">This is Panel 2.</div>

Here’s a quick breakdown of how the panels work.  The panels are created using the <div> tag and to differentiate the panels, we use the id attribute.  The data-target attribute in the <button> tag references the id value of the panel it’s supposed to control.  The onclick attribute in the <button> tag will be used later to call a JavaScript function which will place a cookie on the computer for the duration of the session to remember the last “state” of the panel.  Go ahead and hit F5 at this point to compile your application so that you can test out how the buttons currently work.

Test Run 1

Now, let’s write some JavaScript that will help your application remember the last state (open or closed) of the panel.  In the Solution Explorer window and under Solution, right click on “CollapsiblePanelDemo” and navigate to Add -> JavaScript file.  Name the file panelState and click on the OK button.

Add JavaScript File

Enter the following code in the file and save it:

function getCookie(cname) {
  var name = cname + "=";
  var ca = document.cookie.split(';');
  for (var i = 0; i < ca.length; i++) {
    var c = ca[i];
    while (c.charAt(0) == ' ') c = c.substring(1);
    if (c.indexOf(name) != -1) {
      return c.substring(name.length, c.length);
    }
  }
  return "";
}

function setCookie(sectionName) {
  var lastState = getCookie(sectionName);
  if (lastState == "" || lastState == "off") {
    document.cookie = sectionName + "=on";
  }
  else {
    document.cookie = sectionName + "=off";
  }
}

function setState() {
  if (getCookie("Panel1") == "" || getCookie("Panel1") == "off") {
    document.getElementById("Panel1").className = "collapse";
  }
  else {
    document.getElementById("Panel1").className = "collapse in";
  }

  if (getCookie("Panel2") == "" || getCookie("Panel2") == "off") {
    document.getElementById("Panel2").className = "collapse";
  }
  else {
    document.getElementById("Panel2").className = "collapse in";
  }
}

One function gets the cookie (i.e. reads the data), another sets it, and the last function is used to determine the last state the panel was in (i.e. open or closed).  Let’s add a reference to this JavaScript file by adding this markup right above the </body> tag of our page:

<script src="panelState.js"></script>

We also add an onload event in the <body> tag to call the setState() function:

<body onload="setState()">

Now, let’s add a Submit button that will initiate a post-back.  Drag an ASP.NET button control on to the form and place it right under the second button.  Change the ID to “submitButton” and Text to “Submit“.  I’ll also add this attribute (CssClass=”btn btn-primary”) to the button control for styling.  And that’s it.  Hit F5 to compile and run your application to test it.  You’ll notice that when you click on a Panel button and then click on the Submit button or if you reload the page that the browser will remember the last state (open or closed) that the panel was in and keep it that way.  This behavior will be in effect for both regular load and post-back operations until the browser is closed.  If you’d like to review the code, you can download the entire Visual Studio project using the link below:

CollapsiblePanelDemo

Incorrect Space Usage Reporting in SQL Server

One of our customers for my company asked a great question the other day. He was wondering why after deleting/truncating a lot of data in a table, it was providing inaccurate results after executing the system stored procedure sp_spaceused on a table. He only had 1 row of data, and it couldn’t possibly be taking up 3 MB of disk space. The answer can be found on Microsoft’s Official documentation regarding sp_spaceused on the web.  The stored procedure actually gets it data from the sys.allocation_units and sys.partitions catalog views,  and according to the documentation:

When you drop or rebuild large indexes, or drop or truncate large tables, the Database Engine defers the actual page deallocations, and their associated locks, until after the transaction commits. Deferred drop operations do not release allocated space immediately. Therefore, the values returned by sp_spaceused immediately after dropping or truncating a large object may not reflect the actual disk space available.

Fortunately, there is a simple solution to this problem.  You can update the statistics by either executing this Transact-SQL statement:

EXEC sp_spaceused @updateusage = N'TRUE';

or this one:

DBCC UPDATEUSAGE (0)

Both will update the statistics for the current database.

The .htaccess File is Useful in a Windows Hosting Environment

There is a misconception about the .htacces file and its usefulness in a Windows hosting environment.  Normally, this is the file that controls the configuration settings for Linux/UNIX/Apache hosting environments, and its Window’s equivalent is the web.config file.  I finally found a use for it the other day, and it’s with WordPress itself.  Unfortunately, I didn’t have time to blog about it when I found the fix, and it seems that I am unable to reproduce the problem.  But I wanted to at least write about the events that led up to the problem and what I did to fix it to hopefully help reduce the frustration for someone else encountering the same issue.  This site is about troubleshooting computer problems after all.  And who knows?  That someone might be me again after a few months as it’s getting harder to remember things as I age.

The problem was created when I tried to transfer WordPress from one Windows hosting provider to another.  Of course, I know each hosting provider is configured differently, and I was running into errors during the move.  I finally isolated it to a problem with URL Rewrite.  Apparently, the other hosting provider disabled delegation for URL Rewrite, so it broke a lot of my WordPress links.  After scouring the Internet, I found the solution, and WordPress will actually tell you the solution.  You just need to click on Settings and Permalinks.  WordPress will throw some PHP errors, but I never noticed that way at the bottom, it tells you that you need to include some code in the .htaccess file.  Basically, it’s to include the mod_rewrite (Linux/UNIX/Apache’s equivalent for IIS’ URL Rewrite) rules.  Normally, WordPress will look at the web.config file for rewrite rules in a WIndows environment, but since the hosting provider disabled delegation for it, IIS would error out.  This means I couldn’t use them.  But once I created an .htaccess file with the mod_rewrite rules and uploaded it, my links started working again.  It’s good to know that WordPress will look at the .htaccess file for configuration information if it cannot find it in the web.config file.  And I believe here’s the code that you need to add to the .htaccess file to get everything working again:

# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>

# END WordPress