Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use dom-repeat with objects instead of arrays in Polymer 1.0?

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}?

like image 887
Tamas Avatar asked Jun 11 '15 12:06

Tamas


People also ask

How do you use dom repeat?

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 .

How do you use dom in polymer?

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.


2 Answers

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> 
like image 183
Scott Miles Avatar answered Sep 22 '22 17:09

Scott Miles


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 :-)

like image 28
T. Roggendorf Avatar answered Sep 21 '22 17:09

T. Roggendorf