2016-07-26 26 views
36

Ich schreibe eine einfache Winkelkomponente. Ich übergebe einen Parameter als Bindung und zeige seinen Wert auf dem Bildschirm an. Alles funktioniert gut: Ich kann sehen, dass der Parameter auf dem Bildschirm angezeigt wird.Eckige Komponenten: Bindungen sind im Controller nicht definiert

Komponente:

var app = angular.module("test", []); 
app.component("test", { 
    bindings: { 
    "contactId": "<" 
    }, 
    controllerAs: "model", 
    controller:() => { 
    //output: 'contact id from controller: undefined' 
    console.log(`contact id from controller: ${this.contactId}`); 
    }, 
    template: "<div>Contact id from view: {{model.contactId}}</div>" 
}); 

Html:

<test contact-id="8"></test> 

aber wenn ich versuche, die Bindung für den Zugriff von innerhalb des Controllers (siehe console.log) ist der Bindungswert undefined. Ich verstehe nicht, wie es in der Ansicht verfügbar sein kann, aber nicht in der Steuerung.

Was mache ich falsch?

Hier ist eine plnkr zur Veranschaulichung des Problems.

+1

Ich bin etwas fehlt einfach. Warum ist "contactId" in Anführungszeichen definiert? – Winnemucca

Antwort

33

Wenn Winkelkomponenten verwendet werden, gibt es einen Punkt, an dem der Controller nicht über die interne Verbindung verdrahtet wurde. Wenn Sie dies im Konstruktor Ihres Controllers versuchen, sind Sie nicht zu den Bindungen verknüpft worden. Die Komponenten-API zeigt einige Lebenszyklus-Hooks, die Sie definieren können und die zu bestimmten Zeiten ausgelöst werden. Sie suchen nach dem $onInit Haken.

$ onInit() - auf jedem Controller aufgerufen, nachdem alle Regler auf ein Element gebaut worden und hatten ihre Bindungen initialisiert (und vor den Pre & Post die Verknüpfung von Funktionen für die Richtlinien über dieses Element). Dies ist ein guter Platz, um Initialisierungscode für Ihren Controller zu setzen.

pro docs - https://docs.angularjs.org/guide/component

+1

Ich denke, Sie haben Recht, sollte $ OnInit verwendet werden. Das funktioniert bei mir: ' var vm = this; vm. $ OnInit = function() { console.log ('geladen in init'); console.log ('vm', vm.YOUR_BINDING); console.log ('def ja?', Angular.isDefined (vm.YOUR_BINDINGj)); }; ' – escapedcat

+2

In einigen Szenarien können Ihre Bindungen später aktualisiert werden und ihre Werte sind nicht bereit, wenn der Haken' $ onInit' Aufruf ist. In solchen Fällen sollten Sie '$ onChanges' verwenden und die ersten Änderungen überspringen. Arbeitsbeispiel: https://jsfiddle.net/auxcoder/4hq5gaq0/ – aUXcoder

+1

@ aUXcoder Das war mein Problem. Ich habe versucht, die Komponente zu erstellen, bevor die Daten zur Bindung an die Komponente bereit waren. Setzen Sie eine 'ng-if'-Anweisung, um sicherzustellen, dass ich die Daten hatte, bevor die Komponente initialisiert wurde (zB ' ') behob das Problem. – Xchai

4

Das Schlüsselwort diese nicht mit Pfeil Funktion zu Werke scheint, funktioniert dies mit

controller: function() { 
    alert('contact id from controller: ' + this.contactId); 
} 

Wenn Pfeil-Funktion, diese, scheint beziehen sich auf das Fensterobjekt, weil

Ein Pfeil Funktion erstellen nicht, dass es diesen Kontext besitzen, sondern es fängt die diesen Wert des einschließenden Kontextes

6

Der Wert für contactId auf die $scope in Ihrem Controller verfügbar:

var app = angular.module("test", []); 
app.component("test", { 
    bindings: { 
    "contactId": "<" 
    }, 
    controllerAs: "model", 
    controller: ($scope) => { 
    var model = $scope.model; 
    alert(`contact id from controller: ${model.contactId}`); 
    }, 
    template: "<div>Contact id from view: {{model.contactId}}</div>" 
}); 

Verbindung zu einer anderen Version Ihres Plunker here.

+1

Warum können wir dieses Schlüsselwort nicht verwenden, wenn wir den Pfeilfunktionsstil verwenden? –

+0

Sie können 'this' mit dem Pfeilfunktionsstil verwenden, aber ich denke in dieser Situation ist 'this.contactId' noch nicht verfügbar, aus Gründen, die @jusopi erwähnt hat. Wenn Sie über API-Methoden verfügen, z. B. "someController.prototype.someMethod", sollte "this" das haben, was Sie erwarten. Wie @jusopi erwähnt hat, wird die Ausführungsreihenfolge '' '' im Konstruktor (Nicht-Prototyp) wie erwartet nicht füllen. – JohnnyCoder

+1

Ich habe versucht mit einer Zeitüberschreitung und es funktioniert nicht. Wie ich oben sagte, erstellt eine Pfeilfunktion diesen Kontext nicht, sondern erfasst den Wert des umgebenden Kontexts. Bei der Pfeilfunktion bezieht sich dies auf das Fensterobjekt, nicht auf den Controller. –

13

Stellen Sie sicher, dass Sie Bindestriche für Bindungen in HTML und CamelCase für Bindungen in Javascript verwenden.

app.component("test", { 
    bindings: { 
    "myContactId": "<" 
    } 
} 

<test my-contact-id="8"></test> 

Das vergesse ich immer zu tun.

1

Sein vielleicht ist es nicht die beste Praxis, aber Sie haben einen easyer Zugriff auf diese Werte:

$scope.$ctrl.contactId 

Sie können in der Eigenschaft $ ctrl innerhalb des $ scope alle Bindungen erhalten.

Ich hoffe, seine Hilfe

3

ich werde einige Änderungen vorschlagen, die Sie wirklich diese ungewöhnlichen Fehler vermeiden müssen.

app.component("test", { 
    bindings: { 
    "myContactId": "<" 
    }, 
    controller:function(){ 
    var self=this; 
    this.$onInit=function(){ 
    // do all your initializations here. 
    // create a local scope object for this component only. always update that scope with bindings. and use that in views also. 

     self.myScopeObject=self.myContactId 
    } 
    }, 
    template:'<p>{{$ctrl.myScopeObject}}</p>' 
} 

<test my-contact-id="8"></test> 

einige Punkte:

  1. Bindungen an eine Komponente in html vorbei geht immer mein-Kontakt-ID und ihre jeweiligen Javascript Variable verrohrten ex Kebab wird Cammal verrohrt sein: myContactId.

  2. Wenn Sie den Wert des Objekts übergeben, verwenden Sie '@' in Bindings. Wenn Sie ein Objekt verwenden und das Objekt an Bindigs übergeben, verwenden Sie '<. wenn Sie möchten, 2-Wege-Bindung an das Objekt Verwendung '=' in den Bindungen Config

bindings:{ 
     value:'@', 
     object:'<', // also known as one-way 
     twoWay:'=' 
    }