Verlust des Umfangs bei Verwendung von ng-include

181

Ich habe dieses Modul Routen:

var mainModule = angular.module('lpConnect', []).
    config(['$routeProvider', function ($routeProvider) {
    $routeProvider.
        when('/home', {template:'views/home.html', controller:HomeCtrl}).
        when('/admin', {template:'views/admin.html', controller:AdminCtrl}).
        otherwise({redirectTo:'/connect'});
}]);

Home HTML:

<div ng-include src="views.partial1"></div>

partial1 HTML:

<form ng-submit="addLine()">
    <input type="text" ng-model="lineText" size="30" placeholder="Type your message here">
</form>

HomeCtrl::

function HomeCtrl($scope, $location, $window, $http, Common) {
    ...
    $scope.views = {
        partial1:"views/partial1.html"
    };

    $scope.addLine = function () {
        $scope.chat.addLine($scope.lineText);
        $scope.lines.push({text:$scope.lineText});
        $scope.lineText = "";
    };
...
}

In der addLineFunktion $scope.lineTextist undefined, kann dies durch Zugabe gelöst werden , ng-controller="HomeCtrl"um partial1.htmljedoch bewirkt , dass es die Regler zweimal aufgerufen werden. Was fehlt mir hier?

Shlomi Schwartz
quelle

Antworten:

83

Dies liegt daran, ng-includedass ein neuer untergeordneter Bereich erstellt wird, der also $scope.lineTextnicht geändert wird. Ich denke, das thisbezieht sich auf den aktuellen Umfang, this.lineTextsollte also festgelegt werden.

Renan Tomal Fernandes
quelle
260

Wie @Renan erwähnt hat, erstellt ng-include einen neuen untergeordneten Bereich. Dieser Bereich erbt prototypisch (siehe gestrichelte Linien unten) vom HomeCtrl-Bereich. ng-model="lineText"Erstellt tatsächlich eine primitive Bereichseigenschaft für den untergeordneten Bereich, nicht für den Bereich von HomeCtrl. Auf diesen untergeordneten Bereich kann der übergeordnete / HomeCtrl-Bereich nicht zugreifen:

ng-include-Bereich

Um zu speichern, was der Benutzer in das Array $ scope.lines von HomeCtrl eingegeben hat, empfehlen wir Ihnen, den Wert an die Funktion addLine zu übergeben:

 <form ng-submit="addLine(lineText)">

Da lineText dem ngInclude-Bereich / -Partial gehört, sollte es meines Erachtens für das Löschen verantwortlich sein:

 <form ng-submit="addLine(lineText); lineText=''">

Die Funktion addLine () würde somit werden:

$scope.addLine = function(lineText) {
    $scope.chat.addLine(lineText);
    $scope.lines.push({
        text: lineText
    });
};

Geige .

Alternativen:

  • Definieren Sie eine Objekteigenschaft im $ scope von HomeCtrl und verwenden Sie diese im Teil : ng-model="someObj.lineText; Geige
  • Nicht empfohlen, dies ist eher ein Hack: Verwenden Sie $ parent im Teil, um eine lineTextEigenschaft im Bereich HomeCtrl $ zu erstellen / darauf zuzugreifen :   ng-model="$parent.lineText"; Geige

Es ist ein wenig kompliziert zu erklären, warum die beiden oben genannten Alternativen funktionieren, aber es wird hier vollständig erklärt: Was sind die Nuancen der prototypischen / prototypischen Vererbung des Geltungsbereichs in AngularJS?

Ich empfehle nicht, thisdie Funktion addLine () zu verwenden. Es wird viel weniger klar, auf welchen Bereich zugegriffen / manipuliert wird.

Mark Rajcok
quelle
1
Endlich verstehe ich.
Scott Tesler
1
Gleiche Frage @Jess hatte, warum wird dies als Hack angesehen?
qbert65536
13
@ qbert65536, es ist im Wesentlichen ein Hack / Fragile, denn wenn Sie Ihr HTML umstrukturieren, funktioniert es möglicherweise nicht mehr. Möglicherweise müssen Sie dann verwenden $parent.$parent..., um es zum Laufen zu bringen. Anders ausgedrückt: Verwenden Sie $parentAnnahmen über die DOM-Struktur.
Mark Rajcok
6
@Jess' Link oben wurde auf diese geänderte Verständnis Scopes ngInclude . Lesen Sie die ganze Seite, es ist großartig.
mraaroncruz
1
Dies ist eine sehr detaillierte Antwort, aber ich habe sie alle ohne Erfolg ausprobiert. Ich habe ein Formular mit einigen Eingaben in einen Controller und das Ergebnis eines Controllers sollte auf einem anderen Div angezeigt werden. Sobald ich eine Eingabe eingebe, geht die Synchronität verloren und ich habe einen konstanten Wert von 0,00 in der Ansicht div, während die App ausgeführt wird.
Zahra
33

Anstelle der Verwendung thisals die akzeptierte Antwort vermuten lässt, verwenden $parentstatt. Also in deinem partial1.htmlhast du:

<form ng-submit="$parent.addLine()">
    <input type="text" ng-model="$parent.lineText" size="30" placeholder="Type your message here">
</form>

Wenn Sie mehr über den Geltungsbereich ng-includeoder andere Richtlinien erfahren möchten , lesen Sie diese Informationen unter: https://github.com/angular/angular.js/wiki/Understanding-Scopes#ng-include

ErwinGO
quelle
1
Für jeden Leser, bedeutet , dass er $scope.$parentstatt $parentnach Angular nicht definiert ist.
Sebastialonso
1
Diese Antwort spart mir den Tag! Vielen Dank, dass Sie auf die Verwendung von $ parent hingewiesen haben.
Derek Webb
ist $ scope. $ parent als Referenz übergeben? oder ist es nur eine Kopie des Elternteils?
OMGPOP
1
@Sebastiallonso ist falsch. $ scope. $ parent.lineText ist undefiniert. $ parent.lineText funktioniert, this.lineText oder einfach nur lineText funktionieren auch
OMGPOP
Es ist das $scope.$parent, was für mich in Winkel 1.3.20
Radtek
4

Ich habe herausgefunden, wie ich dieses Problem umgehen kann, ohne übergeordnete und untergeordnete Daten zu mischen. Setzen Sie ein ng-iffür das ng-includeElement und setzen Sie es auf eine Bereichsvariable. Zum Beispiel :

<div ng-include="{{ template }}" ng-if="show"/>

Wenn Sie in Ihrem Controller alle Daten festgelegt haben, die Sie in Ihrem Unterbereich benötigen, setzen Sie show auf true. Das ng-includekopiert zu diesem Zeitpunkt den Datensatz in Ihrem Bereich und legt ihn in Ihrem Unterbereich fest.

Als Faustregel gilt, dass die Bereichsdaten tiefer reduziert werden, da Sie sonst in dieser Situation sind.

Max

wascou
quelle
Ich verwende diesen Ansatz für ein ähnliches Problem, aber er ist nicht für alle Fälle geeignet. Besonders wenn Sie möchten, dass das enthaltene Element niemals versteckt wird ...
iSpithash