Ember视图模板作为计算属性 [英] Ember view template as a computed property

查看:83
本文介绍了Ember视图模板作为计算属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当Ember视图为计算属性时,我无法更新Ember视图中的模板属性。



当视图首先加载并返回为属性时,Ember会正确地编译模板,但是当依赖关系稍后更改时,模板计算属性不会更新。

以下是JSFiddle的示例: http://jsfiddle.net/VkJC3/

  App = Em.Application.create(); 

App.MyView = Em.View.extend({
toggle:true
,template:function(){
if(this.get('toggle' ){
return Em.Handlebars.compile('toggle is true')
} else {
return Em.Handlebars.compile('toggle is false')
}
} .property('toggle')
});

theView = App.MyView.create();
theView.append('body');

Ember.run.later(function(){
console.log('later');
theView.set('toggle',false);
},2000);

任何其他有关如何完成此操作的建议均得到赞赏。也许最好把助手放在一个把手模板中。



编辑:



这是一个更完整的示例,显示将包含上述Ember.View的Ember.CollectionView: http: /jsfiddle.net/VkJC3/6/



在Ember.run.later之后,第一个项目应该从类型1更改为类型2,具有计算的模板属性更新。

  App = Em.Application.create(); 

App.MyView = Em.CollectionView.extend({
content:[
Em.Object.create({type:1,data:maybe item type 1 is a link})
,Em.Object.create({type:2,data:And item type 2 is a header})]

,itemViewClass:Em.View.extend ({
template:function(){
if(this.get('content.type')== 1){
return Em.Handlebars.compile('< a href = #> {{view.content.data}}< / a>')
} else if(this.get('content.type')== 2){
return Em .Handlebars.compile('< h1> {{view.content.data}}< / h1>')
}
} .property('content.type')
} )
});


theView = App.MyView.create();
theView.append('body');

Ember.run.later(function(){
console.log('later');
theView.get('content')[0] .set类型',2);
},2000);


解决方案

模板。模板不应该返回一个编译的模板,而是作为编译的模板。在您的代码中,您尝试将模板本身设置为计算属性,并且您有条件地编译两个可能的模板。 IMHO应该编译一个绑定到一个计算属性的模板,该属性根据切换属性来计算文本,如下所示:

  App = Em.Application.create(); 

App.MyView = Em.View.extend({
template:Em.Handlebars.compile('toggle is {{toggleState}}'),
toggle:true,
toggleState:function(){
if(this.get('toggle')){
return'set to \'true\'';
} else {
return'set to \'false\'';
}
} .property('toggle')
});

theView = App.MyView.create();
theView.append('body');

Ember.run.later(function(){
console.log('later');
theView.set('toggle',false);
},2000);

看到小提琴这里



这只会更改需要更改的内容,因此您不必重新编译模板。 p>

编辑



我对小提琴做了一些修改(你可以看到它 这里 )。



我在做什么,而不是直接分配模板属性,我正在将模板编译成code> Ember.TEMPLATES 集合在创建应用程序之前(我假设你会在prod中做这样的事情),我正在更改你的计算属性来返回根据条件使用的模板(在您的情况下 content.type ),我绑定 templateName 计算属性的属性。模板更改后,您转换为 rerender 您的视图。代码可以改进,但是我将其粘贴到这里来演示解决方案:

 (function(){

Em.TEMPLATES [one] = Em.Handlebars.compile('< a href =#> {{view.content.data}}< / a>');
Em.TEMPLATES [two] = Em.Handlebars.compile('< h1> {{view.content.data}}< / h1>');

}) );

App = Em.Application.create();

App.MyView = Em.CollectionView.extend({
content:[
Em.Object.create({type:1,data:Item type 1 is a link }),
Em.Object.create({type:2,data:Item type 2 is a header})
],
itemViewClass:Em.View.extend({
templateNameBinding:'currentTypeName',
currentTypeName:function(){
if(this.get('content.type')== 1){
returnone;
} else if(this.get('content.type')== 2){
returntwo;
}
} .property('content.type' )
templateNameObserver:function(){
this.rerender();
} .observes('templateName')
})
});
// ...其余的代码...

像我说的这样代码可以改进...希望这有助于


I am having problems updating the template property on an Ember view when it is a computed property.

Ember compiles the template correctly when the view first loads and returns as a property, but the template computed property does not update when the dependency is later changed.

Here is an example on JSFiddle: http://jsfiddle.net/VkJC3/

App=Em.Application.create();

App.MyView = Em.View.extend({
    toggle: true
    ,template: function(){
        if (this.get('toggle')) {
            return Em.Handlebars.compile('toggle is true')
        } else {
            return Em.Handlebars.compile('toggle is false')
        }
     }.property('toggle')
});

theView= App.MyView.create();
theView.append('body');

Ember.run.later(function() {
    console.log('later');
    theView.set('toggle',false);
}, 2000);
​

Any other suggestions on how to accomplish this are appreciated. Maybe it is best to just put if helpers into one handlebars template.

EDIT:

Here is a more complete example showing the Ember.CollectionView that will contain the above Ember.View: http://jsfiddle.net/VkJC3/6/

After the Ember.run.later, the first item should change from a type 1 to type 2, and have the computed template property update.

App=Em.Application.create();

App.MyView = Em.CollectionView.extend({
    content: [
        Em.Object.create({type: 1, data:"Maybe item type 1 is a link"})
        ,Em.Object.create({type: 2, data:"And item type 2 is a header"})]

    ,itemViewClass: Em.View.extend({
        template: function(){
            if (this.get('content.type')==1) {
                return Em.Handlebars.compile('<a href="#">{{view.content.data}}</a>')
            } else if (this.get('content.type')==2) {
                return Em.Handlebars.compile('<h1>{{view.content.data}}</h1>')
            }
         }.property('content.type')
    })
});


theView= App.MyView.create();
theView.append('body');

Ember.run.later(function() {
    console.log('later');
    theView.get('content')[0].set('type',2);
}, 2000);
    ​

解决方案

That's not how you should set the template. The template should not return a compiled template but rather act as a compiled template. In your code you're trying to set the template itself as a computed property and you're compiling two possible templates to it conditionally. IMHO you should compile a template with a binding to a computed property that evaluates a text based on your toggle property, like this:

App = Em.Application.create();

App.MyView = Em.View.extend({
    template: Em.Handlebars.compile('toggle is {{toggleState}}'),
    toggle: true,
    toggleState: function(){
        if (this.get('toggle')) {
            return 'set to \'true\'';
        } else {
            return 'set to \'false\'';
        }
     }.property('toggle')
});

theView = App.MyView.create();
theView.append('body');

Ember.run.later(function() {
    console.log('later');
    theView.set('toggle',false);
}, 2000);

See fiddle here

This will only change what needs to be change, so you don't have to re-compile a template.

EDIT:

I've made some modifications to the fiddle (You can see it here).

What I am doing, instead of assigning the template property directly, I'm compiling the templates to Ember.TEMPLATES collection before creating the app (I'm assuming you'll do something like this in prod anyway), and I'm changing your computed property to return the name of the template to be used depending on the condition (in your case content.type), and I'm binding the templateName property that computed property. Once the template changes, you have to rerender your view. The code can be improved, but I'll paste it here to demonstrate the solution:

(function() {

    Em.TEMPLATES["one"] = Em.Handlebars.compile('<a href="#">{{view.content.data}}</a>');
    Em.TEMPLATES["two"] = Em.Handlebars.compile('<h1>{{view.content.data}}</h1>');

})();

App = Em.Application.create();

App.MyView = Em.CollectionView.extend({
    content: [
        Em.Object.create({type: 1, data:"Item type 1 is a link"}),
        Em.Object.create({type: 2, data:"Item type 2 is a header"})
    ],
    itemViewClass: Em.View.extend({
        templateNameBinding: 'currentTypeName',
        currentTypeName: function() {
            if (this.get('content.type') == 1) {
                return "one";
            } else if (this.get('content.type') == 2) {
                return "two";
            }
        }.property('content.type'),
        templateNameObserver: function() {
            this.rerender();
        }.observes('templateName')
    })
});
// ... rest of the code... 

Like I said, this code can be improved... hope this helps

这篇关于Ember视图模板作为计算属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆