当我尝试将其值绑定到模型时,我对Ember.Select视图有一个奇怪的问题。 以下是我正在做的摘要,完整的jsbin可以在这里找到:
使用JavaScript:http://jsbin.com/jayutuzazi/1/edit?html,js,output
使用CoffeeScript:http://jsbin.com/nutoxiravi/2/edit?html,js,output
基本上我尝试做的是使用模型的属性来设置另一个模型的属性。
我有Age
这样的模型
App.Age = DS.Model.extend({
label: DS.attr('string'),
base: DS.attr('number')
});
另一个名为Person
的模型就像这样
App.Person = DS.Model.extend({
name: DS.attr('string'),
ageBase: DS.attr('number')
});
模板如下所示:
<!-- person/edit.hbs -->
<form>
<p>Name {{input value=model.name}}</p>
<p>
Age
{{view "select" value=model.ageBase
content=ages
optionValuePath="content.base"
optionLabelPath="content.label"}}
</p>
</form>
我要做的是在人物编辑表单中有select
,其中使用base
作为值并使用label
作为标签列出年龄。
我希望在加载时选择正确的值,并在所选选项更改时进行更改。
在jsbin输出中可以看到,所选内容已正确填充,但它将已编辑人员的ageBase
值设置为undefined
,并且不选择任何选项。选择选项时,会正确设置模型值。
我做错了吗?这是一个错误吗?我应该做些什么来完成这项工作?
谢谢:)
答案 0 :(得分:3)
您可以根据ages
的履行情况有条件地呈现,如下所示,因为选择不会处理承诺(更多内容如下):
{{#if ages.isFulfilled}}
{{view "select" value=ageBase
content=ages
optionValuePath="content.base"
optionLabelPath="content.label"}}
{{/if}}
我更新了JsBin,证明它有效。
我还在JsBin中说明了如何在模板中使用model.
进行限定,因为对象控制器是他们装饰的模型的代理。这意味着如果属性来自模型或控制器上的某些计算属性,则您的视图不必关注。
目前有一个PR #9468用于选择视图,我提出了合并到Ember的案例,它解决了选择和选项路径的一些问题。还有meta issue #5259来处理一些选择性视图问题,包括使用promises。
从问题#5259开始,您会发现Ember核心开发人员Robert Jackson有一些候选人选择替代品。我克隆了一个JsBin来运行最新的Ember生产版本。
没有什么可以阻止您在应用中使用Roberts代码作为选择视图替换。异步集合/承诺将起作用(从我看到的基准测试中渲染速度要快得多)。
该组件的模板只是:
{{#if prompt}}
<option disabled>{{prompt}}</option>
{{/if}}
{{#each option in resolvedOptions}}
<option {{bind-attr value=option.id}}>{{option.name}}</option>
{{/each}}
组件的js是:
App.AsyncSelectComponent = Ember.Component.extend({
tagName: 'select',
prompt: null,
options: null,
initialValue: null,
resolvedOptions: null,
resolvedInitialValue: null,
init: function() {
var component = this;
this._super.apply(this, arguments);
Ember.RSVP.hash({
resolvedOptions: this.options,
resolvedInitialValue: this.initialValue
})
.then(function(resolvedHash){
Ember.setProperties(component, resolvedHash);
//Run after render to ensure the <option>s have rendered
Ember.run.schedule('afterRender', function() {
component.updateSelection();
});
});
},
updateSelection: function() {
var initialValue = Ember.get(this, 'resolvedInitialValue');
var options = Ember.get(this, 'resolvedOptions') || [];
var initialValueIndex = options.indexOf(initialValue);
var prompt = Ember.get(this, 'prompt');
this.$('option').prop('selected', false);
if (initialValueIndex > -1) {
this.$('option:eq(' + initialValueIndex + ')').prop('selected', true);
} else if (prompt) {
this.$('option:eq(0)').prop('selected', true);
}
},
change: function() {
this._changeSelection();
},
_changeSelection: function() {
var value = this._selectedValue();
this.sendAction('on-change', value);
},
_selectedValue: function() {
var offset = 0;
var selectedIndex = this.$()[0].selectedIndex;
if (this.prompt) { offset = 1; }
return Ember.get(this, 'resolvedOptions')[selectedIndex - offset];
}
});
答案 1 :(得分:0)
问题在于:
{{view "select" value=model.ageBase
当应用启动时,value
未定义且model.ageBase
与value
同步到model.ageBase
之前的同步。因此,解决方法是跳过初始未定义的value
。
请参阅:http://jsbin.com/rimuku/1/edit?html,js,console,output
相关部分是:
模板
{{view "select" value=selectValue }}
控制器
App.IndexController = Ember.Controller.extend({
updateModel: function() {
var value = this.get('selectValue');
var person = this.get('model');
if ( value ) { // skip initial undefined value
person.set('ageBase', value);
}
}.observes('selectValue'),
selectValue: function() {
// randomly used this one
return this.store.find('age', 3);
}.property()
});
答案 2 :(得分:0)
givanse的答案应该有效。
我不认为它是因为值未定义,但因为值只是一个整数(42)并且不等于任何选择内容,即Person对象({id:2, label:&#39; middle&#39;,base:42})。
你可以做类似于给予建议或使用关系的东西。
//
// Models
//
App.Person = DS.Model.extend({
name: DS.attr('string'),
ageBase: DS.belongsTo('age', { async: true })
});
App.Age = DS.Model.extend({
label: DS.attr('string'),
base: DS.attr('number')
});
//
// Fixtures
//
App.Person.reopenClass({
FIXTURES: [
{ id: 1, name: 'John Doe', ageBase: 2 }
]
});
App.Age.reopenClass({
FIXTURES: [
{ id: 1, label: 'young', base: 2 },
{ id: 2, label: 'middle', base: 42 },
{ id: 3, label: 'old', base: 82 }
]
});
<h1>Edit</h1>
<pre>
name: {{model.name}}
age: {{model.ageBase.base}}
</pre>
<form>
<p>Name {{input value=model.name}}</p>
<p>
Age
{{view "select" value=model.ageBase
content=ages
optionValuePath="content"
optionLabelPath="content.label"}}
</p>
</form>
答案 3 :(得分:0)
好的,我找到了一个我认为更令人满意的解决方案。我认为问题来自ages
是一个承诺。解决方案是确保在呈现页面之前加载年龄列表。
我是这样做的:
App.IndexRoute = Ember.Route.extend({
model: function() {
return Ember.RSVP.hash({
person: this.store.find('person', 1),
ages: this.store.findAll('age')
});
}
});
那就是它!我需要的就是根据新模型改变视图:
{{#with model}}
<form>
<p>Name {{input value=person.name}}</p>
<p>
Age
{{view "select" value=person.ageBase
content=ages
optionValuePath="content.base"
optionLabelPath="content.label"}}
</p>
</form>
{{/with}}
可以在此处找到完整的工作解决方案:http://jsbin.com/qeriyohacu/1/edit?html,js,output
再次感谢@givanse和@Larsaronen的回答:)