Können Sie bei der Erstellung Parameter an einen AngularJS-Controller übergeben?

278

Ich habe einen Controller, der für die Kommunikation mit einer API verantwortlich ist, um die Eigenschaften eines Benutzers, seines Namens, seiner E-Mail-Adresse usw. zu aktualisieren. Jeder Benutzer hat eine, 'id'die vom Server übergeben wird, wenn die Profilseite angezeigt wird.

Ich möchte diesen Wert an den AngularJS-Controller übergeben, damit dieser weiß, was der API-Einstiegspunkt für den aktuellen Benutzer ist. Ich habe versucht, den Wert weiterzugeben ng-controller. Zum Beispiel:

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

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

und im HTML

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

Hier wird {% id %}die vom Server gesendete ID gedruckt. aber ich bekomme fehler.

Was ist der richtige Weg, um einen Wert bei seiner Erstellung an einen Controller zu übergeben?

Nickponline
quelle
6
Wenn Sie die ID als Teil der URL hatten, konnten Sie einfach die URL lesen
Akonsu
Ich hatte ein sehr ähnliches Problem und habe es gelöst, wie ich in meiner Antwort angegeben habe. Manchmal übersehen wir bei Verwendung der Bibliotheken das einfache grundlegende Konzept des JavaScript-Funktionsaufrufs.
Jigar Patel
@nickponline Nach 21+ denkst du immer noch, dass es nicht möglich ist?
Om471987

Antworten:

362

Anmerkungen:

Diese Antwort ist alt. Dies ist nur ein Proof of Concept, wie das gewünschte Ergebnis erzielt werden kann. Es ist jedoch möglicherweise nicht die beste Lösung gemäß einigen Kommentaren unten. Ich habe keine Dokumentation, um den folgenden Ansatz zu unterstützen oder abzulehnen. Weitere Informationen zu diesem Thema finden Sie in den Kommentaren unten.

Ursprüngliche Antwort:

Ich antwortete mit Ja, Sie können dies absolut mit ng-initeiner einfachen Init-Funktion tun .

Hier ist das Beispiel auf 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
quelle
5
Vielen Dank dafür - ersparte mir viel Kopfkratzen und es funktionierte perfekt für meine Situation. Ich musste meinen Controller mit einer Objekt-ID initialisieren, und das war genau richtig.
Masonoise
26
Aus Dokumenten :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
Die Antwort macht deutlich, dass das Dokument gegen diesen Ansatz empfiehlt, aber kann mich jemand darauf hinweisen, wo die Dokumente die offizielle Lösung bieten?
Michael Pell
53
Nun, ich denke, die Dokumente sind schlecht darin, nur gegen diesen Ansatz zu empfehlen, ohne Gründe dafür anzugeben. Ich denke, das ist ein brillanter Ansatz. Wenn die Framework-Autoren nicht möchten, dass das Framework auf eine für sie "falsche" Weise verwendet wird, sollten sie es nicht ermöglichen, auf diese "falsche" Weise verwendet zu werden ... und Hinweise zur " richtiger Weg!
Shawn de Wet
2
Ein Wort der Warnung: Wenn Sie versuchen, sich an einen Bereichswert zu binden oder wirklich etwas tun, das erwartet, dass der Wert in der Controller-Funktion vorhanden ist, wird die Controller-Funktion bereits ausgeführt, bevor sie ng-initauftritt - siehe plnkr.co/edit / donCm6FRBSX9oENXh9WJ? p = Vorschau
drzaus
143

Ich bin sehr spät dran und habe keine Ahnung, ob dies eine gute Idee ist, aber Sie können das $attrsInjizierbare in die Controller-Funktion aufnehmen, damit der Controller mit "Argumenten" initialisiert werden kann, die für ein Element bereitgestellt werden, z

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>

Wieder keine Ahnung, ob dies eine gute Idee ist, aber es scheint zu funktionieren und ist eine andere Alternative.

Michael Tiller
quelle
3
Wie würde ich mit diesem Ansatz ein Objekt übergeben? var obj = {a: 1, b: 2};
Neil
3
Dies ist eine sehr vernünftige Lösung für das Problem der Erstellung einer Hybrid-App.
Superluminary
2
@Neil: Sie müssen Ihr JSON-Objekt stringifizieren und dann im Controller analysieren. Nicht die schönere Lösung, aber es kann funktionieren. Die Michael-Lösung ist gut für
stringartige
1
Dies ist tatsächlich zuverlässiger als die Verwendung ng-init- wenn Sie versuchen, an einen Bereichswert zu binden, wird die Controller-Funktion bereits ausgeführt, bevor sie ng-initauftritt - siehe plnkr.co/edit/donCm6FRBSX9oENXh9WJ?p=preview
drzaus
2
Ich kann das Rad nicht mit Anweisungen usw. neu erfinden. Wenn Sie einen Controller haben, den Sie in mehreren Ansichten mit einigen unterschiedlichen Initialisierungsparametern verwenden möchten, ist dies die einfachste und zuverlässigste Lösung.
Eric H.
39

Das funktioniert auch.

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>
Jonghee Park
quelle
3
Dies ist eine gute Lösung, die mit dem vorhandenen Konstruktorinjektionsmechanismus funktioniert. Sie erstellen im Wesentlichen zwei einfache Dienste mit den Namen "Name" und "ID". Der Injektor sorgt dafür, dass sie während der Konstruktion namentlich übereinstimmen. Siehe: den Abschnitt Wertrezept
Todd
1
Nett. Beachten Sie, dass dies auch mit Objekten funktioniert, nicht nur mit primitiven Typen wie Zeichenfolgen.
jbustamovej
Diese Lösung gefällt mir besser. Ich konnte meine duplizierten Codes durch Parameterübergabe modularisieren. Prost!
Agentpx
Dies sieht nach dem idiomatischsten Weg aus, aber ich bin nicht sicher, ob es vom eckigen Team empfohlen wird
VinGarcia
Richtet dies im Wesentlichen globale Schlüssel / Wert-Paare ein? Können diese auf bestimmte Controller-Instanzen beschränkt werden, sodass sie nur auf untergeordneten Controllern unter der Hauptinstanz erfasst werden? Wenn nicht, scheint dies nicht viel anders zu sein, als nur eine reguläre globale Javascript-Variable auf Fensterebene festzulegen.
Jpierson
16

Die Ansicht sollte keine Konfiguration vorgeben

In Angular sollte die Vorlage niemals die Konfiguration vorschreiben. Dies ist von Natur aus das, was Benutzer wünschen, wenn sie Argumente aus einer Vorlagendatei an Controller übergeben möchten. Dies wird zu einem rutschigen Hang. Wenn die Konfigurationseinstellungen in Vorlagen fest codiert sind (z. B. durch eine Direktive oder ein Controller-Argumentattribut), können Sie diese Vorlage nur noch für die einmalige Verwendung wiederverwenden. Bald möchten Sie diese Vorlage wiederverwenden, aber mit einer anderen Konfiguration. Um dies zu tun, werden Sie entweder die Vorlagen vorverarbeiten, um Variablen einzufügen, bevor sie an eckig übergeben werden, oder massive Anweisungen verwenden, um Riesen auszuspucken HTML-Blöcke, sodass Sie den gesamten Controller-HTML-Code mit Ausnahme des Wrapper-Div und seiner Argumente wiederverwenden können. Für kleine Projekte ist es keine große Sache. Für etwas Großes (was eckig auszeichnet) wird es schnell hässlich.

Die Alternative: Module

Für diese Art der Konfiguration wurden Module entwickelt. In vielen eckigen Tutorials haben Benutzer ein einziges Modul für ihre gesamte Anwendung, aber tatsächlich ist das System so konzipiert und unterstützt viele kleine Module, die jeweils kleine Teile der gesamten Anwendung einschließen. Im Idealfall werden Controller, Module usw. in separaten Dateien deklariert und in bestimmten wiederverwendbaren Abschnitten zusammengefügt. Wenn Ihre Anwendung auf diese Weise entworfen wird, werden Sie neben einfachen Controller-Argumenten häufig wiederverwendet.

Das folgende Beispiel enthält zwei Module, die denselben Controller wiederverwenden, jedoch jeweils ihre eigenen Konfigurationseinstellungen haben. Diese Konfigurationseinstellungen werden über die Abhängigkeitsinjektion mit übergeben module.value. Dies entspricht dem Winkel, da wir Folgendes haben: Konstruktorabhängigkeitsinjektion, wiederverwendbarer Controller-Code, wiederverwendbare Controller-Vorlagen (das Controller-Div könnte leicht in ng-include enthalten sein), leicht Unit-testbares System ohne HTML und zuletzt wiederverwendbar Module als Vehikel zum Zusammennähen der Teile.

Hier ist ein Beispiel:

<!-- 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>

Sehen Sie es in Aktion: jsFiddle .

Nucleon
quelle
Ich habe bereits gestimmt, aber ich möchte mich für Ihren Beitrag bedanken. Diese Antwort hat mich auf einen besseren Weg gebracht. Stackoverflow ist am besten, wenn Benutzer Best Practices und nicht nur hackige Snippets austauschen. Das ist brillant: "Die Vorlage sollte niemals die Konfiguration vorschreiben, was von Natur aus gewünscht wird, wenn Benutzer Argumente aus einer Vorlagendatei an Controller übergeben möchten." Vielen Dank, dass Sie Laser Vision in den Mittelpunkt der Angelegenheit gestellt haben.
Pestophagous
15

Wie @akonsu und Nigel Findlater vorschlagen, können Sie die URL lesen , wo url ist index.html#/user/:idmit $routeParams.idund verwenden Sie es in der Steuerung.

Ihre App:

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

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

der Ressourcendienst

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

Der Controller

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

dann elmist in der Ansicht abhängig von der zugänglich id.

François Romain
quelle
8

Wenn Sie ng-initkeine Objekte übergeben möchten $scope, können Sie jederzeit eine eigene Direktive schreiben. Also hier ist was ich habe:

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>

Mein Ansatz kann jedoch nur Objekte ändern, die bereits im Controller definiert sind.

Sergey Goliney
quelle
Als Referenz funktioniert dies großartig, aber in der aktuellen Version von Angular ist es $ attrs (vs attrs)
Dinis Cruz
8

Es sieht so aus, als wäre die beste Lösung für Sie eine Richtlinie. Auf diese Weise können Sie Ihren Controller weiterhin haben, aber benutzerdefinierte Eigenschaften dafür definieren.

Verwenden Sie diese Option, wenn Sie Zugriff auf Variablen im Umbruchbereich benötigen:

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>

Verwenden Sie diese Option, wenn Sie keinen Zugriff auf Variablen im Umbruchbereich benötigen:

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
quelle
7

Ich fand es nützlich, Variablen von $ routeProvider zu übergeben.

Sie verwenden beispielsweise einen Controller MyController für mehrere Bildschirme und übergeben eine sehr wichtige Variable "mySuperConstant".

Verwenden Sie diese einfache Struktur:

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
quelle
6

Sie können dies tun, wenn Sie die Routen für z

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

Und später als verwenden

(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;
  }
})();

Wenn wir also die Route einrichten, die wir gesendet haben: itemType und rufen Sie sie später von $ routeParams ab.

ssaini
quelle
3

Diese Frage ist alt, aber ich hatte lange Mühe, eine Antwort auf dieses Problem zu finden, die für meine Bedürfnisse geeignet war, und fand sie nicht leicht. Ich glaube, meine folgende Lösung ist viel besser als die derzeit akzeptierte, vielleicht weil Angular die Funktionalität hinzugefügt hat, seit diese Frage ursprünglich gestellt wurde.

Mit der kurzen Antwort können Sie mithilfe der Module.value-Methode Daten an einen Controller-Konstruktor übergeben.

Sehen Sie meinen Plunker hier

Ich erstelle ein Modellobjekt, ordne es dann dem Controller des Moduls zu und verweise es mit dem Namen 'model'.

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>

Der Konstruktor in meinem Controller akzeptiert dann einen Parameter mit demselben Bezeichner 'model', auf den er dann zugreifen kann.

Regler

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

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

Anmerkungen:

Ich verwende die manuelle Initialisierung des Bootstrapings , mit der ich mein Modell initialisieren kann, bevor ich es an Angular sende. Dies funktioniert viel besser mit vorhandenem Code, da Sie warten können, bis Sie Ihre relevanten Daten eingerichtet haben, und die eckige Teilmenge Ihrer App nur bei Bedarf kompilieren können, wenn Sie möchten.

Im Plunker habe ich eine Schaltfläche hinzugefügt, um die Werte des Modellobjekts zu warnen, das ursprünglich in Javascript definiert und an Angular übergeben wurde, um zu bestätigen, dass Angular wirklich auf das Modellobjekt verweist, anstatt es zu kopieren und mit einer Kopie zu arbeiten.

In dieser Zeile:

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

Ich übergebe das MyController-Objekt an die Module.controller-Funktion, anstatt es als Inline-Funktion zu deklarieren. Ich denke, dies ermöglicht es uns, unser Controller-Objekt viel klarer zu definieren, aber die Angular-Dokumentation tendiert dazu, dies inline zu tun, sodass ich dachte, dass es einer Klärung bedarf.

Ich verwende die Syntax "controller as" und weise der Eigenschaft "this" von MyController Werte zu, anstatt die Variable "$ scope" zu verwenden. Ich glaube, dass dies mit $ scope genauso gut funktionieren würde. Die Controller-Zuweisung würde dann ungefähr so ​​aussehen:

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

und der Controller-Konstruktor hätte eine Signatur wie diese:

function MyController ($scope, model) {

Wenn Sie aus irgendeinem Grund möchten, können Sie dieses Modell auch als Wert eines zweiten Moduls anhängen, das Sie dann als Abhängigkeit zu Ihrem primären Modul anhängen.

Ich glaube, seine Lösung ist viel besser als die derzeit akzeptierte, weil

  1. Das an den Controller übergebene Modell ist eigentlich ein Javascript-Objekt, keine Zeichenfolge, die ausgewertet wird. Es ist eine echte Referenz auf das Objekt, und Änderungen daran wirken sich auf andere Referenzen auf dieses Modellobjekt aus.
  2. Angular sagt, dass die Verwendung von ng-init durch die akzeptierte Antwort ein Missbrauch ist, den diese Lösung nicht tut.

Die Art und Weise, wie Angular in den meisten anderen Beispielen zu funktionieren scheint, hat dazu geführt, dass der Controller die Daten des Modells definiert, was für mich nie sinnvoll war. Es gibt keine Trennung zwischen dem Modell und dem Controller, die nicht wirklich so aussieht MVC für mich. Mit dieser Lösung können Sie wirklich ein völlig separates Modellobjekt haben, das Sie an die Steuerung übergeben. Wenn Sie die Direktive ng-include verwenden, können Sie auch alle Ihre eckigen HTML-Dateien in einer separaten Datei ablegen und so Ihre Modellansicht und Ihren Controller vollständig in separate modulare Teile aufteilen.

O. Winter
quelle
2

Wenn Sie einen Angular-UI-Router verwenden, ist dies die richtige Lösung: https://github.com/angular-ui/ui-router/wiki#resolve

Grundsätzlich deklarieren Sie eine Reihe von Abhängigkeiten, die "aufgelöst" werden sollen, bevor der Controller instanziiert wird. Sie können Abhängigkeiten für jeden Ihrer "Zustände" deklarieren. Diese Abhängigkeiten werden dann im "Konstruktor" des Controllers übergeben.

Juan
quelle
1

Eine Möglichkeit, dies zu tun, wäre ein separater Dienst, der als "Schiff" für die Argumente verwendet werden kann, bei denen es sich um öffentliche Datenmitglieder handelt.

Marcin Wyszynski
quelle
Beste Antwort, IMO. In einigen Fällen verwende ich derzeit auch den Browserspeicher für Benutzer, die es wagen, F5 zu drücken, sodass dieser Status beibehalten wird.
Siebenschläfer
1

Ich mochte keine der Lösungen hier für meinen speziellen Anwendungsfall wirklich, also dachte ich, ich würde posten, was ich getan habe, weil ich es hier nicht gesehen habe.

Ich wollte einfach einen Controller eher wie eine Direktive innerhalb einer ng-repeat-Schleife verwenden:

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

Um nun auf die objParameterOn-Erstellung in jedem DirectiveLikeController zuzugreifen (oder um jederzeit den aktuellen objParameter abzurufen), muss ich nur $ scope injizieren und Folgendes aufrufen $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); 
});

Der einzige wirkliche Nachteil, den ich sehe, ist, dass der übergeordnete Controller wissen muss, dass der Parameter benannt ist objParameter.

JohnTD
quelle
0

Nein, das ist nicht möglich. Ich denke, Sie können ng-init als Hack verwenden http://docs.angularjs.org/api/ng.directive:ngInit .

SunnyShah
quelle
4
Ich bin anderer Meinung, aber Sie können dies mit ng-init und einer init-Funktion erreichen.
Jigar Patel
Ein Wort der Warnung: Wenn Sie versuchen, sich an einen Bereichswert zu binden oder wirklich etwas tun, das erwartet, dass der Wert in der Controller-Funktion vorhanden ist, wird die Controller-Funktion bereits ausgeführt, bevor sie ng-initauftritt - siehe plnkr.co/edit / donCm6FRBSX9oENXh9WJ? p = Vorschau
drzaus
Ja, es ist möglich. Zumindest würden Sie Datenparameter oder was auch immer verwenden. Aber es ist definitiv möglich.
Juan
0

Hier ist eine Lösung (basierend auf dem Vorschlag von Marcin Wyszynski), die funktioniert, wenn Sie einen Wert an Ihren Controller übergeben möchten, den Controller jedoch nicht explizit in Ihrem HTML-Code deklarieren (was ng-init anscheinend erfordert) - wenn zum Beispiel Sie rendern Ihre Vorlagen mit ng-view und deklarieren jeden Controller für die entsprechende Route über 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>

In dieser Lösung ist CurrentUser ein Dienst, der in jeden Controller eingefügt werden kann, wobei die Eigenschaft .name dann verfügbar ist.

Zwei Anmerkungen:

  • Ein Problem, auf das ich gestoßen bin, ist, dass .name nach dem Laden des Controllers festgelegt wird. Als Problemumgehung habe ich eine kurze Zeitüberschreitung, bevor ich den Benutzernamen im Bereich des Controllers rendere. Gibt es eine gute Möglichkeit zu warten, bis .name für den Dienst festgelegt wurde?

  • Dies scheint eine sehr einfache Möglichkeit zu sein, einen aktuellen Benutzer in Ihre Angular-App zu integrieren, wobei die gesamte Authentifizierung außerhalb von Angular erfolgt. Sie könnten einen before_filter haben, um zu verhindern, dass nicht angemeldete Benutzer zu dem HTML-Code gelangen, in dem Ihre Angular-App gebootet ist, und in diesem HTML-Code können Sie einfach den Namen des angemeldeten Benutzers und sogar dessen ID interpolieren, wenn Sie mit den Benutzerdetails interagieren möchten über http-Anfragen von Ihrer Angular-App. Sie können nicht angemeldeten Benutzern erlauben, die Angular App mit einem Standard-Gastbenutzer zu verwenden. Jeder Rat, warum dieser Ansatz schlecht wäre, wäre willkommen - es fühlt sich zu einfach an, vernünftig zu sein!)

Ollie HM
quelle
0

Dies ist eine Erweiterung der hervorragenden Antwort von @Michael Tiller . Seine Antwort dient zum Initialisieren von Variablen aus der Ansicht, indem das $attrsObjekt in die Steuerung injiziert wird. Das Problem tritt auf, wenn derselbe Controller aufgerufen wird, $routeProviderwenn Sie per Routing navigieren. Dann erhalten Sie einen Injektorfehler, Unknown provider : $attrsProviderda er $attrsnur für die Injektion verfügbar ist, wenn die Ansicht kompiliert wird. Die Lösung besteht darin, die Variable (foo) $routeParamsbeim Initialisieren des Controllers von der Route und $attrsbeim Initialisieren des Controllers von der Ansicht durch zu übergeben. Hier ist meine Lösung.

Von der Route

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

Dies behandelt eine URL wie '/mypage/bar'. Wie Sie sehen können, wird foo von url param übergeben und wir stellen dem $injectorein leeres Objekt zur Verfügung, $attrsdamit keine Injektorfehler auftreten.

Aus der Ansicht

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

</div>

Nun die Steuerung

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
quelle