我慢慢开始了解EmberJS。不幸的是,我遇到了一个似乎无法解决的问题。
我有一个复杂的数据结构,我通过JSON检索,有多个嵌套数组,我似乎无法嵌套#each helpers。
我设置了我的模板如下(缩短):
{{#each Servers}}
<div class="server">
<h1>{{unbound Name}}</h1>
Time: {{jsonDate CurrentTime}}<br />
<table>
{{#each Processes}}
<tr>
<td>{{unbound Name}}</td>
<td>{{unbound Location}}</td>
</tr>
{{/each}}
</table>
</div>
{{#/each}}
第二个循环似乎没有运行,当我修改Ember以记录消息时,#第二个循环被调用,但它似乎不知道该怎么做。
当我用#Queue替换第二个#each时,它可以工作,但是在-element之前,为列表中的每个元素插入一个“undefined”-text(减1)。
当我将#each移动到另一个循环之外并放入Queue的直接路径(例如Servers.0.Queue)时,它工作正常,所以它肯定不是数据。
我该如何解决这个问题?如果无法嵌套#each,我如何为其他方法保护“undefined”-text?还有其他可能性吗?
PS。我出于性能原因使用unbound,我一次更新Servers对象并观察它,因此不需要使用绑定属性 - 因为我注意到它显着降低了浏览器性能(13%CPU使用率,而未绑定给了我0 %)。不确定是否相关。
修改
请参阅:http://jsfiddle.net/PTC9B/7/
ServerOverview2a方法毕竟是有效的,显然ServerOverview2b生成我之前描述的“未定义”文本 - 可能应该为此提交错误报告?
我现在的问题是:为什么嵌套#each不起作用而#Processes呢?
答案 0 :(得分:6)
看起来哈希中的属性会导致麻烦:使用大写属性Processes
不起作用 - 如果将其更改为processes
,each
帮助程序将按预期工作,请参阅http://jsfiddle.net/pangratz666/ndkWt/:
<script type="text/x-handlebars" data-template-name="app-server">
<h1>Default</h1>
{{#each data.Servers}}
<div class="server">
<h1>{{unbound this.Name}}</h1>
Time: {{unbound this.CurrentTime}}<br />
<table>
{{#each this.processes}}
<tr>
<td>{{unbound Name}}</td>
<td>{{unbound Location}}</td>
</tr>
{{/each}}
</table>
</div>
{{/each}}
</script>
App = Ember.Application.create({
ready: function() {
Ember.View.create({
templateName: 'app-server',
dataBinding: 'App.dataController.data'
}).append();
App.dataController.getServers();
}
});
App.dataController = Ember.Object.create({
data: {},
getServers: function() {
this.set('data', Ember.Object.create({
"Servers": [
{
"Name": "USWest",
"CurrentTime": "1337",
"processes": [
{
"Name": "apache.exe",
...
}
]}
]
}));
}
});
IMHO引用this.Processes
应该在#each
帮助器中工作,所以这可能是一个错误。您是否能够更改从服务器获得的JSON的属性名称?否则,您可能会编写一个帮助程序,在使用它之前将其缩小JSON的属性名称...
另一个注意事项:Application#ready
在您提供的JSFiddle中不起作用,因为您指定了要执行的JS onDomReady
(在JSFiddle的左上角选择下拉列表)。如果您将其更改为no wrap
,则可以在App
回调中访问ready
。
关于命名的另一个注意事项:实例应命名为lowerCase和类UpperCase。所以在你的例子中它是App.serverOverview1 = Ember.View.create({ ... });
。
答案 1 :(得分:2)
Ember尝试通过它是否具有大写属性来推断您的路径是绝对路径(全局路径)还是相对路径路径(本地路径)。在这种情况下,Ember正在寻找不存在的全局Processes
属性。正如@pangratz指出的那样,简单的解决方案是使用小写。有关详细信息,请参阅http://www.emberist.com/2012/04/09/naming-conventions.html。
答案 2 :(得分:0)
这是我制作的后处理方法:
function decapitalizeJSON(data, dataType) {
var output = (dataType == undefined || dataType == '[object Object]') ? {} : [];
var value, type;
for(var key in data) {
if(!data.hasOwnProperty(key)) {
continue;
}
value = data[key];
type = Object.prototype.toString.apply(value);
if (type == '[object Array]' || type == '[object Object]') {
output[key.charAt(0).toLowerCase() + key.substr(1)] = decapitalizeJSON(value, type);
}
else {
output[key.charAt(0).toLowerCase() + key.substr(1)] = value;
}
}
return output;
}
然而,这是非常缓慢的 - 毫不奇怪。需要hasOwnProperty
以防止它尝试复制Ember添加到Array对象的方法,并且它是递归的,以确保它对所有内容进行资本化。在我的情况下,它可以优化为仅对数组进行decapitalize,但之后再次混合命名约定。
相反,我只是要求API供应商添加一个“emberHack”属性,如果通过该属性,我会提供适当的JSON Ember预期并且已被授予 - 但据称是“跛脚”要求。我可以保证大多数API供应商不会像我一样宽松。