私は、データを下に実装し、アクションをきらめくコンポーネント階層で上に実装する方法を理解するのに苦労しています(Ember Octane、v3.15を使用)。
アイテムのリストを持つ親コンポーネントがあります。ユーザーがParent
コンポーネント内のボタンをクリックしたときに、Editor
関連するアイテムのデータをコンポーネントに入力したいと思います。ユーザーがEditor
コンポーネント内で[保存]をクリックすると、変更を親に戻します。代わりに次のようになります。
テキストボックスに「こんにちは」と入力し、「保存」をクリックしたときに変更を上記のリストに保持するにはどうすればよいですか?
{{!-- 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
ある@tracked
にParentComponent
し、私が更新するために、そのプロパティの再割り当てを期待する@currentModel
に渡される引数をEditor
。
実際、次の内のいずれかの項目に「編集」をクリックするので、ケースのように思われるParentComponent
可能<small>Editing ID: {{this.id}}</small>
表示されます。ただし、<Input />
要素の値もid
入力もされません。
私はそれを理解してthis.text
おり、親の変更時にofが再実行されないthis.id
ため、更新されていません...しかし、代わりに何をすべきかについて悩んでいます。constructor
EditorComponent
currentModel
これを理解しようとしていたときに、(hbs)と(hbs、js)の間でほぼ同じ相互作用を持つこの例(コード)に出くわしました。私の問題に適用される彼らの解決策は、次のようにEditorComponentを書くことです。BlogAuthorComponent
BlogAuthorEditComponent
{{!-- 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
私もこの質問に出くわしましたが、それは古いバージョンのグリマーを参照しているようです。
ここまで読んでいただきありがとうございます---アドバイスをいただければ幸いです。
コンポーネントcurrentModel
内のへの変更を追跡しeditor
、デフォルト値を設定するには、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>
ただし、これはコンポーネント内で変化currentModel
することに注意してください。これは、あなたparent
が望むものではないと思います。これを回避するには、編集しているモデルのプロパティから新しいオブジェクトを作成します。
解決:
// editor/component.js
export default class EditorComponent extends Component {
get model() {
return this.args.currentModel;
}
@action
save() {
this.args.save(this.model);
}
}
親コンポーネントで、渡されたモデルから新しいオブジェクトを作成します。また、currentModel
保存アクションでリセットすることを忘れないでください。これid
で、parent
コンポーネントのsave
アクションでnullかどうかを確認でき、nullの場合は、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 = {};
}
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加