Skip to content

Instantly share code, notes, and snippets.

@alexweissman
Last active May 20, 2016 16:48
Show Gist options
  • Select an option

  • Save alexweissman/07ab1ad90c345ff9fe5a000b063dcbc7 to your computer and use it in GitHub Desktop.

Select an option

Save alexweissman/07ab1ad90c345ff9fe5a000b063dcbc7 to your computer and use it in GitHub Desktop.
load some kind of data from a JSON API into a dropdown menu
{
"count": 6,
"rows": [
{
"id": 1,
"name": "Indiana University Bloomington"
},
{
"id": 2,
"name": "Ivy Tech Bloomington"
},
{
"id": 5,
"name": "Loyola"
},
{
"id": 6,
"name": "Montgomery College Rockville"
},
{
"id": 3,
"name": "University of Maryland College Park"
},
{
"id": 4,
"name": "University of Maryland University College"
}
],
"count_filtered": 6
}
<!-- This is the dropdown item to populate with messages -->
<li class="dropdown">
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
<i class="fa fa-university fa-fw"></i> <span class="dropdown-value"></span> <i class="fa fa-caret-down"></i>
</a>
<ul class="dropdown-menu" id="main-menu-institutions">
</ul>
<!-- /.dropdown-institutions -->
</li>
<script>
$(document).ready( function () {
/**
* Institution menu - for selecting current institution context
*/
$('#main-menu-institutions').viewMenu({
'institutionUrl': site.uri.public + '/api/institutions'
}).on("change", function () {
// Store selected institution_id in localStorage
localStorage.setItem('institution_id', $(this).data('selected-id'));
// Debug - remove in production
console.log(localStorage.getItem('institution_id'));
}).on("loaded", function () {
// Add a final "all" option. This will set the context as "all institutions I have access to"
$('#main-menu-institutions').viewMenu('addItem', {
id: "-1",
name: "All institutions",
alternate: true
});
// Set value on page load from localStorage
var institution_id = localStorage.getItem('institution_id');
if (institution_id !== null) {
$('#main-menu-institutions').viewMenu('set', institution_id);
}
});
});
</script>
/**
* CSS for view-menus in topbar.
*
* TODO: I don't like that we have to scope this to .navbar-userfrosting .navbar-top-links. This is a limitation of sb-admin, which we should fix.
*/
.navbar-userfrosting .navbar-top-links .view-menu {
padding: 0px;
}
.navbar-userfrosting .navbar-top-links .view-menu li a {
border-bottom: 1px solid #eee;
padding: 8px 15px 8px 30px !important;
}
.navbar-userfrosting .navbar-top-links .view-menu .view-menu-item-alt a {
font-weight: 600;
}
.navbar-userfrosting .navbar-top-links .view-menu .view-menu-loading {
text-align: center;
padding: 20px;
}
.navbar-userfrosting .navbar-top-links .view-menu .search-control {
padding: 5px;
border-bottom: 1px solid #eee;
}
/**
* viewMenu
*
* A plugin that renders a menu for viewing the site in different modes. For example, toggling different institutions, semesters, etc.
* Adapted from https://gist.github.com/Air-Craft/1300890
*/
(function( $ ){
/**
* The plugin namespace, ie for $('.selector').viewMenu(options)
*
* Also the id for storing the object state via $('.selector').data()
*/
var PLUGIN_NS = 'viewMenu';
var Plugin = function ( target, options ) {
this.$T = $(target);
/** #### OPTIONS #### */
this.options= $.extend(
true, // deep extend
{
institutionUrl : "/api/institutions",
logosUrl : "/logos",
searchInterval : 500,
DEBUG: false
},
options
);
// DOM to generate menu item
this._menu_item_html="";
this._menu_item_html += "<li class=\"view-menu-item\">";
this._menu_item_html += " <a href=\"#\" class=\"js-menu-item-select\" data-id=\"{{id}}\">{{name}}<\/a>";
this._menu_item_html += "<\/li>";
// Handlebars template method
this._menu_item_template = Handlebars.compile(this._menu_item_html);
// DOM to generate menu search box
this._menu_search_html="";
this._menu_search_html += "<li class=\"search-control\">";
this._menu_search_html += " <input type=\"text\" class=\"form-control\" placeholder=\"Search...\"\/>";
this._menu_search_html += "<\/li>";
this._init( target, options );
return this;
}
/** #### INITIALISER #### */
Plugin.prototype._init = function ( target, options ) {
var base = this;
var $el = $(target);
// Add container class
$el.toggleClass("view-menu", true);
// Get the parent dropdown item
var $dropdown = base.$T.closest('.dropdown');
// Create search field
$(this._menu_search_html).appendTo(base.$T);
// Prevent dropdown from closing when search control is clicked
base.$T.find(':input').on('click', function(e){
e.stopPropagation();
});
// Populate menu items
base._populateMenu();
// Search box
base.timer = 0;
base.$T.find('.search-control input').on('input', function(e) {
var $searchBox = $(this);
base._populateMenu({
filters: {
name: $searchBox.val()
}
});
});
return this;
};
Plugin.prototype.set = function (id) {
var base = this;
base.$T.data("selected-id", id);
// Set the visible value in menu control
var $item = base.$T.find("[data-id=" + id + "]");
var $dropdown = base.$T.closest('.dropdown');
$dropdown.find(".dropdown-value").html($item.html());
base.$T.trigger("change");
return base.$T;
};
Plugin.prototype.addItem = function (options) {
var params = {
id : "0",
name: "Unknown"
};
$.extend(true, params, options[0]);
var base = this;
var newMenuItemTemplate = base._menu_item_template(params);
var newMenuItem = $(newMenuItemTemplate).appendTo(base.$T);
if (params.alternate && params.alternate === true)
newMenuItem.addClass("view-menu-item-alt");
// Register click handler
newMenuItem.find(".js-menu-item-select").on('click', function () {
base.set($(this).data('id'));
});
};
/** #### PRIVATE METHODS #### */
Plugin.prototype._populateMenu = function (options){
var base = this;
clearTimeout(base.timer); // Clear the timer so we don't end up with dupes.
// Clear out any existing items
base.$T.find(".view-menu-item").remove();
// Add loading icon, if it doesn't already exist
if (!base.$T.find(".view-menu-loading").length)
$("<li class=\"view-menu-loading\"><i class=\"fa fa-spinner fa-4x fa-spin\"></i></li>").appendTo(base.$T);
base.timer = setTimeout(function() { // assign timer a new timeout
var url = base.options.institutionUrl;
$.getJSON(url, options).done(function(data) {
// Remove loading icon
$(".view-menu-loading").remove();
// Add each menu item and register a click handler
jQuery.each(data['rows'], function(idx, row) {
base.addItem([row]);
});
// Items loaded
base.$T.trigger("loaded");
});
}, base.options.searchInterval);
};
/**
* EZ Logging/Warning (technically private but saving an '_' is worth it imo)
*/
Plugin.prototype.DLOG = function ()
{
if (!this.DEBUG) return;
for (var i in arguments) {
console.log( PLUGIN_NS + ': ', arguments[i] );
}
}
Plugin.prototype.DWARN = function ()
{
this.DEBUG && console.warn( arguments );
}
/*###################################################################################
* JQUERY HOOK
###################################################################################*/
/**
* Generic jQuery plugin instantiation method call logic
*
* Method options are stored via jQuery's data() method in the relevant element(s)
* Notice, myActionMethod mustn't start with an underscore (_) as this is used to
* indicate private methods on the PLUGIN class.
*/
$.fn[ PLUGIN_NS ] = function( methodOrOptions ) {
if (!$(this).length) {
return $(this);
}
var instance = $(this).data(PLUGIN_NS);
// CASE: action method (public method on PLUGIN class)
if ( instance
&& methodOrOptions.indexOf('_') != 0
&& instance[ methodOrOptions ]
&& typeof( instance[ methodOrOptions ] ) == 'function' ) {
return instance[ methodOrOptions ]( Array.prototype.slice.call( arguments, 1 ) );
// CASE: argument is options object or empty = initialise
} else if ( typeof methodOrOptions === 'object' || ! methodOrOptions ) {
instance = new Plugin( $(this), methodOrOptions ); // ok to overwrite if this is a re-init
$(this).data( PLUGIN_NS, instance );
return $(this);
// CASE: method called before init
} else if ( !instance ) {
$.error( 'Plugin must be initialised before using method: ' + methodOrOptions );
// CASE: invalid method
} else if ( methodOrOptions.indexOf('_') == 0 ) {
$.error( 'Method ' + methodOrOptions + ' is private!' );
} else {
$.error( 'Method ' + methodOrOptions + ' does not exist.' );
}
};
})(jQuery);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment