我正在尝试使{{#each}}
助手在对象上进行迭代,就像在香草车把中一样。不幸的是,如果我在对象上使用#each,Ember.js版本会给我这个错误:
Assertion failed: The value that #each loops over must be an Array. You passed [object Object]
我写了这个帮助程序来解决这个问题:
Ember.Handlebars.helper('every', function (context, options) {
var oArray = [];
for (var k in context) {
oArray.push({
key : k,
value : context[k]
})
}
return Ember.Handlebars.helpers.each(oArray, options);
});
现在,当我尝试使用{{#every}}
时,出现以下错误:
Assertion failed: registerBoundHelper-generated helpers do not support use with Handlebars blocks.
这似乎是一项基本功能,我知道我可能缺少明显的东西。谁能帮忙?
编辑:
这里是小提琴:http://jsfiddle.net/CbV8X/
使用{{each-in}}
助手。您可以像{{each}}
助手一样使用它。
示例:
{{#each-in modelWhichIsObject as |key value|}}
`{{key}}`:`{{value}}`
{{/each-in}}
经过几个小时的摆弄,我想出了这种骇人听闻的方法:
Ember.Handlebars.registerHelper('every', function(context, options) {
var oArray = [], actualData = this.get(context);
for (var k in actualData) {
oArray.push({
key: k,
value: actualData[k]
})
}
this.set(context, oArray);
return Ember.Handlebars.helpers.each.apply(this,
Array.prototype.slice.call(arguments));
});
我不知道this.set
有什么影响,但这似乎行得通!
这里是小提琴:http://jsfiddle.net/CbV8X/1/
我一直在追求类似的功能,并且由于我们共享自己的hacky方式,所以这是我急躁的小提琴:http://jsfiddle.net/L6axcob8/1/
[这个小提琴是基于@lxe提供的,而@ Kingpin2k然后是我自己的更新。
Ember:1.9.1,Handlebars:2.0.0,jQuery 2.1.3
这里我们添加了一个名为every
的助手,该助手可以遍历对象和数组。
例如,此模型:
model: function() {
return {
properties: {
foo: 'bar',
zoo: 'zar'
}
};
}
可以使用以下车把模板进行迭代:
<ul class="properties">
{{#every p in properties}}
<li>{{p.key}} : {{p.value}}</li>
{{/every}}
</ul>
every
助手通过从对象键创建一个数组,然后通过ArrayController协调对Ember的更改来工作。是的,。但是,这确实允许我们向对象添加属性/从对象中删除属性,只要该对象支持对[]属性的观察。
在我的用例中,我有一个Ember.Object派生类,当添加/删除属性时,该类通知[]。我建议您查看Ember.Set以获得此功能,尽管我发现Set最近已被弃用。由于这超出了这个问题的范围,因此我将其留给读者练习。提示:setUnknownProperty
要通知属性更改,我们将非对象值包装在我称为的DataValueObserver中,该值设置(当前是一种方式)绑定。这些绑定提供了内部ArrayController所保存的值与我们正在观察的对象之间的桥梁。
[处理对象时;我们将它们包装在ObjectProxy中,以便我们可以引入“键”成员,而无需修改对象本身。为什么会这样,这确实意味着您可以递归使用#every。读者的另一项练习;-)
我建议您将模型基于Ember.Object并与Ember的其余部分保持一致,从而允许您通过其get&set处理程序来操纵模型。另外,如小提琴所示,只要您保持一致,就可以使用Em.Get / Em.set来访问模型。如果您直接触摸模型(无获取/设置),那么every
将不会收到有关更改的通知。
Em.set(model.properties, 'foo', 'asdfsdf');
为了完整起见,这是我的every
助手:
var DataValueObserver = Ember.Object.extend({
init: function() {
this._super();
// one way binding (for now)
Em.addObserver(this.parent, this.key, this, 'valueChanged');
},
value: function() {
return Em.get(this.parent, this.key);
}.property(),
valueChanged: function() {
this.notifyPropertyChange('value');
}
});
Handlebars.registerHelper("every", function() {
var args = [].slice.call(arguments);
var options = args.pop();
var context = (options.contexts && options.contexts[0]) || this;
Ember.assert("Must be in the form #every foo in bar ", 3 == args.length && args[1] === "in");
options.hash.keyword = args[0];
var property = args[2];
// if we're dealing with an array we can just forward onto the collection helper directly
var p = this.get(property);
if (Ember.Array.detect(p)) {
options.hash.dataSource = p;
return Ember.Handlebars.helpers.collection.call(this, Ember.Handlebars.EachView, options);
}
// create an array that we will manage with content
var array = Em.ArrayController.create();
options.hash.dataSource = array;
Ember.Handlebars.helpers.collection.call(this, Ember.Handlebars.EachView, options);
//
var update_array = function(result) {
if (!result) {
array.clear();
return;
}
// check for proxy object
var result = (result.isProxy && result.content) ? result.content : result;
var items = result;
var keys = Ember.keys(items).sort();
// iterate through sorted array, inserting & removing any mismatches
var i = 0;
for ( ; i < keys.length; ++i) {
var key = keys[i];
var value = items[key];
while (true) {
var old_obj = array.objectAt(i);
if (old_obj) {
Ember.assert("Assume that all objects in our array have a key", undefined !== old_obj.key);
var c = key.localeCompare(old_obj.key);
if (0 === c) break; // already exists
if (c < 0) {
array.removeAt(i); // remove as no longer exists
continue;
}
}
// insert
if (typeof value === 'object') {
// wrap object so we can give it a key
value = Ember.ObjectProxy.create({
content: value,
isProxy: true,
key: key
});
array.insertAt(i, value);
} else {
// wrap raw value so we can give it a key and observe when it changes
value = DataValueObserver.create({
parent: result,
key: key,
});
array.insertAt(i, value);
}
break;
}
}
// remove any trailing items
while (array.objectAt(i)) array.removeAt(i);
};
var should_display = function() {
return true;
};
// use bind helper to call update_array if the contents of property changes
var child_properties = ["[]"];
var preserve_context = true;
return Ember.Handlebars.bind.call(context, property, options, preserve_context, should_display, update_array, child_properties);
});
受启发:
如果您错过了,这里再次是小提琴: