如何在 Polymer 1.0 中对对象而不是数组使用 dom-repeat?
How to use dom-repeat with objects instead of arrays in Polymer 1.0?
遍历数组 myarray=[1, 2, 3]
的工作方式如下:
<template is="dom-repeat" items="[[myarray]]">
<span>[[item]]</span>
</template>
如何遍历对象 myobject = {a:1, b:2, c:3}
?
您需要将此对象转换为有意义的数组,以便能够使用 dom-repeat
对其进行迭代。
我用初始值创建了一个 myObj
属性。然后我创建了一个名为 myObjAsArray
的 属性,它是一个空数组。在 local dom 准备就绪时调用的 ready
回调函数中,我遍历 myObj
的所有属性并添加它们到 myObjAsArray
(请参阅 here 以了解如何遍历对象属性)。然后,您可以使用 dom-repeat
.
遍历此数组
<link rel="import" href="bower_components/polymer/polymer.html">
<dom-module id="test-element">
<style>
</style>
<template>
<template is="dom-repeat" items="{{myObjAsArray}}">
name: <span>{{item.name}}</span>
value: <span>{{item.value}}</span>
</template>
</template>
</dom-module>
<script>
Polymer({
is: "test-element",
properties: {
myObj: {
type: Object,
value: function () {
return {
a: 1,
b: 2,
c: 3
};
}
},
myObjAsArray: {
type: Array,
value: function () {
return [];
}
}
},
attached: function () {
var propArray = [];
for (var prop in this.myObj) {
if (this.myObj.hasOwnProperty(prop)) {
propArray.push({name: prop, value: this.myObj[prop]});
}
}
this.myObjAsArray = propArray;
}
});
</script>
我一直在使用Object.keys(obj).map(function(prop){return {id:prop, val:obj[prop]}})
这是一个完整的实现:
<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>
我遇到了同样的问题,但我的用例要求更高:我需要通过重复进行双向深度绑定。另外,我负担不起在每次更改时重写整棵树。
由于我没有找到解决办法,而且polymer团队在这个问题上似乎处理得比较慢,所以我暂时做了一些东西。它是用 ES2015 编写的,但将其转换为 vanilla ES5 应该很简单。无论如何按原样在 Chrome 中运行。或将其扔给婴儿。 This page 详细说明如何。这篇文章的要点:
vulcanize element.html --inline-script --inline-css | \
crisper -h element.v.html -j element.js;
babel element.js -o element.js
我们开始吧:
<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>
用法:
<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>
希望对某人有所帮助。 Presumable polymer 现在获得像明天一样的功能:-)
Object.keys() 似乎在 IE 中不起作用。因此修改了实现以使用 _.map 代替。
<test-element obj='{"a": 1, "b": 2, "c": 3}'></test-element>
<dom-module id="test-element">
<template>
<template is="dom-repeat" items="{{getKeyValue(obj)}}">
key: <span>{{item.key}}</span>
<br> value: <span>{{item.value}}</span>
<br>
<hr>
</template>
</template>
<script>
Polymer({
properties: {
obj: Object
},
getKeyValue: function(obj) {
return _.map(obj, function(value, key) {
return {
key: key,
value: value
};
});
}
});
</script>
</dom-module>
重新审视此问题以解决其他人提到的问题。这与所有浏览器兼容并使用 hasOwnProperty
.
<template is="dom-repeat" items="[[_toArray(obj)]]">
key: [[item.key]] val: [[item.val]]
</template>
...
_toArray: function(obj, deep) {
var array = [];
for (var key in obj) {
if (deep || obj.hasOwnProperty(key)) {
array.push({
key: key,
val: obj[key]
});
}
}
return array;
}
遍历数组 myarray=[1, 2, 3]
的工作方式如下:
<template is="dom-repeat" items="[[myarray]]">
<span>[[item]]</span>
</template>
如何遍历对象 myobject = {a:1, b:2, c:3}
?
您需要将此对象转换为有意义的数组,以便能够使用 dom-repeat
对其进行迭代。
我用初始值创建了一个 myObj
属性。然后我创建了一个名为 myObjAsArray
的 属性,它是一个空数组。在 local dom 准备就绪时调用的 ready
回调函数中,我遍历 myObj
的所有属性并添加它们到 myObjAsArray
(请参阅 here 以了解如何遍历对象属性)。然后,您可以使用 dom-repeat
.
<link rel="import" href="bower_components/polymer/polymer.html">
<dom-module id="test-element">
<style>
</style>
<template>
<template is="dom-repeat" items="{{myObjAsArray}}">
name: <span>{{item.name}}</span>
value: <span>{{item.value}}</span>
</template>
</template>
</dom-module>
<script>
Polymer({
is: "test-element",
properties: {
myObj: {
type: Object,
value: function () {
return {
a: 1,
b: 2,
c: 3
};
}
},
myObjAsArray: {
type: Array,
value: function () {
return [];
}
}
},
attached: function () {
var propArray = [];
for (var prop in this.myObj) {
if (this.myObj.hasOwnProperty(prop)) {
propArray.push({name: prop, value: this.myObj[prop]});
}
}
this.myObjAsArray = propArray;
}
});
</script>
我一直在使用Object.keys(obj).map(function(prop){return {id:prop, val:obj[prop]}})
这是一个完整的实现:
<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>
我遇到了同样的问题,但我的用例要求更高:我需要通过重复进行双向深度绑定。另外,我负担不起在每次更改时重写整棵树。
由于我没有找到解决办法,而且polymer团队在这个问题上似乎处理得比较慢,所以我暂时做了一些东西。它是用 ES2015 编写的,但将其转换为 vanilla ES5 应该很简单。无论如何按原样在 Chrome 中运行。或将其扔给婴儿。 This page 详细说明如何。这篇文章的要点:
vulcanize element.html --inline-script --inline-css | \
crisper -h element.v.html -j element.js;
babel element.js -o element.js
我们开始吧:
<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>
用法:
<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>
希望对某人有所帮助。 Presumable polymer 现在获得像明天一样的功能:-)
Object.keys() 似乎在 IE 中不起作用。因此修改了实现以使用 _.map 代替。
<test-element obj='{"a": 1, "b": 2, "c": 3}'></test-element>
<dom-module id="test-element">
<template>
<template is="dom-repeat" items="{{getKeyValue(obj)}}">
key: <span>{{item.key}}</span>
<br> value: <span>{{item.value}}</span>
<br>
<hr>
</template>
</template>
<script>
Polymer({
properties: {
obj: Object
},
getKeyValue: function(obj) {
return _.map(obj, function(value, key) {
return {
key: key,
value: value
};
});
}
});
</script>
</dom-module>
重新审视此问题以解决其他人提到的问题。这与所有浏览器兼容并使用 hasOwnProperty
.
<template is="dom-repeat" items="[[_toArray(obj)]]">
key: [[item.key]] val: [[item.val]]
</template>
...
_toArray: function(obj, deep) {
var array = [];
for (var key in obj) {
if (deep || obj.hasOwnProperty(key)) {
array.push({
key: key,
val: obj[key]
});
}
}
return array;
}