Iterating over an array myarray=[1, 2, 3]
works like this:
<template is="dom-repeat" items="[[myarray]]"> <span>[[item]]</span> </template>
How can I iterate over an object myobject = {a:1, b:2, c:3}
?
dom-repeat accepts an items property, and one instance of the template is stamped for each item into the DOM at the location of the dom-repeat element. The item property will be set on each instance's binding scope, thus templates should bind to sub-properties of item .
The <dom-if> element will stamp a light-dom <template> child when the if property becomes truthy, and the template can use Polymer data-binding and declarative event features when used in the context of a Polymer element's template. When if becomes falsy, the stamped content is hidden but not removed from dom.
Here is a complete implementation:
<test-element obj='{"a": 1, "b": 2, "c": 3}'></test-element> <dom-module id="test-element"> <template> <template is="dom-repeat" items="{{_toArray(obj)}}"> name: <span>{{item.name}}</span> <br> value: <span>{{item.value}}</span> <br> <hr> </template> </template> <script> Polymer({ properties: { obj: Object }, _toArray: function(obj) { return Object.keys(obj).map(function(key) { return { name: key, value: obj[key] }; }); } }); </script> </dom-module>
I faced the same problem, but my use-case is a bit more demanding: I need two-way deep binding through the repeat. Plus I cannot afford rewriting the whole tree on each change.
Since I did not find a solution and the polymer team seems to take it slowly on this issue, I made something for the time being. It's written in ES2015, but translating that to vanilla ES5 should be straightforward. Runs in Chrome anyway as is. Or throw it at bable. This page details how. The gist for the purpose of this posting:
vulcanize element.html --inline-script --inline-css | \ crisper -h element.v.html -j element.js; babel element.js -o element.js
So here we go:
<link rel="import" href="../../bower_components/polymer/polymer.html"> <dom-module id="my-objarray"> <script> (function() { 'use strict'; class Objarray { beforeRegister() { this.is = 'my-objarray'; this.properties = { array:{ notify:true, type:Array, value:function() {return new Array();} }, object:{ notify:true, type:Object } }; this.observers = ['_onArray(array.*)', '_onObject(object.*)']; } _onObject(change) { if(this._setting) return; if(change.path == "object") this._rewriteArray(); else this._writeElement(change); } _rewriteArray() { this.splice("array", 0, this.array.length); for(let i in this.object) { this.push("array", {key:i, value:this.object[i]}); } } _writeElement(change) { const path = change.path.match(/^object\.([^\.]+)(.*)$/); const key = path[1]; const objectPath = "object." + key + (path[2] || ""); const id = this._getId(key); const arrayPath = "array." + id + ".value" + (path[2] || ""); this.set(arrayPath, this.get(objectPath)); } _getId(key) { const collection = Polymer.Collection.get(this.array); for(const element of this.array) { if((element && element.key) === key) { return collection.getKey(element); } } } _onArray(change) { let path = change.path.match(/^array\.(#\d+)\.([^\.]+)(\.|$)/); if(!path) return; let id = path[1], field = path[2]; if(field == "key") throw new Error("my-objarray: Must not change key!"); if(field != "value") throw new Error("my-objarray: Only change inside value!"); this._setting = true; this.set(this._getPath(change, id), change.value); delete this._setting; } _getPath(change, id) { let collection = Polymer.Collection.get(change.base); let index = change.base.indexOf(collection.getItem(id)); let key = change.base[index].key; return change.path.replace("array." + id + ".value", "object." + key); } } Polymer(Objarray); })(); </script> </dom-module>
Usage:
<dom-module id="my-objarray-test"> <template strip-whitespace> <my-objarray object="{{items}}" array="{{array}}"></my-objarray> <template is="dom-repeat" items="{{array}}"> <div> <label>{{item.key}}:</label> <input type="number" value="{{item.value.data::input}}"> </div> </template> </template> <script> (function() { 'use strict'; class ObjarrayTest { beforeRegister() { this.is = 'my-repeat-test'; this.properties = { items:{ notify:true, type:Object, value:function() {return new Object();} } }; this.observers = ['_onItems(items.*)']; } ready() { console.log("my-repeat-test.ready"); this.items = {a:{data:1}, b:{data:2}}; } _onItems(change) {console.log("test._onItems", change.path);} } Polymer(ObjarrayTest); })(); </script> </dom-module>
Hope that helps somebody. Presumable polymer now gets the feature like tomorrow :-)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With