7 votes

Comment passer des événements entre contrôleurs dans Emberjs ? Mise à jour : Comment concevoir un autocomplete en Ember

Scénario : Un widget d'autocomplétion avec son propre contrôleur et sa propre vue, de sorte qu'il s'agit d'un composant modulaire qui peut être rendu dans n'importe quelle autre vue avec {{render "autocomplete"}} ou éventuellement la nouvelle aide {{control}} une fois qu'il sera sorti de la phase expérimentale. Afin de rendre l'autocomplétion indépendante de tout le reste, elle ne doit pas être consciente du contrôleur parent ou de l'action qui se produit lorsqu'un élément est sélectionné.

J'ai essayé de comprendre comment utiliser le mixin Ember.Evented afin de pouvoir déclencher un événement à partir de l'autocomplétion, tel que itemSelected, qui peut ensuite remonter et être pris en compte par la vue ou le contrôleur parent.

Comme toujours, la documentation sur Ember est lacunaire. Surtout quand il s'agit d'Ember.Evented. (Pour être honnête, la documentation a beaucoup évolué, mais j'en veux toujours plus. On dit que la convention est préférable à la configuration sans fournir de conventions). Quoi qu'il en soit, assez de se plaindre, la documentation montre qu'Ember Evented fonctionne sur des objets génériques et j'ai trouvé ce post qui va un peu plus en profondeur : EmberJs prend-il en charge les événements de type "publish/subscriber" ? mais je pense qu'un exemple plus concret avec des contrôleurs, des vues, des routes et des composants comme les autocomplétions serait parfait.

Je pensais que ces types d'événements étaient censés relever de la responsabilité des vues, mais cela n'a pas fonctionné, alors j'ai mis le mixin sur les contrôleurs également. Cela prendra tout son sens lorsque vous verrez la jsFiddle

Vous y verrez un faux contrôleur d'autocomplétion qui récupère un ensemble statique de contenu à partir d'une fixation et affiche deux boutons pour chaque élément sur lesquels vous pouvez cliquer pour déclencher un événement à partir de la vue ou du contrôleur. Dans un exemple réel, la saisie dans la zone de texte serait observée et le contenu serait mis à jour pour présenter différentes suggestions en fonction de la saisie, mais ce n'est pas important pour cet exemple.

jsFiddle : http://jsfiddle.net/wCfb9/ Ce sont ces lignes qui m'inspirent le plus de méfiance : this.on("myEvent", this.addItem); puisque la fonction qui déclenche l'événement est clairement appelée, mais c'est comme si l'événement ne se propageait pas ou que le contrôleur d'index et la vue n'étaient pas correctement configurés pour répondre à l'événement.

Voici les principales questions :

  1. Que dois-je modifier pour que le contrôleur d'index puisse répondre à un événement déclenché par l'autocomplétion ?

  2. Quel est le moyen le plus approprié pour y parvenir ? Le déclenchement et la réception doivent-ils se faire au niveau de la vue ou du contrôleur ?

  3. Existe-t-il une meilleure façon de procéder ?

Note complémentaire : Ma solution actuelle est d'ajouter un needs: ["index"] dans le contrôleur d'autocomplétion et au lieu de déclencher des événements, j'appelle explicitement la méthode dans le contrôleur d'index à partir du contrôleur d'autocomplétion. Cela pose de nombreux problèmes, tout d'abord un couplage étroit entre les contrôleurs, et ne s'adapte pas bien si l'autocomplétion est supposée affecter plusieurs contrôleurs ou être réutilisée ailleurs et doit être reconfigurée, etc.

J'espère avoir été suffisamment clair. Toute aide est appréciée.

3voto

Mike Grassotti Points 15937

Excellente question.

Pour que l'autocomplétion soit indépendante de tout le reste, elle ne doit pas connaître le contrôleur parent ni l'action qui se produit lorsqu'un élément est sélectionné.

Oui, je pense que vous êtes sur la bonne voie en essayant de garder les choses aussi isolées que possible.

Existe-t-il une meilleure façon de procéder ?

Je pense que la meilleure solution est d'utiliser la nouvelle fonctionnalité "composants" introduite dans la RC6. Voir Ember Component API Docs pour plus de détails.

L'approche par composants permet d'atteindre l'objectif d'une autocomplétion indépendante du contrôleur parent et de ce qui se passe lorsqu'un élément est sélectionné. C'est assez proche de la façon dont fonctionne la vue Ember.Select intégrée. Par exemple :

{{app-autocomplete items=model selectedItem=selectedPerson}}

Ici, j'ai défini les propriétés items et selectedItem de l'autocomplete pour qu'elles soient liées aux valeurs du contrôleur actuel. app-autocomplete ne sait pas ce qu'il y a de l'autre côté de ces liaisons ni comment l'appelant réagira lorsque les valeurs changeront. Votre contrôleur d'index peut alors observer sa propre propriété selectedPerson et réagir lorsqu'elle change. Quelque chose comme ceci :

App.IndexController = Ember.ArrayController.extend({
  selectedPerson: null,
  selectedPersonDidChange: function() {
      Ember.Logger.log("Index.contoller addItem: ", this.get('selectedPerson').toString());
  }.observes('selectedPerson'),
});

Le composant est également très simple. Il s'attend à ce que son items pour contenir un tableau d'objets avec un name et lorsque l'on clique sur l'un d'entre eux, il définit sa propre selectedItem propriété.

<script type="text/x-handlebars" id="components/app-autocomplete">
  {{input}}
  {{#each item in items}}
    <li><button {{action itemSelected item}}>{{item.name}}</button></li>
  {{/each}}
</script>

App.AppAutocompleteComponent = Ember.Component.extend({
itemSelected: function (item) {
  this.set("selectedItem", item);
      Ember.Logger.log("component.itemSelected: myEvent triggered wit h: ", item.toString());
}
});

Exemple complet ici : http://jsfiddle.net/dKUf4/

3voto

Matt Mazzola Points 450

Sur la base de la suggestion de Mike Grassotti, nous pensons qu'Ember.Evented n'est pas vraiment la bonne solution et nous avons commencé à étudier {{control}} et Ember.Component.

Je ne suis toujours pas sûr du lien jsFiddle qu'il a posté, mais j'ai eu assez d'informations à partir de son post et j'ai créé un jsBin pour simuler à la fois la tentative d'utiliser {{control}} et celle d'utiliser Ember.Component. Il y a des avantages et des inconvénients à chacun, mais à la fin, Ember.Component a gagné parce que le {{control}} ne se liait pas correctement.

Voir : http://jsbin.com/ehokak/3/ ( Je n'ai pas réussi à trouver comment définir ENV.EXPERIMENTAL_CONTROL_HELPER dans jsFiddle, c'est pourquoi j'ai utilisé jsBin et j'ai fini par préférer jsBin...) )

Vous y trouverez deux autocomplétions. Une implémentée avec l'aide {{control}} qui utilise un AutocompleteController et AutocompleteView et une avec Ember.Component comme Mike Grassotti l'a suggéré.

#1 Utilisation de l'aide {{control}} :

Pour : J'aime l'idée d'avoir un contrôleur pour l'autocomplétion parce que je pense que c'est une meilleure séparation des préoccupations / une responsabilité unique. Le contrôleur de l'autocomplétion devrait savoir comment traiter le texte dans la boîte de saisie, comment envoyer une requête et analyser les données si nécessaire.

Cons : Le premier problème que j'ai rencontré est que l'aide au contrôle semble nécessiter un modèle. Cependant, le contrôleur d'index ne devrait pas se soucier du type de modèle utilisé par l'autocomplétion, tout ce qu'il devrait savoir c'est qu'il recevra l'élément sélectionné sur la propriété que nous choisissons de lier. Voir : controlItemSelectedBinding="itemSelected1"

Le deuxième problème qui a été un frein est qu'il semble que les bindings de l'aide au contrôle ne fonctionnent pas comme prévu. Pour cette raison, le contrôleur d'index n'a jamais observé le changement sur itemSelected1. Je ne savais pas comment écrire les bindings sur le control helper car ils sont différents sur les composants. Certains utilisent le suffixe *Binding, les guillemets sur les valeurs, etc. J'ai essayé toutes les combinaisons et aucune n'a fonctionné. Je ne sais pas si c'est un bug ou une fonctionnalité, mais c'est comme si les bindings étaient à sens unique.

#2 Utilisation de Ember.Component :

Pour : Cela a fonctionné ! Comme vous pouvez le voir, il y a du code fictif pour mettre à jour le contenu lorsque vous tapez dans la boîte de saisie, et lorsque vous cliquez sur un bouton à côté de l'élément, il définit le code local componentItemSelected et parce qu'elle est liée à IndexControllers.itemSelected2, le changement est observé et le contrôleur d'index peut prendre les mesures qui s'imposent.

Cons : Je n'aime pas l'idée que le composant soit responsable du travail avec les modèles, etc. puisque je crois comprendre que les composants sont censés être des extensions des vues, mais compte tenu du fait qu'il n'y a pas d'alternative pratique, c'est le gagnant par défaut .

Encore une fois, un grand merci à Mike pour l'astuce concernant l'utilisation d'Ember.Component.

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