cas*_*run 5 javascript ember.js glimmer.js
我正在努力弄清楚如何在一个微光组件层次结构中向下实现数据,向上执行操作(使用 Ember Octane,v3.15)。
我有一个带有项目列表的父组件。当用户单击Parent组件内的按钮时,我想Editor用相关项目的数据填充组件;当用户在Editor组件中单击“保存”时,将更改填充回父级。下面是发生的情况:
如何让文本框填充“Hello”,并在单击“保存”时将更改保留回上面的列表?
{{!-- app/components/parent.hbs --}}
<ul>
{{#each this.models as |model|}}
<li>{{model.text}} <button {{on 'click' (fn this.edit model)}}>Edit</button></li>
{{/each}}
</ul>
<Editor @currentModel={{this.currentModel}} @save={{this.save}} />
Run Code Online (Sandbox Code Playgroud)
{{!-- app/components/parent.hbs --}}
<ul>
{{#each this.models as |model|}}
<li>{{model.text}} <button {{on 'click' (fn this.edit model)}}>Edit</button></li>
{{/each}}
</ul>
<Editor @currentModel={{this.currentModel}} @save={{this.save}} />
Run Code Online (Sandbox Code Playgroud)
{{!-- app/components/editor.hbs --}}
{{#if @currentModel}}
<small>Editing ID: {{this.id}}</small>
{{/if}}
<Input @value={{this.text}} />
<button {{on 'click' this.save}}>Save</button>
Run Code Online (Sandbox Code Playgroud)
// app/components/parent.js
import Component from '@glimmer/component';
export default class ParentComponent extends Component {
@tracked models = [
{ id: 1, text: 'Hello'},
{ id: 2, text: 'World'}
]
@tracked currentModel = null;
@action
edit(model) {
this.currentModel = model;
}
@action
save(model) {
// persist data
this.models = models.map( (m) => m.id == model.id ? model : m )
}
}
Run Code Online (Sandbox Code Playgroud)
我决定Editor作为一个有状态的组件来实现,因为这似乎是从<Input />组件中获取表单数据的最惯用的方式。我使用args. 由于this.currentModel是@tracked在ParentComponent,我希望重新分配该属性以更新@currentModel传递给Editor.
确实如此,因为单击 make 中的一项旁边的“编辑”ParentComponent会<small>Editing ID: {{this.id}}</small>出现。但是,既不填充<Input />元素的值,也不id填充 。
我理解这一点this.text并且this.id没有被更新,因为当父级发生变化时, constructor ofEditorComponent不会重新运行currentModel......但我坚持要做什么。
当我试图弄清楚这一点时,我遇到了这个示例(代码),它在BlogAuthorComponent( hbs ) 和BlogAuthorEditComponent( hbs , js )之间具有几乎相同的交互。他们的解决方案,适用于我的问题,将像这样编写 EditorComponent:
{{!-- app/components/editor.hbs --}}
{{#if this.isEditing}}
<small>Editing ID: {{@currentModel.id}}</small>
<Input @value={{@currentModel.text}} />
<button {{on 'click' this.save}}>Save</button>
{{/if}}
Run Code Online (Sandbox Code Playgroud)
{{!-- app/components/editor.hbs --}}
{{#if @currentModel}}
<small>Editing ID: {{this.id}}</small>
{{/if}}
<Input @value={{this.text}} />
<button {{on 'click' this.save}}>Save</button>
Run Code Online (Sandbox Code Playgroud)
有用!但我不喜欢这个解决方案,有几个原因: - 修改传递给子组件的某物的属性作为一个arg看起来......怪异......老实说,我不确定它为什么会起作用(因为 whileParentComponent#models是@tracked,我不希望遵循该数组中 POJO 的属性......) - 这会在ParentComponent您键入时更新文本,虽然整洁,但不是我想要的---我希望更改仅保留当用户点击“保存”(在这种情况下什么都不做) - 在我的真实应用中,当用户没有“编辑”现有项目时,我希望表单是“添加项目”表单,点击“保存”按钮添加一个新项目。一世'<Input @value
我也遇到过这个问题,但它似乎指的是旧版本的微光。
感谢您阅读到这里---我将不胜感激!
要跟踪对currentModel您的editor组件,并设置一个默认值,使用get访问:
get model() {
return this.args.currentModel || { text: '', id: null };
}
Run Code Online (Sandbox Code Playgroud)
在你的模板中做:
{{#if this.model.id}}
<small>
Editing ID:
{{this.model.id}}
</small>
{{/if}}
<Input @value={{this.model.text}} />
<button type="button" {{on "click" this.save}}>
Save
</button>
Run Code Online (Sandbox Code Playgroud)
请注意,这会currentModel在您的parent组件中发生变异,我想这不是您想要的。要避免这种情况,请根据您正在编辑的模型的属性创建一个新对象。
解决方案:
// editor/component.js
export default class EditorComponent extends Component {
get model() {
return this.args.currentModel;
}
@action
save() {
this.args.save(this.model);
}
}
Run Code Online (Sandbox Code Playgroud)
在您的父组件中,从传递的模型创建一个新对象。另外,请记住currentModel在保存操作中重置。现在您只需检查组件操作中是否id为空,如果是,只需实现您的逻辑:parentsavesave
// parent/component.js
@tracked currentModel = {};
@action
edit(model) {
// create a new object
this.currentModel = { ...model };
}
@action
save(model) {
if (model.id) {
this.models = this.models.map((m) => (m.id == model.id ? model : m));
} else {
// save logic
}
this.currentModel = {};
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
711 次 |
| 最近记录: |