簡體   English   中英

如何根據參數設置微光組件的初始狀態?

[英]How to set initial state of glimmer component based on argument?

我正在努力弄清楚如何在微光組件層次結構中實現數據向下,向上操作(使用 Ember Octane,v3.15)。

我有一個帶有項目列表的父組件。 當用戶單擊Parent組件中的按鈕時,我想用相關項目的數據填充Editor組件; 當用戶在Editor組件中單擊“保存”時,將更改填充回父級。 這是發生的事情:

我的應用程序的 GIF

如何使文本框填充“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.currentModelParentComponent中是@tracked ,我希望重新分配該屬性以更新傳遞給Editor@currentModel參數。

確實情況似乎如此,因為單擊ParentComponent中的一項旁邊的“編輯”會使<small>Editing ID: {{this.id}}</small>出現。 但是,既沒有填充<Input />元素的值,也沒有填充id

我知道this.textthis.id沒有被更新,因為當父級中的currentModel更改時, EditorComponentconstructor沒有重新運行......但我被困在該怎么做。


我試過的

當我試圖弄清楚這一點時,我遇到了這個示例code ),它在BlogAuthorComponenthbs )和BlogAuthorEditComponenthbsjs )之間具有幾乎相同的交互。 他們的解決方案,適用於我的問題,是這樣編寫 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM