Polymer: There is no easy way to data-bind an array with a filtered/sorted subset of that array

Created on 8 Apr 2016  Â·  22Comments  Â·  Source: Polymer/polymer

array-selector provides developers a mechanism to data-bind between a source array and a "selected" array which is a subset of the source array.

What could be equally useful is an "array-filter" that data-binds between a source array and generated subset array based on given filter and sort functions.

e.g.
<array-filter filter="_filterFunction" sort="_sortFunction" data="{{data}}" filtered-data="{{filteredData}}"></array-filter>

In my case, I have a data array I retrieve via AJAX, which can be filtered and sorted in various ways based on user input. The filtered data is then handed off to various components, where it can be edited via data-binding templates. I need these edits propagated back to the original source array.

1.x api-feedback databinding

Most helpful comment

I also had a go at this a while back and just published it recently (didn't see that you had tried to implement it already).

Here's what I came up with: 43081j/array-filter.

It works for filtering and/or sorting an array, maintaining bindings/notification. Some of the implementation is similar to that of dom-repeat. However, it is slightly more efficient with splices as it will calculate the sort positions and splice as needed (rather than doing a full re-sort). Works fine with iron-list right now too (as you can see in the demo).

Technically, both dom-repeat and iron-list could depend on such an element, so they share the same implementation.

All 22 comments

I agree this would be a nice feature.

We need this in our app as well.

Why can't you just do something like this:

<template is="dom-repeat" items="[[_functionToFilterOrSort(items)]]">
   <div>[[item]]</div>
</template>

Then write a custom _functionToFilterOrSort that does what you need with items.

Hi @miztroh ! I could definitely do that, however the "dom-repeat" doesn't have the performance benefits that iron-list gives us by reusing DOM elements to generate the list; that's why I'm requesting it as a feature on iron-list.

Tom can you file this under the iron-list repo if that's the case?

On Sun, Jul 31, 2016, 5:40 PM Tom Stewart [email protected] wrote:

Hi @miztroh https://github.com/miztroh ! I could definitely do that,
however the "dom-repeat" doesn't have the performance benefits that
iron-list gives us by reusing DOM elements to generate the list; that's why
I'm requesting it as a feature on iron-list.

—
You are receiving this because you are subscribed to this thread.

Reply to this email directly, view it on GitHub
https://github.com/Polymer/polymer/issues/3571#issuecomment-236467304,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AAOigJqbQOf1IXS5FI21WthKK0OjuYvMks5qbUBngaJpZM4ICo_a
.

That was just an example. You could use the same technique with iron-list.

@miztroh @ebidel whoops! I thought I was in a different thread; notably, the one about how iron-list doesn't have filter/sort/observe properties: https://github.com/PolymerElements/iron-list/issues/123

However, with an array-filter component that I'm describing here, we wouldn't need those features on iron-list because we could just pass the filtered-data from the array-filter into the iron-list.

As for your proposed solution miztroh, it wouldn't quite work because I need both the "unfiltered" and "filtered" arrays and I need them data-bound with each other. Your example filters, but if the user modified one of the items in the filtered list, those modifications wouldn't be copied in the unfiltered array.

I see your point and would definitely like to see these improvements made to iron-list. As a workaround until then, you could start with a sorted items list and then do something like this:

<iron-list items="[[items]]">
   <template>
      <template is="dom-if"> if="[[_showItem(item)]]">
         <div>[[item]]</div>
      </template>
   </template>
</iron-list>

I will test that in my app soon @miztroh and will get back to you. In theory, it looks like it should work, though I'm somewhat skeptical of the nested templates.

Even if it does, we would still benefit from a separate component that does this "data-bound filtering", plus would have sorting capabilities included.

@miztroh the iron-list broke when I attempted this strategy. My guess is it can't handle the nested templates.

I know I've done something similar in the past. Try it this way.

<iron-list items="[[items]]">
   <template>
      <div>
         <template is="dom-if"> if="[[_showItem(item)]]">
            <div>[[item]]</div>
         </template>
      </div>
   </template>
</iron-list>

@miztroh This works, but only as a basic filter; the filter is not updatable and does not have the capability to recompute the list whenever an item's filter-dependent property has changed.

Thank you so much for your help, but I don't want to get further away from the original enhancement request, which is a component similar to "array-selector" that does filtering/sorting instead of "selecting" (while maintaining data-binding). Please see the first post above for details.

Sure. Didn't mean to distract from the issue. Just wanted to help you get up and running. A minor update to my last suggestion is that you could change _showItem(item) to _showItem(item.*). That'll get you the recomputing you want.

FYI, I created this component locally, and it works as expected, except for a particular scenario when displaying the output with an iron-list (due to an iron-list defect: https://github.com/PolymerElements/iron-list/issues/300)

If desired, I could submit a pull request for this component.

I also had a go at this a while back and just published it recently (didn't see that you had tried to implement it already).

Here's what I came up with: 43081j/array-filter.

It works for filtering and/or sorting an array, maintaining bindings/notification. Some of the implementation is similar to that of dom-repeat. However, it is slightly more efficient with splices as it will calculate the sort positions and splice as needed (rather than doing a full re-sort). Works fine with iron-list right now too (as you can see in the demo).

Technically, both dom-repeat and iron-list could depend on such an element, so they share the same implementation.

@43081j I just tested your component with my demo - it appears to also be affected/broken by https://github.com/PolymerElements/iron-list/issues/300

To replicate the defect in your demo, you will need (I think) the ability to turn the filter function on and off (i.e. have a toggle-switch that toggles filter between null and a function-type value). Also, the items in my demo have a boolean property that I reference for the filtering and the observe property, but I'm not sure that's a requirement to replicate the defect. Once you have that set up, you can replicate by:

  1. Turn the filter ON.
  2. Modify a value for an item in the filtered list whose index in the unfiltered list is > the current total number of items in the filtered list.
  3. Turn the filter OFF.
  4. ISSUE: The item you modified does not appear modified in the filtered list.

@tstewart15 do you have a jsbin of this? using the array-filter element?

I also just pushed a fix for the ability to remove filter/sort functions. Should make it more reproducible.

You can use this as a start point if you like.

@43081j here is the jsbin: http://jsbin.com/gakocal/edit?html,console,output, though it seems it's still breaking when the filter is supposed to be null.

@tstewart15 this is because filter expects a function (through binding) or the name of a method on this. Changing it to [[_computeFilter(_filterCheckedItems)]] should sort that error.

I now see the issue, though. Because of the node reuse, item 3 does indeed become set (visually) again.

@43081j Thanks for looking into this. I tried to pinpoint what Polymer is doing wrong in https://github.com/PolymerElements/iron-list/issues/300, however it's still rather open-ended as to how Polymer could/should fix it, so any help you could provide there would be appreciated.

You might want to study iron-data-table.

It appears that https://github.com/43081j/array-filter solves this use-case. We have no intention to maintain a (somewhat) duplicate version of that element if a solution already exists. Feel free to use that element or any other element that is created by the community that addresses this use-case.

Was this page helpful?
0 / 5 - 0 ratings