12 votes

Mise à jour d'un élément HTML en dehors d'un ng-view

J'ai le HTML ci-dessous sur une page :

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" ng-app="myCart">
<head>
    <title>AngularJS Shopping Cart</title>
    <link href="css/jsonstore.css" rel="stylesheet" />
</head>
<body>
    <div id="container">
        <div id="header">
            <h1>The JSON Store</h1>
            <div class="cart-info">
                My Cart (<span class="cart-items">{{item.basketCount}}</span> items)
            </div>
        </div>
        <div id="main" ng-view>
        </div>
    </div>
    <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.4/angular.js"></script>
    <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.4/angular-resource.js"></script>
    <script src="js/routing.js"></script>
    <script src="js/dataresource.js"></script>
    <script src="js/basketinfo.js"></script>
    <script src="js/index.js"></script>
    <script src="js/detail.js"></script>
</body>
</html>

Le div "main" est remplacé par des modèles HTML par mes routes, mais je voudrais mettre à jour la section d'en-tête avec un compte de panier.

J'ai essayé la liaison de modèle comme indiqué dans le HTML et ci-dessous :

function DetailController($scope, item, basketDetail) {
    $scope.item = item;
    $scope.item.basketCount = basketDetail.getCount();

    //more code
}

J'ai également essayé d'injecter le service et de l'appeler depuis le HTML. Les deux méthodes ne donnent rien.

Quelqu'un peut-il m'aider ?

Merci

15voto

Mark Rajcok Points 85912

Votre header div est en fait une vue, tout comme les autres vues que vous avez définies pour être utilisées avec ng-view. Un jour, vous voudrez peut-être afficher plus que le modèle basketCount dans cette vue d'en-tête. Mais le fait que vous projetiez ne serait-ce qu'un élément de données de modèle dans cette section d'en-tête fait de cette section une vue. Je recommanderais donc de lui donner son propre $scope pour projeter ce modèle, et donc son propre contrôleur.

Reste alors à savoir où placer le modèle basketCount ? Et nous devons considérer que de multiples vues peuvent permettre à l'utilisateur de faire quelque chose qui doit affecter ce modèle. La réponse normale d'Angular à la question "plusieurs besoins d'accès" est l'injection de dépendances. Donc, je mettrais le modèle basketCount dans un service. Les vues/contrôleurs qui ont besoin d'y accéder peuvent l'injecter. Un jour, votre application pourra comporter des vues supplémentaires qui n'auront pas besoin d'accéder à ces modèles, de sorte que ces vues n'injecteront pas le service.

Potentiellement, l'ensemble du panier pourrait être modélisé dans ce service :

app.factory('basketService', function() {
   return {
     items: [],
     itemCount: 0,
     ...
   }
});

function HeaderCtrl($scope, basketService) {
   $scope.basket = basketService;
   ...
}

function DetailCtrl($scope, basketService) {
   $scope.basket = basketService;
   ...
}

<div id="header" ng-controller="HeaderCtrl">
   <h1>The JSON Store</h1>
   <div class="cart-info">
        My Cart (<span class="cart-items">{{basket.itemCount}}</span> items)
   </div>

3voto

Ben Lesh Points 39290

Vous devrez injecter $rootScope, puis le mettre à jour :

function DetailController($scope, $rootScope, basketDetail) {
    $rootScope.item = $rootScope.item || {};
    $rootScope.item.basketCount = basketDetail.getCount();

    //more code
}

Il y a beaucoup d'autres façons de faire, mais c'est ma première suggestion, car c'est probablement la plus facile.


EDIT : selon votre demande, d'autres façons de faire...

Vous pouvez utiliser $parent pour pousser vers votre portée parent. L'avantage est que c'est assez rapide et propre... L'inconvénient est que c'est un peu négligé dans la mesure où l'un de vos contrôleurs fait des suppositions sur ce qu'est son parent dans une certaine mesure (mais ce n'est toujours pas terrible, vraiment) :

   {{item.basketCount}}
   <div ng-controller="InnerCtrl">
   </div>

function InnerCtrl($scope, basketDetail) {
   $scope.$parent.item = $scope.$parent.item || {};
   $scope.$parent.item.basketCount = basketDetail.getCount();
}

Ensuite, il y a la méthode @asgoth mentionnée ci-dessus où vous utilisez un contrôleur imbriqué et une méthode sur la portée parent pour mettre à jour la portée parent. Valable, mais comme mon autre solution dans cette section "autres façons de faire", elle repose sur des hypothèses faites sur le conteneur du contrôleur, et elle repose également sur la création d'un contrôleur supplémentaire.

Enfin, vous pouvez créer un service. Maintenant, les services ne sont généralement pas utilisés de cette façon, mais vous pourriez en utiliser un de cette façon Où vous pourriez prendre votre service basketDetail, et l'utiliser pour passer la valeur dans les deux sens. Comme ça :

app.factory('basketDetail', function() {
   return {
      items: { basketCount: 0 },
      getCount: function() {
          //return something here
          return 123;
      }
   }
});

function FooCtrl($scope, basketDetail) {
   $scope.items = basketDetail.items;
   $scope.items.basketCount = basketDetail.getCount();
}

function BarCtrl($scope, basketDetail) {
   $scope.items = basketDetail.items;
}

<div ng-controller="FooCtrl">
  {{items.basketCount}}
</div>
<div ng-controller="BarCtrl">
  {{items.basketCount}}
</div>

Cela fonctionne parce que le $scope des deux contrôleurs conserve une référence au même objet, qui est géré par votre service basketDetail. Mais encore une fois, ce n'est pas vraiment la méthode recommandée.

Tout cela étant dit : $rootScope, IMO est très probablement ce que vous recherchez.

  • Il ne nécessite pas la création d'un contrôleur supplémentaire.
  • Elle ne nécessite pas la création de références de fonctions supplémentaires.
  • N'entraînera pas la création d'une imbrication supplémentaire de Scope parent/enfant et de montres ultérieures.

2voto

asgoth Points 14599

Pas de réel besoin de $rootScope . Créez un contrôleur parent (par exemple RootController ) avec une fonction sur sa portée. Les scopes enfants en hériteront automatiquement :

<div id="container" ng-controller="RootController">
...

function RootController($scope) {
   $scope.item = {};

   $scope.setBasketCount = function (detail) {
      $scope.item.basketCount = detail.getCount();
   }
}

Dans votre contrôleur de détail, vous utilisez simplement l'élément setBasketCount() fonction :

function DetailController($scope, item, basketDetail) {
    $scope.item = item;
    $scope.setBasketCount(basketDetail);

    //more code
}

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