Pouvez-vous transmettre des paramètres à un contrôleur AngularJS lors de la création?

278

J'ai un contrôleur chargé de communiquer avec une API pour mettre à jour les propriétés d'un utilisateur, nom, e-mail, etc. Chaque utilisateur a un 'id'qui est transmis par le serveur lorsque la page de profil est consultée.

Je voudrais transmettre cette valeur au contrôleur AngularJS afin qu'il sache quel est le point d'entrée de l'API pour l'utilisateur actuel. J'ai essayé de transmettre la valeur ng-controller. Par exemple:

function UserCtrl(id, $scope, $filter) {

$scope.connection = $resource('api.com/user/' + id)

et dans le HTML

<body ng-controller="UserCtrl({% id %})">

{% id %}imprimer l'identifiant envoyé par le serveur. mais je reçois des erreurs.

Quelle est la bonne façon de transmettre une valeur à un contrôleur lors de sa création?

nickponline
la source
6
si vous aviez l'identifiant dans l'url, alors vous pouvez simplement lire l'url
akonsu
J'ai eu un problème très similaire et je l'ai résolu comme je l'ai signalé dans ma réponse. Parfois, en utilisant les bibliothèques, nous oublions le concept fondamental simple de l'appel de fonction JavaScript.
Jigar Patel
@nickponline Après 21+, vous pensez toujours que ce n'est pas possible?
om471987

Réponses:

362

Remarques:

Cette réponse est ancienne. Ce n'est qu'une preuve de concept sur la façon dont le résultat souhaité peut être atteint. Cependant, ce n'est peut-être pas la meilleure solution selon certains commentaires ci-dessous. Je n'ai aucune documentation pour soutenir ou rejeter l'approche suivante. Veuillez vous référer à certains des commentaires ci-dessous pour une discussion plus approfondie sur ce sujet.

Réponse originale:

J'ai répondu à Oui, vous pouvez absolument le faire à l'aide d' ng-initune simple fonction d'initialisation.

En voici l'exemple sur plunker

HTML

<!DOCTYPE html>
<html ng-app="angularjs-starter">
  <head lang="en">
    <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.0.3/angular.min.js"></script>
    <script src="app.js"></script>
  </head>  
  <body ng-controller="MainCtrl" ng-init="init('James Bond','007')">
    <h1>I am  {{name}} {{id}}</h1>
  </body>
</html>

Javascript

var app = angular.module('angularjs-starter', []);

app.controller('MainCtrl', function($scope) {

  $scope.init = function(name, id)
  {
    //This function is sort of private constructor for controller
    $scope.id = id;
    $scope.name = name; 
    //Based on passed argument you can make a call to resource
    //and initialize more objects
    //$resource.getMeBond(007)
  };


});
Jigar Patel
la source
5
Merci pour cela - m'a sauvé beaucoup de gratter la tête, et cela a parfaitement fonctionné pour ma situation. J'ai dû initialiser mon contrôleur avec un ID d'objet, et c'était parfait.
Masonoise
26
De docs :The only appropriate use of ngInit for aliasing special properties of ngRepeat, as seen in the demo below. Besides this case, you should use controllers rather than ngInit to initialize values on a scope.
Sergey Goliney
8
La réponse indique clairement que le doc recommande contre cette approche, mais quelqu'un peut-il m'indiquer où les documents fournissent la solution officielle?
Michael Pell
53
Eh bien, je pense que les docs sont pauvres en recommandant simplement contre cette approche sans donner de raisons. Je pense que c'est une approche brillante. Si les auteurs du cadre ne veulent pas que le cadre soit utilisé de manière "erronée" pour eux, alors ils ne devraient pas permettre qu'il soit utilisé de cette manière "erronée" ... et fournir des indications sur le " La bonne façon!
Shawn de Wet
2
un mot d'avertissement - si vous essayez de vous lier à une valeur de portée, ou si vous faites vraiment quelque chose qui s'attend à ce que la valeur soit présente dans la fonction de contrôleur, il a déjà exécuté la fonction de contrôleur avant de ng-initse produire
drzaus
143

Je suis très en retard et je n'ai aucune idée si c'est une bonne idée, mais vous pouvez inclure l' $attrsinjectable dans la fonction contrôleur permettant au contrôleur d'être initialisé en utilisant des "arguments" fournis sur un élément, par exemple

app.controller('modelController', function($scope, $attrs) {
    if (!$attrs.model) throw new Error("No model for modelController");

    // Initialize $scope using the value of the model attribute, e.g.,
    $scope.url = "http://example.com/fetch?model="+$attrs.model;
})

<div ng-controller="modelController" model="foobar">
  <a href="{{url}}">Click here</a>
</div>

Encore une fois, aucune idée si c'est une bonne idée, mais cela semble fonctionner et c'est une autre alternative.

Michael Tiller
la source
3
Comment passer un objet en utilisant cette approche? var obj = {a: 1, b: 2};
Neil
3
Il s'agit d'une solution très raisonnable au problème de la production d'une application hybride.
superluminaire
2
@Neil: vous devez stringifier votre objet json puis l'analyser dans le contrôleur. Pas la meilleure solution, mais cela peut fonctionner. La solution de Michael convient parfaitement aux paramètres de type chaîne ...
M'sieur Toph '
1
c'est en fait plus fiable que d'utiliser ng-init- si vous essayez de vous lier à une valeur d'étendue, il exécute déjà la fonction de contrôleur avant qu'il ne ng-initse produise - voir plnkr.co/edit/donCm6FRBSX9oENXh9WJ?p=preview
drzaus
2
Je ne parviens pas à réinventer la roue avec des directives, etc. Si vous avez un contrôleur que vous souhaitez utiliser dans plusieurs vues avec quelques paramètres d'initialisation différents, c'est la solution la plus simple et la plus fiable.
Eric H.
39

Cela fonctionne également.

Javascript:

var app = angular.module('angularApp', []);

app.controller('MainCtrl', function($scope, name, id) {
    $scope.id = id;
    $scope.name = name;
    // and more init
});

Html:

<!DOCTYPE html>
<html ng-app="angularApp">
  <head lang="en">
    <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.0.3/angular.min.js"></script>
    <script src="app.js"></script>
    <script>
       app.value("name", "James").value("id", "007");
    </script>
  </head>
  <body ng-controller="MainCtrl">
    <h1>I am  {{name}} {{id}}</h1>
  </body>
</html>
Parc Jonghee
la source
3
Il s'agit d'une bonne solution qui fonctionne avec le mécanisme d'injection du constructeur existant. Vous créez essentiellement deux services simples appelés «nom» et «id». L'injecteur se charge de les faire correspondre par leur nom lors de la construction. Voir: la section Recette de valeur de docs.angularjs.org/guide/providers
Todd
1
Agréable. Notez que cela fonctionne également avec les objets, pas seulement avec les types primitifs comme les chaînes.
jbustamovej
J'aime mieux cette solution. J'ai pu modulariser mes codes dupliqués via le passage de paramètres. À votre santé!
agentpx
Cela ressemble à la façon la plus idiomatique, mais je ne suis pas sûr que cela soit recommandé par l'équipe angulaire
VinGarcia
Cela établit-il essentiellement des paires clé / valeur globales? Est-ce que ceux-ci peuvent être étendus à des instances de contrôleur données afin qu'il ne soit récupéré que sur les contrôleurs enfants sous le contrôleur principal? Sinon, il semble que cela ne soit pas très différent de la simple définition d'une variable Javascript globale régulière au niveau de la fenêtre.
jpierson
16

La vue ne doit pas dicter la configuration

Dans Angular, le modèle ne doit jamais dicter la configuration, ce qui est intrinsèquement ce que les gens souhaitent lorsqu'ils souhaitent passer des arguments aux contrôleurs à partir d'un fichier de modèle. Cela devient une pente glissante. Si les paramètres de configuration sont codés en dur dans les modèles (par exemple, par une directive ou un attribut d'argument de contrôleur), vous ne pouvez plus réutiliser ce modèle pour autre chose que pour cette utilisation unique. Bientôt, vous voudrez réutiliser ce modèle, mais avec une configuration différente et maintenant, pour ce faire, vous devrez soit prétraiter les modèles pour injecter des variables avant de les passer en angulaire, soit utiliser des directives massives pour cracher géant. des blocs de HTML afin que vous réutilisiez tout le code HTML du contrôleur, à l'exception du div wrapper et de ses arguments. Pour les petits projets, ce n'est pas grave. Pour quelque chose de grand (ce que l'angulaire excelle), ça devient très vite laid.

L'alternative: les modules

Ce type de configuration est ce que les modules ont été conçus pour gérer. Dans de nombreux didacticiels angulaires, les gens ont un seul module pour l'ensemble de leur application, mais en réalité, le système est conçu et prend entièrement en charge de nombreux petits modules qui enveloppent de petits morceaux de l'application totale. Idéalement, les contrôleurs, modules, etc. devraient être déclarés dans des fichiers séparés et assemblés en morceaux spécifiques réutilisables. Lorsque votre application est conçue de cette façon, vous obtenez beaucoup de réutilisation en plus des arguments de contrôleur faciles.

L'exemple ci-dessous a 2 modules, réutilisant le même contrôleur, mais chacun avec ses propres paramètres de configuration. Les paramètres de configuration sont transmis via l'injection de dépendances à l'aide de module.value. Cela adhère à la méthode angulaire, car nous avons les éléments suivants: injection de dépendance du constructeur, code de contrôleur réutilisable, modèles de contrôleur réutilisables (le div du contrôleur pourrait facilement être inclus avec ng-include), système facilement testable par unité sans HTML, et enfin réutilisable modules comme véhicule pour assembler les pièces.

Voici un exemple:

<!-- index.html -->
<div id="module1">
    <div ng-controller="MyCtrl">
        <div>{{foo}}</div>
    </div>
</div>
<div id="module2">
    <div ng-controller="MyCtrl">
        <div>{{foo}}</div>
    </div>
</div>
<script>
    // part of this template, or a JS file designed to be used with this template
    angular.element(document).ready(function() {
        angular.bootstrap(document.getElementById("module1"), ["module1"]);
        angular.bootstrap(document.getElementById("module2"), ["module2"]);
    });
</script>

<!-- scripts which will likely in be in their seperate files -->
<script>
    // MyCtrl.js
    var MyCtrl = function($scope, foo) {
    $scope.foo = foo;
    }

    MyCtrl.$inject = ["$scope", "foo"];

    // Module1.js
    var module1 = angular.module('module1', []);
    module1.value("foo", "fooValue1");
    module1.controller("MyCtrl", MyCtrl);

    // Module2.js file
    var module2 = angular.module('module2', []);
    module2.value("foo", "fooValue2");
    module2.controller("MyCtrl", MyCtrl);
</script>

Voyez-le en action: jsFiddle .

Nucléon
la source
j'ai déjà voté, mais je tiens à exprimer mes remerciements pour votre contribution. cette réponse m'a mis sur une meilleure voie. stackoverflow est préférable lorsque les gens partagent les meilleures pratiques et pas seulement des extraits hacky. c'est génial: "le modèle ne doit jamais dicter la configuration, ce qui est intrinsèquement ce que les gens désirent lorsqu'ils veulent passer des arguments aux contrôleurs à partir d'un fichier modèle". merci d'avoir la vision laser au cœur du sujet.
pestophage
15

Comme @akonsu et Nigel Findlater suggèrent, vous pouvez lire l'URL où URL est index.html#/user/:idavec $routeParams.idet de l' utiliser à l' intérieur du contrôleur.

votre application:

var app = angular.module('myApp', [ 'ngResource' ]);

app.config(['$routeProvider', function($routeProvider) {
    $routeProvider.when('/:type/:id', {templateUrl: 'myView.html', controller: 'myCtrl'});
}]);

le service des ressources

app.factory('MyElements', ['$resource', function($resource) {
     return $resource('url/to/json/:type/:id', { type:'@type', id:'@id' });
}]);

le controlle

app.controller('MyCtrl', ['$scope', '$routeParams', 'MyElements', function($scope, $routeParams, MyElements) {
    MyElements.get({'type': $routeParams.type, "id": $routeParams.id }, function(elm) {
        $scope.elm = elm;
    })
}]);

puis, elmest accessible dans la vue en fonction du id.

François Romain
la source
8

Si ce ng-initn'est pas pour passer des objets $scope, vous pouvez toujours écrire votre propre directive. Voici donc ce que j'ai obtenu:

http://jsfiddle.net/goliney/89bLj/

Javasript:

var app = angular.module('myApp', []);
app.directive('initData', function($parse) {
    return function(scope, element, attrs) {
        //modify scope
        var model = $parse(attrs.initData);
        model(scope);
    };
});

function Ctrl1($scope) {
    //should be defined
    $scope.inputdata = {foo:"east", bar:"west"};
}

Html:

<div ng-controller="Ctrl1">
    <div init-data="inputdata.foo=123; inputdata.bar=321"></div>
</div>

Mais mon approche ne peut que modifier des objets, qui sont déjà définis au niveau du contrôleur.

Sergey Goliney
la source
Pour référence, cela fonctionne très bien, mais sur la version actuelle d'angular, c'est $ attrs (vs attrs)
Dinis Cruz
8

Il semble que la meilleure solution pour vous soit en fait une directive. Cela vous permet d'avoir toujours votre contrôleur, mais de lui définir des propriétés personnalisées.

Utilisez-le si vous avez besoin d'accéder aux variables dans la portée d'encapsulation:

angular.module('myModule').directive('user', function ($filter) {
  return {
    link: function (scope, element, attrs) {
      $scope.connection = $resource('api.com/user/' + attrs.userId);
    }
  };
});

<user user-id="{% id %}"></user>

Utilisez ceci si vous n'avez pas besoin d'accéder aux variables dans la portée d'encapsulation:

angular.module('myModule').directive('user', function ($filter) {
  return {
    scope: {
      userId: '@'
    },
    link: function (scope, element, attrs) {
      $scope.connection = $resource('api.com/user/' + scope.userId);
    }
  };
});

<user user-id="{% id %}"></user>
btesser
la source
7

J'ai trouvé des variables de passage de $ routeProvider utiles.

Par exemple, vous utilisez un contrôleur MyController pour plusieurs écrans, en passant à l'intérieur une variable très importante "mySuperConstant".

Utilisez cette structure simple:

Router:

$routeProvider
            .when('/this-page', {
                templateUrl: 'common.html',
                controller: MyController,
                mySuperConstant: "123"
            })
            .when('/that-page', {
                templateUrl: 'common.html',
                controller: MyController,
                mySuperConstant: "456"
            })
            .when('/another-page', {
                templateUrl: 'common.html',
                controller: MyController,
                mySuperConstant: "789"
            })

MyController:

    MyController: function ($scope, $route) {
        var mySuperConstant: $route.current.mySuperConstant;
        alert(mySuperConstant);

    }
Dmitri Algazin
la source
6

Vous pouvez le faire lors de la configuration des itinéraires, par exemple

 .when('/newitem/:itemType', {
            templateUrl: 'scripts/components/items/newEditItem.html',
            controller: 'NewEditItemController as vm',
            resolve: {
              isEditMode: function () {
                return true;
              }
            },
        })

Et plus tard, utilisez-le comme

(function () {
  'use strict';

  angular
    .module('myApp')
    .controller('NewEditItemController', NewEditItemController);

  NewEditItemController.$inject = ['$http','isEditMode',$routeParams,];

  function NewEditItemController($http, isEditMode, $routeParams) {
    /* jshint validthis:true */

    var vm = this;
    vm.isEditMode = isEditMode;
    vm.itemType = $routeParams.itemType;
  }
})();

Voici donc quand nous avons configuré l'itinéraire que nous avons envoyé: itemType et récupérez-le plus tard à partir de $ routeParams.

ssaini
la source
3

Cette question est ancienne mais j'ai eu du mal pendant longtemps à essayer d'obtenir une réponse à ce problème qui répondrait à mes besoins et ne l'a pas facilement trouvée. Je crois que ma solution suivante est bien meilleure que celle actuellement acceptée, peut-être parce que angular a ajouté des fonctionnalités depuis que cette question a été posée à l'origine.

Réponse courte, l'utilisation de la méthode Module.value vous permet de transmettre des données à un constructeur de contrôleur.

Voir mon plongeur ici

Je crée un objet modèle, puis je l'associe au contrôleur du module, en le référençant avec le nom «modèle»

HTML / JS

  <html>
  <head>
    <script>
      var model = {"id": 1, "name":"foo"};

      $(document).ready(function(){
        var module = angular.module('myApp', []);
        module.value('model', model);
        module.controller('MyController', ['model', MyController]);
        angular.bootstrap(document, ['myApp']);
      });

      function confirmModelEdited() {
        alert("model name: " + model.name + "\nmodel id: " + model.id);
      }
    </script>

  </head>
  <body >
      <div ng-controller="MyController as controller">
        id: {{controller.model.id}} <br>
        name: <input ng-model="controller.model.name"/>{{controller.model.name}}
        <br><button ng-click="controller.incrementId()">increment ID</button>
        <br><button onclick="confirmModelEdited()">confirm model was edited</button>
    </div>
  </body>

</html>

Le constructeur de mon contrôleur accepte alors un paramètre avec le même identifiant «modèle» auquel il peut alors accéder.

Manette

function MyController (model) {
  this.model = model;
}

MyController.prototype.incrementId = function() {
  this.model.id = this.model.id + 1;
}

Remarques:

J'utilise l'initialisation manuelle du bootstrap , ce qui me permet d'initialiser mon modèle avant de l'envoyer en angulaire. Cela fonctionne beaucoup mieux avec le code existant, car vous pouvez attendre de configurer vos données pertinentes et de compiler le sous-ensemble angulaire de votre application à la demande lorsque vous le souhaitez.

Dans le plunker, j'ai ajouté un bouton pour alerter les valeurs de l'objet modèle initialement défini en javascript et passé à angular, juste pour confirmer que angular fait vraiment référence à l'objet modèle, plutôt que de le copier et de travailler avec une copie.

Sur cette ligne:

module.controller('MyController', ['model', MyController]);

Je passe l'objet MyController dans la fonction Module.controller, plutôt que de le déclarer en tant que fonction inline. Je pense que cela nous permet de définir beaucoup plus clairement notre objet contrôleur, mais la documentation angulaire a tendance à le faire en ligne, donc j'ai pensé qu'elle méritait des éclaircissements.

J'utilise la syntaxe "controller as" et j'assigne des valeurs à la propriété "this" de MyController, plutôt que d'utiliser la variable "$ scope". Je pense que cela fonctionnerait aussi bien en utilisant $ scope, l'affectation du contrôleur ressemblerait alors à ceci:

module.controller('MyController', ['$scope', 'model', MyController]);

et le constructeur du contrôleur aurait une signature comme celle-ci:

function MyController ($scope, model) {

Si pour une raison quelconque vous vouliez, vous pouvez également attacher ce modèle en tant que valeur d'un deuxième module, que vous attachez ensuite en tant que dépendance à votre module principal.

Je pense que sa solution est bien meilleure que celle actuellement acceptée car

  1. Le modèle transmis au contrôleur est en fait un objet javascript, pas une chaîne qui est évaluée. Il s'agit d'une véritable référence à l'objet et ses modifications affectent les autres références à cet objet modèle.
  2. Angular dit que l'utilisation de ng-init dans la réponse acceptée est une mauvaise utilisation, ce que cette solution ne fait pas.

La façon dont Angular semble fonctionner dans la plupart des autres exemples que j'ai vus a le contrôleur définissant les données du modèle, ce qui n'a jamais eu de sens pour moi, il n'y a pas de séparation entre le modèle et le contrôleur, cela ne semble pas vraiment MVC pour moi. Cette solution vous permet d'avoir vraiment un objet modèle complètement séparé que vous passez dans le contrôleur. Notez également que si vous utilisez la directive ng-include, vous pouvez mettre tout votre code HTML angulaire dans un fichier séparé, séparant complètement votre vue de modèle et votre contrôleur en pièces modulaires distinctes.

O. Winter
la source
2

Si vous utilisez angular-ui-router, alors c'est la bonne solution: https://github.com/angular-ui/ui-router/wiki#resolve

Fondamentalement, vous déclarez un ensemble de dépendances à «résoudre» avant que le contrôleur ne soit instancié. Vous pouvez déclarer des dépendances pour chacun de vos "états". Ces dépendances sont ensuite passées dans le "constructeur" du contrôleur.

Juan
la source
1

Une façon de le faire serait d'avoir un service distinct qui peut être utilisé comme un «navire» pour les arguments où ils sont membres de données publiques.

Marcin Wyszynski
la source
Meilleure réponse, OMI. J'utilise actuellement le stockage par navigateur dans certains cas pour les utilisateurs qui osent toucher F5, donc cet état est maintenu.
Loir
1

Je n'ai pas vraiment aimé les solutions ici pour mon cas d'utilisation particulier, alors j'ai pensé que je publierais ce que j'ai fait parce que je ne l'ai pas vu ici.

Je voulais simplement utiliser un contrôleur plus comme une directive, dans une boucle ng-repeat:

<div ng-repeat="objParameter in [{id:'a'},{id:'b'},{id:'c'}]">
  <div ng-controller="DirectiveLikeController as ctrl"></div>
</div>

Maintenant, afin d'accéder à la objParametercréation dans chaque DirectiveLikeController (ou pour obtenir l'objParameter à jour à TOUT MOMENT), tout ce que je dois faire est d'injecter $ scope et d'appeler $scope.$eval('objParameter'):

var app = angular.module('myapp', []);
app.controller('DirectiveLikeController',['$scope'], function($scope) {
   //print 'a' for the 1st instance, 'b' for the 2nd instance, and 'c' for the 3rd.
   console.log($scope.$eval('objParameter').id); 
});

Le seul véritable inconvénient que je vois est qu'il nécessite que le contrôleur parent sache que le paramètre est nommé objParameter.

JohnTD
la source
0

Non ce n'est pas possible. Je pense que vous pouvez utiliser ng-init comme hack http://docs.angularjs.org/api/ng.directive:ngInit .

SunnyShah
la source
4
Je vous prie de différer, mais vous pouvez accomplir cela en utilisant ng-init et en utilisant une fonction d'init.
Jigar Patel
un mot d'avertissement - si vous essayez de vous lier à une valeur de portée, ou si vous faites vraiment quelque chose qui s'attend à ce que la valeur soit présente dans la fonction de contrôleur, il a déjà exécuté la fonction de contrôleur avant de ng-initse produire
drzaus
Oui c'est possible. À tout le moins, vous utiliseriez des paramètres de données ou autre chose. Mais c'est définitivement possible.
Juan
0

Voici une solution (basée sur la suggestion de Marcin Wyszynski) qui fonctionne là où vous voulez passer une valeur dans votre contrôleur mais vous ne déclarez pas explicitement le contrôleur dans votre html (ce que ng-init semble exiger) - si, par exemple, vous rendez vos modèles avec ng-view et déclarez chaque contrôleur pour l'itinéraire correspondant via routeProvider.

JS

messageboard.directive('currentuser', ['CurrentUser', function(CurrentUser) {
  return function(scope, element, attrs) {
    CurrentUser.name = attrs.name;
  };
}]);

html

<div ng-app="app">
  <div class="view-container">
    <div ng-view currentuser name="testusername" class="view-frame animate-view"></div>
  </div>
</div>

Dans cette solution, CurrentUser est un service qui peut être injecté dans n'importe quel contrôleur, la propriété .name étant alors disponible.

Deux notes:

  • un problème que j'ai rencontré est que .name est défini après le chargement du contrôleur, donc comme solution de contournement j'ai un court délai avant de rendre le nom d'utilisateur sur la portée du contrôleur. Existe-t-il une manière élégante d'attendre que .name ait été défini sur le service?

  • cela semble être un moyen très facile d'obtenir un utilisateur actuel dans votre application Angular avec toute l'authentification conservée en dehors d'Angular. Vous pouvez avoir un before_filter pour empêcher les utilisateurs non connectés d'accéder au code HTML où votre application Angular est démarrée, et dans ce code HTML, vous pouvez simplement interpoler le nom de l'utilisateur connecté et même son ID si vous souhaitez interagir avec les détails de l'utilisateur. via les requêtes http de votre application Angular. Vous pouvez autoriser les utilisateurs non connectés à utiliser l'application angulaire avec un «utilisateur invité» par défaut. Tout conseil sur les raisons pour lesquelles cette approche serait mauvaise serait le bienvenu - il semble trop facile d'être raisonnable!)

Ollie HM
la source
0

Il s'agit d'une extension de l' excellente réponse de @Michael Tiller . Sa réponse fonctionne pour initialiser des variables de la vue en injectant l' $attrsobjet dans le contrôleur. Le problème se produit si le même contrôleur est appelé $routeProviderlorsque vous naviguez par routage. Ensuite, vous obtenez une erreur d'injecteur Unknown provider : $attrsProvidercar elle $attrsn'est disponible pour l'injection que lorsque la vue est compilée. La solution consiste à transmettre la variable (foo) $routeParamslors de l'initialisation du contrôleur à partir de la route et $attrslors de l'initialisation du contrôleur à partir de la vue. Voici ma solution.

De la route

$routeProvider.
        when('/mypage/:foo', {
            templateUrl: 'templates/mypage.html',
            controller: 'MyPageController',
            caseInsensitiveMatch: true,
            resolve: {
                $attrs: function () {
                    return {};
                }
            }
        });

Cela gère une URL telle que '/mypage/bar'. Comme vous pouvez le voir, foo est passé par url param et nous fournissons $injectorun objet vide pour $attrsaucune erreur d'injecteur.

De la vue

<div ng-controller="MyPageController" data-foo="bar">

</div>

Maintenant, le contrôleur

var app = angular.module('myapp', []);
app.controller('MyPageController',['$scope', '$attrs', '$routeParams'], function($scope, $attrs, $routeParams) {
   //now you can initialize foo. If $attrs contains foo, it's been initialized from view
   //else find it from $routeParams
   var foo = $attrs.foo? $attrs.foo : $routeParams.foo;
   console.log(foo); //prints 'bar'

});
Moses Machua
la source