我必须对用Ember(版本2.10.0)编写的Web应用程序进行一些维护。但是我不是自己写应用程序的,Ember对我来说是新手,并且我在为数组添加新元素后在视图上重新渲染数组方面遇到了麻烦。具体来说,我可以更新数组本身,但不能更新附加到项目上较低级对象的属性。
问题的结构如下。 我有一个包含两个部分的视图:
在标识表单中添加新观察值并按“保存”按钮后,新观察值将添加到基础数据库中,然后应更新观察列表以包含新观察值。 在大多数情况下,一切都按预期进行。新元素将添加到列表中,并显示部分属性。但是很奇怪,新观察值的某些属性未显示,我认为这是因为它们位于附加到观察值的单独对象中。 列表中的每一项(观察)都具有以下属性:
a. Species. This is a separate object with an own ‘name’ attribute.
b. Amount. This is a numeric field directly on the observation itself
c. Sex. This is a separate object with an own attribute ‘label’
d. Age. This is a separate object with an own attribute ‘label’
现在,属性a,物种名称独立存在于组件中,并且可以正确显示
属性b(数量)直接在观察列表组件中,并且也正确显示。
但是属性c和d不会立即呈现,我可以看到它们在背景上可用,但是直到您在浏览器上手动刷新视图后,它们才会显示。
我尝试了两种高级设计:
方法1。 观察值.sex.label和观察值.age.label的值直接添加到观察值列表中,如下所示(请注意具有sequence.assets和asset.observations的多层次结构):
<tbody class="app--table-data">
{{#each sequence.assets as |asset|}}
{{#each asset.observations as |observation|}}
<tr
class="cursor-pointer hovershow"
{{action 'editObservation' observation}}
>
<td>
{{species-common-name
species=observation.species
project=sequence.deployment.project
}}
</td>
<td>
{{observation.amount}}
</td>
<td>
{{observation.sex.label}}
</td>
<td>
{{observation.age.label}}
</td>
</tr>
{{/each}}
{{/each}}
</tbody>
如前所述,这在结构上是正确的,新值可以正确显示,但仅在手动刷新页面后才能显示。这样就可以得到数据了,但是告诉Ember值已更新时出了一些问题。整个背景流程很复杂,但是本质上就是这样。视图上有一个按钮,如下所示:
templates / project / annotate / sequence.hbs
<div class="form-group form-group-sm">
<button
{{action 'saveObservation' on='click'}}
>
SAVE
</button>
</div>
按钮触发对关联控制器controllers / project / annotate / sequence.js的操作
/**
* Set triggerSave data prop to true, this is needed to trigger the save func in the identification form
*/
saveObservation() {
this.set('triggerSave', true);
},
此操作将触发对identification-form-component组件components / identification-form.js的进一步操作,该操作最终会将新观察结果保存到可靠的数据库中:
triggerSave: false,
saveObservationTrigger: function () {
if (this.get('triggerSave')) {
this.send('save', this.get('observation'));
}
}.observes('triggerSave'),
actions: {
save(observation) {
observation.set('createdBy', this.get('author'));
observation.set('asset', this.get('asset'));
observation.save()
.then(() => this.get('asset').reload())
.then(() => this.sendAction('action', observation));
}
}
sendAction返回控制器,controllers / project / annotate / sequence.js,并触发创建新的观察值和其他步骤。
didSaveObservation() {
const newObservation = this.get('store').createRecord('observation');
this.set('newObservation', newObservation);
this.set('triggerSave', false);
this.set('wideListSet', false);
this.set('showObservations', true);
this.send('disableEditMode');
},
在网络上,有人建议Ember依靠pushObject()来查看模型是否已更新,但是上面的代码中没有类似的东西。对我来说,应该是这样,因为数据模型中还有一些其他内部链接,如果您必须自己构建所有这些链接,那将是错误的。框架应该保持所有关系本身的同步,如果有必要,可以从数据库中重新加载。我的假设是,这就是this.get('asset')。reload()的工作–资产是更高级别的模型对象。
但是,显然它只能部分完成这项工作,所以我也尝试了另一种方法。
方法2。 性别和年龄移动到观察列表中引用的单独部分:
<tbody class="app--table-data">
{{#each sequence.assets as |asset|}}
{{#each asset.observations as |observation|}}
<tr
class="cursor-pointer hovershow"
{{action 'editObservation' observation}}
>
<td>
{{species-common-name
species=observation.species
project=sequence.deployment.project
}}
</td>
<td>
{{observation.amount}}
</td>
<td>
{{age-wrapper
sex=observation.sex
}}
</td>
<td>
{{age-wrapper
age=observation.age
}}
</td>
</tr>
{{/each}}
{{/each}}
</tbody>
这些子组件具有以下结构
{{sex.label}}
和
{{age.label}}
尝试这样做的原因是,虽然observation.amount(它应该完全正常工作)直接与observation.sex.label和observation.age.label相关联,但它们与observation.species在不同的对象上。名称。由于物种名称作为其自身成分的行为正确,我认为模仿相同的性别和年龄概念将有所帮助。看来这就是我所做的,但无法解决问题,因此显然我遗漏了一些东西。我不会为此添加完整的代码,因为它很多。
我进一步尝试通过在控制器和路由上调用this.refresh()来触发模型刷新,但这也没有达到预期的效果。从网上出现的类似问题中我了解到,该命令仅作为对Ember的建议,并不强制框架真正刷新。
所以我的问题是:我应该如何重新渲染视图,如果可能的话,不使用pushObject()之类的调用手动更新内部模型。