Sunday, 27 November 2016

Making a simple accordion in Bootstrap 3


Creating an accordion for a web site is a breeze with Bootstrap 3. Just including the Bootstrap CSS and Javascript files and jQuery, we can start building an accordion. The accordion is a menu that shows one menu item a time. These menu items are panels and an accordion resembles a tab control with tabs, but is vertically stacked default. The following HTML page renders a simple accordion with Boostrap, CSS, Javascript and HTML.

<!DOCTYPE html>
<html>
<head>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
</head>
<body>

<div class="container">

  <div id="accordion" class="panel-group">
  
   <div class="panel panel-success">
    <div class="panel-heading">
     <h4 class="panel-title"><a href="#collapse1" data-toggle="collapse" data-parent="#accordion">Collapsible panel 1</a></h4>
    </div>
    <div id="collapse1" class="panel-collapse collapse">
     <div class="panel-body"><div class="well">This is a nice collapsible panel.</div><p>This is a test.</p></div>
     <div class="panel-footer">Panel footer</div>
    </div>   
   </div>
   
    <div class="panel panel-warning">
    <div class="panel-heading">
     <h4 class="panel-title"><a href="#collapse2" data-toggle="collapse" data-parent="#accordion">Collapsible panel 2</a></h4>
    </div>
    <div id="collapse2" class="panel-collapse collapse">
     <div class="panel-body">This is another nice panel</div>
     <div class="panel-footer">Hey a panel footer too!</div>
    </div>   
   </div>
   
    <div class="panel panel-default">
    <div class="panel-heading">
     <h4 class="panel-title"><a href="#collapse3" data-toggle="collapse" data-parent="#accordion">Collapsible panel 3</a></h4>
    </div>
    <div id="collapse3" class="panel-collapse collapse">
     <div class="panel-body">Omg a third panel!</div>
     <div class="panel-footer">Let's have another Panel footer too!</div>
    </div>   
   </div>
  
  </div>  
  
</div>

</body>
</html>

Make note that we here use the data-parent HTML5 extension to point to the parent element to get the accordion effect of only showing one panel at a time. Each panel consists of a panel with a panel heading, having a panel title and then a panel body and finally a panel footer. We use the CSS framework of Bootstrap to achieve this.

Sunday, 6 November 2016

Twitter 3 Bootstrap Autocomplete control for MVC 5 - Typeahead.js



This article will present a reusable user control for MVC applications using Twitter Bootstrap autocomplete feature. This feature is known as the Twitter Bootstrap typeahead. There is a lot of articles covering this topic on the Internet, my version will present a simple reusable control using MVC html helper that generates input fields of type text and hidden, i.e. a textbox and a hidden field to save the value. The MVC model binder will therefore be able to save the selected value in the list showing up in the autocomplete-enabled textbox into the target property specified. Of course, your needs for autocomplete feature will vary. The control described in this article will suit many developer's needs as they call up a controller action to get the desired data and then filter the drop down and also use the Bloodhound engine of Twitter to mark up the matches quite nicely. The end result is a very useful and nicely styled autocomplete textbox! It also supports keyboard navigation with arrow keys and Enter! Read on! Let's first look at the MVC Html helper itself first:

using System;
using System.Linq.Expressions;
using System.Web.Mvc;

namespace TwitterBootstrapAutoCompleteControl.HtmlHelpers
{

    public static class CustomMvcHelpers
    {

        public static MvcHtmlString AutoCompleteFor<TModel, TResult>(this HtmlHelper<TModel> htmlHelper,
            Expression<Func<TModel, TResult>> propertyToSet, string fetchUrl)
        {
            var metaData = ModelMetadata.FromLambdaExpression(propertyToSet, htmlHelper.ViewData);
            string propertyName = metaData.PropertyName;
            string jsComponent = string.Format(
            @"
              <input type ='hidden' id='{0}' />   
              <input type='text' id='{1}' class='typeahead form-control' placeholder='Search some values' />             
              <script type='text/javascript'> 
              <!-- AutoCompleteFor -->
              $(function() {{

                var suggestionEngine = new Bloodhound({{
                limit: 300,
                datumTokenizer: function(datum) {{
                    Bloodhound.tokenizers.obj.whitespace('value')
                }},
                queryTokenizer: Bloodhound.tokenizers.whitespace,
                remote:
                {{
                    url: '{2}',
                    filter: function(response) {{
                    var matches = [];
                    $.map(response, function(item) {{
                            var query = $('#{1}').val().toLowerCase();
                            var itemKey = item.Text.toLowerCase();                          
                            if (itemKey.indexOf(query) >= 0)
                            {{
                                matches.push(item);
                                //console.log(item);
                            }}
                        }});

                        return matches;
                    }}
                }}
            }});

            suggestionEngine.initialize();

            $('#{1}').typeahead({{
                hint: true,
                highlight: true,
                minLength: 1,           
        }}   , {{
                limit: 30,
                displayKey: 'Text',
                source: suggestionEngine.ttAdapter(),
                filter: function(data) {{
                    console.log(data);
                    return data;
                }},            
                templates:
                {{
                    suggestion: function(data) {{
                        return '<p>' + data.Text + '</p>';
                    }},
                empty: [
                '<div>',
                'No results matching',
                '</div>'
                ].join('\n'),
            }}
            }});

            $('#{1}').bind('typeahead:select', function(ev, suggestion) {{
             //console.log('Selection: ' + suggestion.Text);
         
            $('#{0}').val(suggestion.Id); 

           }});

          }});

        </script>

     ", propertyName, propertyName + "TextBox", fetchUrl);


            return MvcHtmlString.Create(jsComponent);
        }

    }

}

The MVC html helper will generate the HTML and the javascript that is required to generate a textbox and a hidden field with the autocomplete feature. Your MVC solution needs to include both jQuery and Twitter Bootstrap, plus the Twitter typeahead.js Nuget packages. In addition, you need to include the Bloodhound javascript file. Let's look at a controller action return Json data to our Html helper, which will use javascript to call that method:

        public ActionResult SomeData()
        {
            var countries = new List
            {
            new IdTextItem {Id = "US", Text = "United States"},
            new IdTextItem {Id = "CA", Text = "Canada"},
            new IdTextItem {Id = "AF", Text = "Afghanistan"},
            new IdTextItem {Id = "AL", Text = "Albania"},
            new IdTextItem {Id = "DZ", Text = "Algeria"},
            new IdTextItem {Id = "DS", Text = "American Samoa"},
            new IdTextItem {Id = "AD", Text = "Andorra"},
            new IdTextItem {Id = "AO", Text = "Angola"},
            new IdTextItem {Id = "AI", Text = "Anguilla"},
            new IdTextItem {Id = "AQ", Text = "Antarctica"},
            new IdTextItem {Id = "AG", Text = "Antigua and/or Barbuda"}
            };

            return Json(countries, JsonRequestBehavior.AllowGet);

        }

The Json method returns a JsonResult that is called once by this html helper. We filter the data on the client as can be seen in the Html Helper code. Let's look at the script bundle added in BundleConfig

   bundles.Add(new ScriptBundle("~/bundles/typeahead").Include(
                "~/Scripts/bloodhound.js",
                "~/Scripts/typeahead.bundle.js"
                ));

This Html helper will fetch data on load, while it is the text that the user is typing that filters the autocomplete list. If you need to pass in a text and use that in your fetchUrl, the html helper's filtering most likely can be adjusted, also look into the prefetch property of the typeahead. We also move up jQuery bundle to the top as the default MVC template has this bundle in the footer and not in the header, as will be required by the typeahead feature. Place in the section of _Layout.cshtml: @Scripts.Render("~/bundles/jquery") And in the bottom of the element of that same file: @Scripts.Render("~/bundles/typeahead") The html helper expects that your class contains the properties Id and Text. You can of course use an anonymous type to avoid creating a new type in your C#-code. The type could be a string or an integer for the Id.

 public class IdTextItem
    {

        public string Id { get; set; }

        public string Text { get; set; }

    }

We also do some adjustments to the style, since the default setting of the typeahead is borishingly looking. Add the following css styling to your view - or better - in a standalone css to be included in _Layout.cshtml. Save the following content into typeahead.css file which you place in the Content folder:
 

.tt-query {
  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
     -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
          box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
}

.tt-hint {
  color: #999
}

.tt-menu {    /* used to be tt-dropdown-menu in older versions */
  width: 422px;
  margin-top: 4px;
  cursor: pointer;
  padding: 4px 0;
  background-color: #fff;
  border: 1px solid #ccc;
  border: 1px solid rgba(0, 0, 0, 0.2);
  -webkit-border-radius: 4px;
     -moz-border-radius: 4px;
          border-radius: 4px;
  -webkit-box-shadow: 0 5px 10px rgba(0,0,0,.2);
     -moz-box-shadow: 0 5px 10px rgba(0,0,0,.2);
          box-shadow: 0 5px 10px rgba(0,0,0,.2);
}

.tt-suggestion {
  padding: 3px 20px;
  line-height: 24px;
}

.tt-suggestion.tt-cursor,.tt-suggestion:hover {
  color: #fff;
  background-color: #0097cf;

}

.tt-suggestion p {
  margin: 0;
}

Then adjust the StyleBundle in BundleConfig to include this css file:
      bundles.Add(new StyleBundle("~/Content/css").Include(
                      "~/Content/bootstrap.css",
                      "~/Content/site.css",
                      "~/Content/typeahead.css"));
Finally, here is an example of how to use this Html Helper:

<div class="row">
    <div class="col-md-4">    
        <h2>Autocomplete control html helper:</h2>   
        @Html.AutoCompleteFor(m => m.SomeProperty, Url.Action("SomeData", "Home"))
    </div>
</div>

The call to the html helper provides as the first argument the property of the Model of the MVC View and the second argument is an url to the action to fetch the data. This HTML helper should match a lot of developer's needs, but can of course be adjusted. The benefit of using a MVC Html helper is that you get reusability. You avoid having to fiddle with Javascript for each field you want to add to your MVC view where you want some autocomplete feature. Maybe you want to adjust the HTML helper to fit your needs. I have provided a link to a zip file of this Html Helper in a Visual Studio 2015 below, let me know if there are some tips or improvement you have in case you evaluate and test out this Html helper and find improvements. Note that the chosen value in the autocomplete list is set to a hidden field. The textbox will be named "propertyname"TextBox and the hidden field will be named "propertyname"

Download the source code for the autocomplete control (VS 2015 solution):

Download zip file [.zip | 31,7 MB] Reading material:

Monday, 3 October 2016

Disposing objects instantiated by MEF

Experienced developers that has worked with the official extensibility framework in .NET, the Managed Extensibility Framework (MEF) allows the composition of different parts into more composite parts through composition. MEF has got similarities to other IoC framework, where you register components and then make use of them in other components. However, with MEF there is a caveat and an important one too!
MEF beautifully abstracts away the IoC container and lets you specify parts that can be epxorted and imported. But if you inspect your application or system with a memory profiler such as JetBrains DotMemory or Red Gate Memory Profiler, you soon find out that much of the memory used by your applications is not properly disposed, i.e freed up after use. This is the case for nonshared (non-singleton) objects that are exported and then instantiated (imported). This means that your application will through continued use hold more and more memory. It will leak memory. By inspecting the memory dependency chain, one can see that MEF is the reason why the nonshared objects instantiated by MEF is not released, even after the objects are issued to be disposed.

I use in this code the ServiceLocator found with the Enterprise Library. Make note that my code will break up the dependency chain that hinders the object, but it does not mean that necessarily objects will be disposed right away. After all, .NET is managed and decides itself when objects are really to be disposed. But if you strive with releasing objects that are tied to memory even after use and also use MEF, read on.

I use the Factory pattern here to instantiate objects. I also use the new feature in .NET 4.5 that is called the ExportLifeTimeContext. I also use the ExportFactory in MEF inside a class called ExportFactoryInstantiator that does actual instantiation of the objects and keeping a track of these ExportLifeTimeContext objects. As noted, you need at least .NET 4.5 to make this work. For .NET 4.0 users, sorry - you are out of luck as far as I know. Upgrade your application to .NET 4.5 if possible and get the newer version of MEF.

The code below shows how you can accomplish control over memory resources using MEF:

MefFactory.cs

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using Microsoft.Practices.ServiceLocation;

namespace SomeAcme.Client.Infrastructure.IoC
{

    /// <summary>
    /// Factory for MEF Parts that is able to actually dispose MEF instantiated objects and get around bug in MEF 
    /// where objects never gets properly GC-ed when they should dispose
    /// </summary>
    /// <typeparam name="T"></typeparam>
    [Export]
    [PartCreationPolicy(CreationPolicy.Shared)]
    public class MefFactory<T> : IPartImportsSatisfiedNotification 
    {

        /// <summary>
        /// Backlog that keeps track of mef parts that are instantiated via this factory 
        /// </summary>
        private static readonly ConcurrentBag<ExportLifetimeContext<T>> MefParts = new ConcurrentBag<ExportLifetimeContext<T>>();

        /// <summary>
        /// Disposes parts added to the mef factory backlog of type T
        /// </summary>
        public static void DisposeMefParts()
        {
            ExportLifetimeContext<T> item;
            while (MefParts.TryTake(out item))
            {
                if (item != null)
                    item.Dispose();
            }
        }

        /// <summary>
        /// Disposes parts added to the mef factory backlog of type T by a given predicate condition
        /// </summary>
        public static void DisposeMefParts(Predicate<T> condition)
        {
            ExportLifetimeContext<T> item;
            List<ExportLifetimeContext<T>> lifeTimeProlonged = new List<ExportLifetimeContext<T>>();
            while (MefParts.TryTake(out item))
            {
                if (item != null && condition(item.Value))
                    item.Dispose();
                else 
                    lifeTimeProlonged.Add(item);
            }
            if (lifeTimeProlonged.Any())
            {
                //Add back again the parts not matching condition to the Concurrent bag
                foreach (var part in lifeTimeProlonged)
                {
                    MefParts.Add(part);
                }
            }
        }

        public void OnImportsSatisfied()
        {
            //marker interface
        }
   
        /// <summary>
        /// Resolves the mef part
        /// </summary>
        /// <returns></returns>
        public static T Resolve()
        {
            var factoryInstantiator = ServiceLocator.Current.GetInstance<ExportFactoryInstantiator<T>>();
            MefParts.Add(factoryInstantiator.Lifetime);
            return factoryInstantiator.Instance;
        }

    }
}



using System.ComponentModel.Composition;

namespace SomeAcme.Client.Infrastructure.IoC
{

    [Export]
    [PartCreationPolicy(CreationPolicy.NonShared)]
    public class ExportFactoryInstantiator<T> : IPartImportsSatisfiedNotification
    {

        [Import]
        public ExportFactory<T> Factory { get; set; }

        public T Instance { get; private set; }

        private ExportLifetimeContext<T> _lifeTime;

        public ExportLifetimeContext<T> Lifetime
        {
            get { return _lifeTime; }
        } 

        public void OnImportsSatisfied()
        {
            _lifeTime = Factory.CreateExport();
            Instance = _lifeTime.Value;
        }

        public bool DisposeOnDemand()
        {
            if (_lifeTime == null)
                return false;
            _lifeTime.Dispose();
            return Instance == null;
        }

    }

}

To instantiate an object, you do:

 var somepart = MefFactory.Resolve();

When you are done using the object you can dispose it with:

 MefFactory.DisposeMefParts(); 

Please note, you can use a Predicate here to filter out which object you want to keep and which ones to dispose.

And once more, the immediate disposal of the object is not guaranteed, since GC will still control the true lifetime of objects. You can use GC.Collect(); to force releasing disposed objects, but that will usually degrade application performance.

But the techniques shown here will over time really improve your application by gaining control on the memory footprint your application uses.

Resources

[1] Enterprise Library: https://msdn.microsoft.com/library/cc467894.aspx
[2] ServiceLocator class: https://msdn.microsoft.com/en-us/library/microsoft.practices.servicelocation.servicelocator(v=pandp.51).aspx
[3] ServiceLocator pattern: https://msdn.microsoft.com/en-us/library/ff648968.aspx
[4] Managed Extensibility Framework: https://msdn.microsoft.com/en-us/library/dd460648(v=vs.110).aspx