2 votes

Comment suivre un attribut imbriqué dans un composant Glimmer ?

Je suis en train de construire mon premier composant Glimmmer en Ember et j'avais quelque chose comme ceci dans mon modèle :

<p>Some val: {{this.my_obj.some.deeply.nested.path.to.val}}</p>

J'ai ensuite fait une correspondance .js et je me suis dit que j'allais essayer de supprimer le long chemin d'accès du HTML.

Ma première tentative a été de faire un getter :

get val() {
  return this.my_obj.some.deeply.nested.path.to.val;
}

Avec le modèle maintenant :

<p>Some val: {{this.val}}</p>

Cela fonctionne initialement et affiche la valeur de départ attribuée à l'élément val mais elle n'est pas mise à jour lorsque la variable sous-jacente val changements.

J'ai donc pensé que je pourrais marquer le getter comme suivi, mais cela a fait disparaître la sortie :

@tracked val;

get val() {
  return this.my_obj.some.deeply.nested.path.to.val;
}

J'ai alors essayé ceci, mais ce n'est pas une syntaxe valide :

@tracked this.my_obj.some.deeply.nested.path.to.val;

Alors comment gérer cela dans un composant Glimmer ?

La solution n'est certainement pas que le HTML fasse référence à un chemin profond comme celui-ci à chaque fois que la variable est référencée, mais la nouvelle documentation d'Ember, aussi agréable soit-elle, ne me laisse pas le temps de comprendre ce cas relativement simple/commun.

5voto

Krutius Points 750

C'est simple : tout ce que vous changez doit être @tracked . Si vous avez {{this.my_obj.some.deeply.nested.path.to.val}} dans votre hbs ou un getter qui retourne cela ne fait pas de différence.

Mais si vous le faites this.my_obj.some.deeply.nested.path.to.val = "something" et que vous voulez que la valeur soit mise à jour, vous devez vous assurer que lors de la mise à jour de la valeur, la valeur est mise à jour. this.my_obj.some.deeply.nested.path.to val est défini comme suivi.

Cela ne fonctionnera donc pas :

@tracked data;
constructor() {
  super(...arguments);
  this.data = { foo: 1 };
}
@action test() {
  this.data.foo = 2; // this will not correctly update
}

vous devez vous assurer que foo es @tracked :

class DataWrapper {
  @tracked foo;
}

...

@tracked data;
constructor() {
  super(...arguments);
  this.data = new DataWrapper();
  this.data.foo = 1;
}
@action test() {
  this.data.foo = 2; // this will now correctly update
}

Ou vous invalidez manuellement. Donc ça va marcher :

@tracked data;
constructor() {
  super(...arguments);
  this.data = { foo: 1 };
}
@action test() {
  this.data.foo = 2; // this will not update
  this.data = this.data; // this ensures that everything that depends on `data` will correctly update. So `foo` will correctly update.
}

C'est aussi une chose importante : @tracked ne doit jamais être défini sur un getter. Cela ne fonctionnera pas. Il doit être défini directement lorsque vous souhaitez modifier quelque chose qui doit déclencher une mise à jour. Cependant, vous pouvez utiliser les getters sans problème. Cela fonctionnera tout simplement, tant que tout ce que vous définissez avec la fonction objsomething = value est correctement @tracked . De même, les appels de fonction (purs) fonctionneront tout simplement.

-1voto

Edoardo99 Points 49

J'ai trouvé la réponse dans cette feuille de route - https://ember-learn.github.io/ember-octane-vs-classic-cheat-sheet/#component-properties

Il existe un @computed qui permet de suivre correctement les modifications de l'attribut imbriqué :

import { computed } from '@ember/object';

// Note that no 'this.' is used here
@computed("my_obj.some.deeply.nested.path.to.val")
get val() {
  return this.my_obj.some.deeply.nested.path.to.val;
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X