Lists list.js

List.js is a convention-based, flexible system for rendering an array of objects as html. While defaults are provided, the HTML used to render the list is largely left up to you. The power of lists comes in a set of actions that can be performed on the list, triggered via data-apis, allowing you to display dynamic lists by writing minimal JavaScript.

Override hooks

Templates can be overridden using either strings with the data-api or a compiled template function using the JavaScript API.

Most other overridable logic occurs in the private .getCurrentItems method. This method is called to generate a sorted, fitered and paginated list of items to render using the default or your custom template.

It calls the following functions in order if they are turned on, each of which has a default implementation and can be overridden by setting your own function: .getFilteredItems, .getSortedItems, .getPaginatedItems. You can also override .getCurrentItems entirely to set your own logic while retaining the build-in rendering logic.

Examples

Static

A list rendered by specifying the content as serialized JSON in a data attribute. This uses the default template to render each row, which renders a table row for each item with the data for each field specified in data-fields.

ID Name
{% highlight html %}
ID Name
{% endhighlight %}

Custom templates

The default template will work for simple displays, but you can always override what gets rendered for each item. The only requirement is that the template is wrapped in a single outer element, which is what events and data is bound to.

    {% highlight html %}
      {% endhighlight %}

      Note that the template doesn't use a specific rendering engine's syntax for including dynamic attributes in the element. Any element with a data-field attribute will be populated with the corresponding value using jQuery's .html() method.

      You can also specify the template inline inside the container element using normal HTML. If no template fields attributes are specified, then the value of the container's .html() method will be used as the template.

      {% highlight html %}
      {% endhighlight %}

      If you do require a more advanced templating engine, you can specify the source template as a string, and set a second configuration option, templateEngine, to your template compilation function. Because you are passing a JavaScript function, this must be done using the JavaScript API.

      {% highlight html %} {% endhighlight %}

      Custom template settings

      The only requirement of the templateEngine function is that it accept the raw template as a string, and return a compiled template function that accepts an item to be rendered.

      When using existing templating libraries, you can wrap their compilation functions to pass custom settings:

      {% highlight js %} $('#myList').list({templateEngine: function(t) { return _.template(t, { ... }) }}); {% endhighlight %}

      For example, you can set the { variable: "item" } option when using _.template to move each item's attributes into a namespace for your template:

      {% highlight html %}<%= item.attribute %>{% endhighlight %}

      Filtering

      Index.js also provides a convention around filtering the list of items before it is rendered, and lets you trigger those filters without JavaScript by using the data-api. Configure the filter using the data-filter and data-match attributes, which specify the comma-separated field and the value to match against. If any given field matches the value (using a fairly tolerant, case insensitive match), then the item will be included.

      Static Filters

      {% highlight html %}
      {% endhighlight %}

      Setting a custom filter function

      Additionally, you can set your own filtering function by calling .setFilter() on the element. Your filter function should return true to include the item, false to reject it.

      $("#myList").list('setFilter', 'myFilterID', function(item) { ... })

      Dynamic Filters

      By attaching a data-filter trigger to an input element, you can filter based on dynamic user input. Input elements use their .val() value instead of their data-match value.

      {% highlight html %}
      {% endhighlight %}

      Multiple Filters

      Filters are stored internally as a hash keyed by the value of data-filter. For simplicity, all filters are always applied on top of one another - an item must match every filter to be included.

      If you want more complex filtering logic, specify your own filtering function with .list('setFilter, ...') below.

      The table at right shows the active filters at any given moment. The button filters have data-filter="id", and the search box has data-filter="id, name"; they're different, so two filters will be created.

      Current filters
      {% highlight html %}
      Current filters
      {% endhighlight %}

      Custom event triggers

      By default, filters are applied when a user clicks on a static trigger, or the value of a user input changes. But you can change the event that Index.js listens for on the given element with a data-trigger attribute. This lets us update the list more or less frequently.

      <input type="text" ... data-trigger="keyup">

      Sorting

      Any element can become a trigger for sorting your list of items. Each requires a data-sort and a data-target. Include the sort-control class to render feedback about which sort state is active.

      The sort's status is kept track of by the trigger cycling through the sort-ascending and sort-descending classes. Include either one to initialize the sort. Only one sort for an Index can be active at a time.

      ID (click me) Name (click me)
      {% highlight html %}
      ID (click me) Name (click me)
      {% endhighlight %}

      Setting a custom sort function

      When you click on a trigger element, Index.js creates a sort function based on the field specified with data-source and the direction you are sorting in, and saves it as the sort function. To provide some sensible defaults, sorting is case-insensitive.

      You can also set your own sort function by calling .setSort() on the element:

      $("#myList").list('setSort', function(a, b) { ... })

      Pagination

      When your list of items gets too long, you'll want to start paginating your data.

      Use the input field to change the current page, and the items displayed at the left should update.

      {% highlight html %}
      {% endhighlight %}

      Rendering page controls

      It's up to you to render any sort of pagination controls you want to navigate over your list. Use the paginated.ac.list event described below to retrieve information on page count / current page / etc, and then use the page instance method to update the current page.

      Selection

      Many lists have some concept of selecting one or more items. Index.js handles these cases by giving each item in the list a boolean state of true or false. If you render a data-toggle="select" into a list element, it will serve as a toggle between those two states. Reflect the status by setting a data-selected-class to apply to 'active' element.

      {% highlight html %}
      {% endhighlight %}

      Events are triggered when any element is selected or unselected.

      Usage

      The list plugin centers around an element that has a single array of items attached to it, and knows how to render out that list at any time. You can control the content of the list, and the template it renders with.

      Via data attributes

      Render a list without writing JavaScript. Set data-control="list" on your list container element to trigger it automatically, along with a data-items attribute containing a serialized array of items.

      {% highlight html %}
      {% endhighlight %}

      Via JavaScript

      Render a list by calling .list() on a container element.

      {% highlight js %}$('#myList').list(options){% endhighlight %}

      Options

      Options can be passed via data attributes or JavaScript. For data attributes, append the option name to data-, as in data-items="".

      The list container

      Name type default description
      items native or serialized array Describes the complete set of items that should be rendered.
      fields string Comma-separated list of fields to render as cells in a table row when using the default template
      template string, function table row, use with fields Compiled or uncompiled template function used to render each item in the list. Use in conjunction with template-engine if using special syntax.
      template-engine function If you want to use a custom templating library. Function that takes a template as a string and returns a function to render that template for a given item. For example, _.template.
      filtering on or off on Turn filtering on. Uses $('#list').data('ac.list').getFilteredItems, which can be overridden.
      sorting on or off on Turn sorting on. Uses $('#list').data('ac.list').getSortedItems, which can be overridden.
      pagination on or off off Turn pagination on. Uses $('#list').data('ac.list').getPaginatedItems, which can be overridden. If off, then every visible item will be rendered.
      page-size integer 20 How many pages to display at once when pagination is turned on.
      current-page integer 1 What page to start on when pagination is turned on.
      selected-class string Class to apply to 'active' items in the list.
      states array of booleans Default an item's state to on by passing true at its index in the items array.
      show boolean true Renders the Index after initialization.
      remote path false If a remote URL is provided, content will be loaded one time via jQuery's .getJSON method and stored as the Index's items. If show is true, list will not be rendered until after content is loaded. You can thus use the original contents of the container element as a loading indicator.

      Filter triggers

      Name type default description
      filter string Comma-separated list of field names against which the filter will be applied. If the filter matches the value of any field, the item will be displayed.
      match string Value to be compared to the item's attributes. When using the default filter function, this value will be compared using a case-insensitive search, and if it is found anywhere in the item's relevant attributes, it will match.
      trigger string click, change Event that will trigger the filter. Defaults to click for static elements, change for input elements.

      Sort triggers

      Name type default description
      sort string Field to sort by.
      states string ascending,descending Comma-separated list of which states to cycle through when toggling the sort. Can specify any combination of ascending, descending, and / or off.

      Methods

      .list(options)

      Activates your content as a list. Accepts an optional options object. You may re-initialize the list by calling this method again with an Object, and the new options will be merged into the existing options.

      {% highlight js %} $('#myList').list({ pagination: 'off' }) {% endhighlight %}

      .list('destroy')

      Removes the list and all associated data. Call this before re-instantiating if you wish to start fresh.

      {% highlight js %}$('#myList').list('destroy'){% endhighlight %}

      .list('show')

      Calculates the list of visible items and renders them into it's container element.

      {% highlight js %}$('#myList').list('show'){% endhighlight %}

      .list('setFilter', key, function)

      Manually sets a filter function to be applied. Can be used multiple times with different keys. Pass undefined as the final argument to remove an existing filter.

      {% highlight js %}$('#myList').list('setFilter', function(item) { ... }){% endhighlight %}

      .list('setSort', function)

      Manually sets a sort function. Only one sort function can exist at a time. Pass undefined as the function to remove an existing filter.

      {% highlight js %}$('#myList').list('setSort', function(a, b) { ... }){% endhighlight %}

      .list('setCurrentPage', Integer)

      Manually sets the current page of the list.

      {% highlight js %}$('#myList').list('setCurrentPage', 2){% endhighlight %}

      .list('select', selector || Integer)

      Changes the state of the items represented by the selector, or at the specified index, to true. You can also pass an array of indices. Triggers the toggle events.

      {% highlight js %}$('#myList').list('select', 2) $('$myList').list('select', $('.selectedItem')){% endhighlight %}

      .list('deselect', selector || Integer)

      Changes the state of the items represented by the selector, or at the specified index, to false. You can also pass an array of indices. Triggers the toggle events.

      {% highlight js %}$('#myList').list('deselect', 2) $('$myList').list('deselect', $('.deselectedItem')){% endhighlight %}

      .list('toggle', selector || Integer)

      Reverses the state of the items represented by the selector, or at the specified index. You can also pass an array of indices. Triggers the toggle events.

      {% highlight js %}$('#myList').list('toggle', 2) $('$myList').list('toggle', $('.item')){% endhighlight %}

      .list('add', Object[, index])

      Adds the passed Object as an item to the list. If you also pass an optional index, the item will be inserted at that index in the list.

      {% highlight js %}$('#myList').list('add', {"id": 1}){% endhighlight %}

      .list('update', index || element || Object, Object)

      Updates an item in the list, and rerenders that element in the container element. You can specify the item to update by passing either the item's index, current DOM element, or the underlying data Object.

      {% highlight js %} $('#myList').list('update', $('#specialListItem'), {"id": 1}) $('#myList').list('update', 0, {"id": 1}) {% endhighlight %}

      .list('delete', index || element || Object)

      Deletes the item at index index or represented by the element.

      Deletes an item in the list, and removes that element from the container element. You can specify the item to delete by passing either the item's index, current DOM element, or the underlying data Object.

      {% highlight js %} $('#myList').list('delete', $('#specialListItem')) $('#myList').list('delete', 0) {% endhighlight %}

      Events

      Adcom's list class exposes a few events for hooking into functionality.

      Event Type Description
      show.ac.list This event is fired immediately when the show instance method has been called.
      shown.ac.list This event is fired when the visible items have been rendered and inserted into the container element. The list of rendered items is available as the items property of the event.
      toggle.ac.list This event is fired when the status of an item is about to be updated. The item whose state has been updated is available as the item property of the event, along with it's index and updated state. If rendered, the item's element is available as the target property of the event.
      toggled.ac.list This event is fired when the status of an item has been updated. The item whose state has been updated is available as the item property of the event, along with it's index and updated state. If rendered, the item's element is available as the target property of the event.
      sortChange.ac.list This event is fired immediately when the setSort instance method has been called.
      sortChanged.ac.list This event is fired when the sort function for the list has been changed or removed. The new sort function is available as the function property of the event.
      filterChange.ac.list This event is fired immediately when the setFilter instance method has been called. The key for this filter function is available as the key property of the event. The value of the filter (undefined to delete, string or function) is filter.
      filterChanged.ac.list This event is fired when one of the filter functions for the list has been changed or removed. The key for this filter function is available as the key property of the event, the value of the filter (undefined to delete, string or function) is filter, and the new filter function is available as function.
      pageChange.ac.list This event is fired immediately when the setCurrentPage instance method has been called.
      pageChanged.ac.list This event is fired when the current page has been changed. The new current page is available as the page property of the event.
      paginated.ac.list This event is fired when the rendered list of items has been paginated in preparation for rendering. Fires before the items have been rendered or inserted into the container element. The current page, number of pages, the count of items, the items, and the start and end positions of the current page are available as properties of the event.
      loaded.ac.list This event is fired when the list has loaded content using the remote option.
      {% highlight js %} $('#myList').on('shown.ac.list', function (e) { // do something... }) {% endhighlight %}