Skip to content
This repository has been archived by the owner on Oct 8, 2021. It is now read-only.

Listview: Expose method facilitating arbitary list item filtering #5930

Closed
dueckes opened this issue Apr 24, 2013 · 7 comments
Closed

Listview: Expose method facilitating arbitary list item filtering #5930

dueckes opened this issue Apr 24, 2013 · 7 comments

Comments

@dueckes
Copy link

dueckes commented Apr 24, 2013

The filter capabilities bundled within Listview's are particularly useful.

However, should I wish to filter by a different control, such as a radio group intended to filter the list based on the state of an attribute of a list item, my task becomes significantly harder.

The likely best solution at this point is to duplicate much of the functionality in listview.filter.js (which takes care of hiding dividers, etc).

It would be great to see a method exposed accepting a callback for each list item that facilitates arbitrary filtering, e.g.

$("#my-list-view").filterBy(function (item) { // true hides item });

@jaspermdegroot
Copy link
Contributor

@dueckes

I like the idea of making it possible to filter a list by radio, checkbox or select values instead of search values. I close this ticket as feature request with milestone 1.5 for now. We re-open when we start working on this. Do you mind adding a link to this ticket at the feature request wiki page?

Thanks!

@frequent
Copy link
Contributor

@uGoMobi: I'm working on it. Prototype here

@jaspermdegroot
Copy link
Contributor

@frequent - Awesome!

@toddparker
Copy link
Contributor

I think this would be a nice addition to 1.5. +1

@dueckes
Copy link
Author

dueckes commented Apr 26, 2013

Related to this, a more advanced use case involves supporting multiple filter controls acting on the one list.
As an example, I may have both a radio group and text search that contribute to filtering the list.

I suspect the best approach for this is to:

  • Expose a filter method that filters the entire list via the configured filterCallback. This filter method can then also be used as a callback for any additional filter controls the user provides (e.g. execute the filter method on a radio group value change)
  • Remove the logic 'resetting' the list when the search is empty (as the other controls can be actively filtering)

Arguably, this behavior is more valuable than that originally proposed in this feature request as it should eliminate the motivation for calling the 'filterBy' method proposed.

uGoMobi - the link you requested is on the feature request wiki.

@frequent
Copy link
Contributor

@dueckes:

not sure I understand. You want multiple filtering functions to be applied to a single list? The other way around makes more sense to me (= use a single filter on multiple element-containers, e.g. triggering a filter on a listview would also filter elements in another listview).

If you want to do something like this, it's quite easy. Add an attribute to the remote list you want to have filtered and inside the JQM listview filter, add list items of the remote list to the overall selection of items to be filtered using the attribute you set on the remote list. I'm using this quite a lot, so if you need an example, let me know.

@dueckes
Copy link
Author

dueckes commented Apr 29, 2013

@frequent:

I arrived at my latest suggestion after implementing an interface with multiple ways of filtering a list (or multiple controls where, when any control changes, the same list must update).

So, for example, the list has the standard search input filtering by name and an additional radio group filtering on another significant attribute. This type of requirement will be more probable in cases where each list item has a very rich data-set and the result-set is fairly large - users will be more inclined to narrow results based on numerous attributes.

My suggestion arose as it is difficult to support multiple controls filtering the list given the current filter / search implementation. It has two limitations:

  1. There is no method exposed to trigger filtering of the overall list. This logic appears to be embedded in the _onKeyUp function in listview.filter.js.
  2. The _onKeyUp method is designed to solely support the search filter control as it will show or hide
    the entire list
    when the search input is empty.

Consequently, my suggestion was to:

  1. Expose a filter method that could be used as an event callback by any additional control filtering the list. For example, filtering could then be triggered on change of a radio group value.
  2. Remove the logic that shows or hides the entire list when the search input is empty and leave it to the filterCallback to decide what is shown.

This suggestion is predicated on the logic that considers all the filters being in the filterCallback method.

To make my suggestion more concrete, here's something I threw together in an attempt to patch the existing behaviour (in CoffeeScript):

define([ "jquery", "underscore" ], ($, _) ->

  class PatchedListview

    constructor: (selector, options) ->
      @element = $(selector).listview(options)
      @searchElement = @element.parent().find($("form input[data-type=search]"))
      @clearElement = @element.parent().find($("form .ui-listview-filter .ui-input-clear-hidden"))
      @filterCallback = options["filterCallback"]
      @_bindFilter()

    # Exposes internals from jquery-mobile/js/widgets/listview.filter.js
    filter: () ->
      childItems = false
      items = @element.children()
      _.each(items.get().reverse(), (rawItem) =>
        item = $(rawItem)
        if item.is("li:jqmData(role=list-divider)")
          item.toggleClass("ui-filter-hidequeue", !childItems)
          childItems = false
        else if (@filterCallback(item))
          item.toggleClass("ui-filter-hidequeue", true)
        else
          childItems = true
      )
      @_showItemsNotOnHideQueue(items)
      @_hideItemsOnHideQueue(items)

    _bindFilter: () ->
      @_unbindDefaultFilter()
      @searchElement.on("keyup change input", () =>
        @clearElement.toggleClass("ui-input-clear-hidden", _.isEmpty(@searchElement.val()))
        @filter()
      )

    # unbinds the default _onKeyUp behaviour
    _unbindDefaultFilter: () ->
      @searchElement.unbind()

    _showItemsNotOnHideQueue: (items) ->
      items.filter(":not(.ui-filter-hidequeue)")
        .toggleClass("ui-screen-hidden", false)

    _hideItemsOnHideQueue: (items) ->
      items.filter(".ui-filter-hidequeue")
        .toggleClass("ui-screen-hidden", true)
        .toggleClass("ui-filter-hidequeue", false)

)

As the _onKeyUp method interfere's with the approach I have suggested, I unbind the callback before binding the new solution.

The patch can be used like so (again CoffeeScript):

listview = new PatchedListview("#some-list-view", filterCallback: (item) => someFilterCallback(item))
$("input[name='some-radio-group']").on("change", listview.filter) # radio group change triggers filter

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

4 participants