简体   繁体   中英

Mutating array within an array (Polymer iron-list)

I currently have an iron-list within another iron-list. The parent's data comes from a firebase-query element, and the child's data is computed from each parent item. The db structure and code looks a bit like this:

DB: [
     category1: [
                 itemId1: {
                           price: 10,
                           title: "title" 
                          }
                ]
    ]



<iron-list id="categoryList" items="{{categories}}" multi-selection as="category">
        <template>
            <div class="category-holder">
                <iron-list id="{{category.$key}}" items="{{_removeExtraIndex(category)}}" as="item" selection-enabled multi-selection selected-items="{{selectedItems}}" grid>
                    <template>
                        <div class$="{{_computeItemClass(selected)}}">
                            <p>[[item.title]]</p>
                            <p>[[item.price]]</p>
                        </div>
                    </template>
                </iron-list>
            </div>
        </template>
    </iron-list>

After selecting any number of items, the user can tap on a fab to batch edit the price. This is where I'm having issues. I can't figure out how to access the correct child iron-list in order to call list.set...I'm currently trying the following very nasty method:

var categories = this.$.categoryList;
var categoryItems = categories.items;

(this.selectedItems).forEach(function(item) {
    var index = item.itemId;
    categoryItems.forEach(function(itemList, categoryIndex) {
    if (itemList[index]) {
         categories.set('item.' + categoryIndex + '.price', 10);
         }
    }, this);
}, this);

I'm iterating over the selected items in order to extract the item index and then iterating over the parent iron-list data (categoryItems) in order to check if the given item exists in that subset of data. If so, then I use the category index and attempt to call set on the parent iron-list using the given path to access the actual item I want to edit. As expected, this fails. Hopefully I've made myself clear enough, any help would be appreciated!

EDIT #1:

After much experimenting, I finally figured out how to correctly mutate the child iron-list:

(this.selectedItems).forEach(function(item) {
                var list = this.$.categoryList.querySelector('#' + item.category);
                var index = list.items.indexOf(item);
                list.set(["items", index, "price"], 30);                   
            }, this);

A couple of things worth noting. I'm using querySelector instead of the recommended this.$$(selector) because I keep running into a "function DNE" error. But now I have another problem...after calling the function, the value gets updated correctly but I get the following error:

Uncaught TypeError: inst.dispatchEvent is not a function

Here's a picture of the full error message: 在此处输入图片说明

I see the light, hopefully someone can help me out!

OK, I'll take a shot at this. I think the following happens, and I guess this based on how dom-repeat works:

  var categories = this.$.categoryList;
  var categoryItems = categories.items;

You take the variable that the iron-list is based on, but setting one array to another just creates a reference in javascript. As soon as you update categoryItems , you also update this.$.categoryList.items. When you later sets the new value, iron-list will do a dirty check and compare all subproperties, and because they are equal (because ... reference), the iron-list wont update the dom.

What you should do is to make sure it's a totally new copy and the way of doing that is to use JSON.parse(JSON.stringify(myArray)) .

Further on, one major flaw I see in your code is that you're using querySelector to select an element, and then manipulate that. What you should do is to use this.categories and only that variable.

So your method should look something like:

  // Get a freshly new array to manipulate
  var category = JSON.parse(JSON.stringify(this.categories);

  // Loop through it
  category.forEach(category) {
    // update your categoryList variable
  }

  // Update the iron list by notifying Polymer that categories has changed.
  this.set('categories', category);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM