Multiple controller dans une vue

L'auteur de ce sujet a trouvé une solution à son problème.
Auteur du sujet

Bonsoir à tous,

Je me suis récemment mis à AngularJs et il faut dire que l'on peu effectivement faire des applications complète en peu de temps.
Je fais face à un problème dont je n'ai cependant pas pu trouver de solutions, enfin il en existe bien au moins une mais je ne l'aime pas du tout.

Je suis en train de réaliser une application de vente, donc liste des produits, gestion du panier… et j'ai décidé de découper la gestion du panier de l'affichage des produits. J'ai donc un controller pour le panier et un controlleur pour la liste des produit.
Lorsque l'on va sur l'url /produits dans la liste des routes définie dans angular c'est le controller des produits qui est appelé. Cependant, dans la vue de celui-ci j'inclus la vue du panier avec le controller de celui-ci afin de permettre au client de voir où il en est dans son panier avec un simple survol de la souris.

Lorsque l'on selectionne un produit, j'utilise la fonction $rootScope.$emit pour que le controller des produits envoie un message au panier afin de tenir compte de l'ajout.

Jusqu'ici tout fonctionne bien, je me suis mis à développer une interface de gestion utilisant le gestionnaire de route d'angular et donc durant mes tests je passais de la page des produits à la page de gestion.

Et c'est là que le problème surviens, lorsque j'appuye sur un bouton, l'action n'était plus éxécuté 1 fois mais 2, 3 fois et plus encore.
J'ai pris du temps pour analyser d'où venais le problème mais j'ai finalement compris, c'est le fait de l'inclusion du controller panier dans la vue des produit avec la communication entre les deux.
Lorsque le controller des produits envoie un message il l'envoie bien qu'une seule fois, mais le controller panier le reçois autant de fois que je suis revenu sur la vue produits (donc que celui-ci à été chargé).

La seule solution que je suis parvenu à imaginer c'est fusionner le controller panier avec le controller produit… le problème c'est que le pannier est utilisé sur d'autre page… bref, à ce jeu là je suis parti pour finalement avoir toute mon application dans un seul controller et je dois dire que je trouve sa très décevant.

Quelqu'un aurai-t'il une idée de comment faire bien les choses afin de régler le problème ?

Merci d'avance pour votre aide.
Cordialement, La source.

+0 -0

Je suis aussi un débutant d'angular donc je ne garantie rien, mais pourquoi ne pas utiliser un service/Factory pour partager les données du panier entre tes contrôleurs ?

https://nicolashcodes.wordpress.com/2015/06/28/truc-15-partager-un-modele-entre-plusieurs-controleurs-a-laide-dun-servicefactory/

http://www.frangular.com/2013/10/conserver-valeurs-criteres-recherche.html

Ca t’évitera de faire appel au RootScope qui ne devrait pas être appelé dans ce genre de cas et éviter les problèmes d'héritages de scoop et appel multiples d'une fonction. Ainsi tu ne devrais avoir que d'un service Panier (partagé entre tous les contrôleurs qui ont besoin d'afficher ou d’interagir avec le panier) et d'un contrôleur produit qui utilise le service $Panier !

Normalement ainsi tu ne devrais plus avoir de problèmes en changement de pages tant que tu restes dans l'application (tu peux aussi faire en sorte que le service $Panier enregistre les données du panier quelque part si tu veux conserver le panier si l'utilisateur quitte le site!).

En fait la plupart de la logique d'une application doit être dans un service, le contrôleur doit faire le minimum de choses, il doit en théorie juste appeler le service qui fait l'action. Dans ton cas par exemple avec un service panier le contrôleur doit appeler le service pour ajouter un objet au panier, mais pas le faire lui même (que ça soit en implémentation la fonction directement ou par héritage via $RootScoop). Un contrôleur doit uniquement s'occuper des données/Fonctions publiées dans le scoop/template, tout le reste doit être dans des services ! En procédant ainsi ton code sera plus facile à maintenir car plus modulable.

Édité par Demandred

"Il est vraiment regrettable que tous les gens qui savent parfaitement comment diriger un pays soient trop occupés à conduire des taxis et à couper des cheveux"

+0 -0
Auteur du sujet

Merci pour ta réponse.

Je ne suis pas d'accord lorsque tu dis que le controlleur doit faire le minimum de chose, dans le concept d'angular c'est justement au controlleur de gérer un maximum de chose. Evidemment lorsqu'il y a des comportements commun il faut réfléchir à comment mutualiser le code.

Effectivement l'utilisation d'un service semble être la bonne option ici cependant je me demande comment gérer la vue.

Concrètement, je retrouve l'affichage de mon panier sur plusieurs page du site, en passant le curseur dessus un popup apparaît montrant le contenu et lorsque l'on survole une ligne des contrôles apparaissent afin de permettre par exemple la suppression du produit.

Bref, dans mon controller produit j'écrivais un <div ng-include="panier.html" ng-controller="PanierController"> ainsi lorsque l'on appuie sur la corbeille le controller est sollicité et je peu gérer l'action utilisateur.

Si je passe par un service, comment gérer ses contrôles ? Si je dois dans chacun de mes contrôleurs créer des fonctions proxy… sa va être un peu pénible :s

+0 -0

Pourquoi ne pas créer une directive "panier" plutôt que d'inclure le code via un ng-include ?

Si je passe par un service, comment gérer ses contrôles ?

Normalement si tu injecte le service en dépendance de chaque contrôleur, chaqun peut l'utiliser. Il suffit de donner à ton service les fonctions nécessaires du genre "ajouterProduit", "supprimerProduit" etc. Lors que ton contrôleur veut ajouter un produit via un bouton, il suffit de mettre un ng-click sur un bouton qui appel la fonction "ajouterProduit" du service et lui passe en paramètres les données nécessaires (id produit, nombre de produits etc…) !

e ne suis pas d'accord lorsque tu dis que le controlleur doit faire le minimum de chose, dans le concept d'angular c'est justement au controlleur de gérer un maximum de chose.

j'imagine que c'est une question de point de vue et de façon de voir, mais j'ai toujours vu les utilisateurs avancés indiquer que le ctrl ne doit gêrer que les relations avec la vue. Il doit déléguer le reste (récupération des données via une api par exemple) à des services ou autres composants. Je trouve que ça à du sens et que ça permet une meilleure organisation du code ainsi qu'une plus grande modularité.

Voici un lien parmi d'autres qui explique cette vision des choses : http://blog.xebia.fr/2014/04/18/devoxxfr-au-secours-mon-code-angularjs-est-pourri/

"Il est vraiment regrettable que tous les gens qui savent parfaitement comment diriger un pays soient trop occupés à conduire des taxis et à couper des cheveux"

+0 -0
Auteur du sujet

Directive ou include… sa change vraiment quelque chose ?

Justement, sa force à écrire une vingtaine de fonctions proxy dans chaque controller, chaque fois que j'ajouterai une fonction au panier je devrai le faire dans tous mes controllers utilisant le panier… moarf

+0 -0

Directive ou include… sa change vraiment quelque chose ?

Disons que utiliser une directive personnalisée est plus dans l'esprit d'angular, et te permet de rendre ton code plus compréhensible. Tu aura juste une balise <panier></panier> quand tu voudrais utiliser ton panier ! Je trouve ça plus pratique d'une div avec un include et un contrôleur.

Après c'est vrai que ça ne change pas grand chose non plus, à toi de voir ce qui te convient le mieux !

j'ajouterai une fonction au panier je devrai le faire dans tous mes controllers utilisant le panier

Je ne comprends pas trop. Normalement si tu définis ces fonctions dans le service, chaque contrôleur doit juste utiliser le service et la fonction "ajouterProduit" du service. Tu écris la fonction une seule fois (dans le service) et tu l'appel via le contrôleur à chaque fois que nécessaire ! Si tu ajoute une fonction au panier, tous les contrôleurs y auront accès et pourront appeler cette fonction.

Sinon je ne sais pas si tu l'utilise, mais quitte à parler de bonnes pratiques je te conseil de déclarer tes controllers avec "as", comme présenté dans cet article. C'est un peu plus verbeux mais ça rend ton code plus lisible et ça permet d'éviter pas mal de problèmes d'héritages de $scope imbriqués qui sont un calvaire dans une application un peu complexe qui n’utiliserait pas cette syntaxe.

"Il est vraiment regrettable que tous les gens qui savent parfaitement comment diriger un pays soient trop occupés à conduire des taxis et à couper des cheveux"

+0 -0
Auteur du sujet

Si dans le service je définit les fonctions addProduit, removeProduit, savePanier, et ainsi de suite, dans mon controlleur je devrai tout de même déclarer des fonctions proxy.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
function ProduitController($scope, servicePanier) {
  // code du controlleur en tant que tel

  $scope.addProduit = function(produit) {
    servicePanier.addProduit(produit); // Là pas de problème, s'pas un proxy vu que c'est issus du controlleur
  };

  $scope.removeProduit = servicePanier.removeProduit;
  $scope.savePanier = servicePanier.savePanier;
  // Et ainsi de suite pour tous les contrôles (boutons) gérant le panier issus de l'include/directive
}

Donc dans mon controller exemple ci-dessus j'ai écrire un proxy pour deux fonctions… Imaginons maintenant que j'ai pas 2 fonctions mais 20 et que je n'ai pas 1 controller mais 15. Si j'ajoute un nouveau bouton dans le panier je dois aller modifier mes 15 controlleurs afin de prendre en compte la nouveauté :s

+0 -0

C'est en un sens difficile de faire autrement…

Je ne sais pas comment fonctionne ton application, mais tu ne peux pas justement utiliser des directives qui s'occupent de ça ? Par exemple une directive <Produit> qui gêre un produit et contient elle même une directive <AddPanier></addPanier> qui crée un bouton qui ajoute le produit au panier !

Ainsi chaque fois que tu veux montrer des produits tu appel la directive <produit> qui s'occupe de l'affichage et ajoute les fonctionnalités pour interagir avec le panier. A toi de voir les différents niveaux d'imbrication que tu veux. Par exemple ajouter manuellement la directive <addProduit> qui crée un bouton d'ajouter au panier sous la directive d'affichage du produit (ce qui permet de l'afficher ou pas selon les besoins) ou au contraire de l'intégrer directement dans la directive <produit> si tu veux toujours afficher ce bouton sous un produit.

Comme ça plus besoin de faire un proxy à chaque fois !

"Il est vraiment regrettable que tous les gens qui savent parfaitement comment diriger un pays soient trop occupés à conduire des taxis et à couper des cheveux"

+0 -0
Vous devez être connecté pour pouvoir poster un message.
Connexion

Pas encore inscrit ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte