[英]How to set initial state of child component based on parent component's API call?
[英]How to set initial state of glimmer component based on argument?
我正在努力弄清楚如何在微光組件層次結構中實現數據向下,向上操作(使用 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}} />
// 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 )
}
}
{{!-- app/components/editor.hbs --}}
{{#if @currentModel}}
<small>Editing ID: {{this.id}}</small>
{{/if}}
<Input @value={{this.text}} />
<button {{on 'click' this.save}}>Save</button>
// app/components/editor.hbs
import Component from '@glimmer/component';
import { tracked } from "@glimmer/tracking";
import { action } from "@ember/object";
export default class EditorComponent extends Component {
@tracked text;
@tracked id;
constructor() {
super(...arguments)
if (this.args.currentModel) {
this.text = this.args.currentModel.text;
this.id = this.args.currentModel.id;
}
}
@action
save() {
// persist the updated model back to the parent
this.args.save({ id: this.id, text: this.text })
}
}
我決定將Editor
實現為有狀態組件,因為這似乎是從<Input />
組件中獲取表單數據的最慣用方式。 我使用args
設置初始狀態。 由於this.currentModel
在ParentComponent
中是@tracked
,我希望重新分配該屬性以更新傳遞給Editor
的@currentModel
參數。
確實情況似乎如此,因為單擊ParentComponent
中的一項旁邊的“編輯”會使<small>Editing ID: {{this.id}}</small>
出現。 但是,既沒有填充<Input />
元素的值,也沒有填充id
。
我知道this.text
和this.id
沒有被更新,因為當父級中的currentModel
更改時, EditorComponent
的constructor
沒有重新運行......但我被困在該怎么做。
當我試圖弄清楚這一點時,我遇到了這個示例( code ),它在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}}
// app/components/editor.hbs
import Component from '@glimmer/component';
import { tracked } from "@glimmer/tracking";
import { action } from "@ember/object";
export default class EditorComponent extends Component {
get isEditing() {
return !!this.args.currentModel
}
@action
save() {
// persist the updated model back to the parent
this.args.save({ id: this.id, text: this.text })
}
}
有用! 但我不喜歡這個解決方案,有幾個原因:
arg
傳遞給子組件的某些東西的屬性似乎......令人毛骨悚然......老實說,我不確定它為什么會起作用(因為雖然ParentComponent#models
是@tracked
,但我不希望 POJO 的屬性在要遵循的數組中...)ParentComponent
中的文本,雖然整潔,但不是我想要的——我希望只有在用戶單擊“保存”時才保留更改(在這種情況下什么都不做)<Input @value
...我也遇到過這個問題,但它似乎指的是舊版本的微光。
感謝您閱讀這篇文章---我將不勝感激任何建議!
要在editor
組件中跟currentModel
的更改並設置默認值,請使用get
訪問器:
get model() {
return this.args.currentModel || { text: '', id: null };
}
在您的模板中執行以下操作:
{{#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>
請注意,這會改變您parent
組件中的currentModel
,我猜這不是您想要的。 為了避免這種情況,請從您正在編輯的模型的屬性中創建一個新對象。
解決方案:
// editor/component.js
export default class EditorComponent extends Component {
get model() {
return this.args.currentModel;
}
@action
save() {
this.args.save(this.model);
}
}
在您的父組件中,從傳遞的模型創建一個新對象。 另外,請記住在保存操作中重置currentModel
。 現在您可以在parent
組件的save
操作中檢查id
是否為空,如果是,只需實現您的save
邏輯:
// 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 = {};
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.