Perdere l'ambito quando si utilizza ng-include


181

Ho i percorsi di questo modulo:

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 = "";
    };
...
}

Nella addLinefunzione $scope.lineTextè undefined, questo può essere risolto aggiungendo ng-controller="HomeCtrl"a partial1.html, tuttavia fa sì che il controller venga chiamato due volte. Cosa mi sto perdendo qui?

Risposte:


83

Ciò è dovuto al fatto ng-includeche crea un nuovo ambito figlio, quindi $scope.lineTextnon viene modificato. Penso che si thisriferisca allo scopo attuale, quindi this.lineTextdovrebbe essere impostato.


260

Come accennato da @Renan, ng-include crea un nuovo ambito figlio. Questo ambito eredita prototipicamente (vedere le linee tratteggiate di seguito) dall'ambito HomeCtrl. ng-model="lineText"crea effettivamente una proprietà dell'ambito primitivo sull'ambito figlio, non l'ambito di HomeCtrl. Questo ambito figlio non è accessibile all'ambito padre / HomeCtrl:

ng-include scope

Per memorizzare ciò che l'utente ha digitato nella matrice $ scope.lines di HomeCtrl, ti suggerisco di passare il valore alla funzione addLine:

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

Inoltre, poiché lineText è di proprietà dell'ambito / parziale ngInclude, ritengo che dovrebbe essere responsabile della sua cancellazione:

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

La funzione addLine () diventerebbe così:

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

Violino .

alternative:

  • definire una proprietà oggetto su $ portata di HomeCtrl, e usarlo nella parziale: ng-model="someObj.lineText; violino
  • non consigliato, questo è più di un hack: uso $ genitore nel parziale di creare / accesso una lineTextproprietà sulla HomeCtrl $ campo di applicazione:   ng-model="$parent.lineText"; violino

È un po 'complicato spiegare perché le due alternative di cui sopra funzionano, ma è completamente spiegato qui: quali sono le sfumature dell'eredità prototipo / prototipica dell'ambito in AngularJS?

Non consiglio di utilizzare thisla funzione addLine (). Diventa molto meno chiaro quale ambito si sta accedendo / manipolando.


1
Finalmente capisco.
Scott Tesler,

1
Stessa domanda che @Jess aveva, perché questo è considerato un trucco?
qbert65536,

13
@ qbert65536, è essenzialmente un hack / fragile perché se ristrutturi il tuo HTML, potrebbe non funzionare più. Ad esempio, potrebbe essere necessario utilizzarlo $parent.$parent...per farlo funzionare. Detto in altro modo, utilizzando $parentfa ipotesi sulla struttura del DOM.
Mark Rajcok,

6
Il link @Jess 'sopra è stato modificato in questo ambito di comprensione ngInclude . Leggi l'intera pagina, è fantastico.
mraaroncruz,

1
Questa è un'ottima risposta dettagliata, ma le ho provate tutte senza successo. Ho un modulo con alcuni input per un controller e il risultato di un controller dovrebbe essere visualizzato su un altro div. Una volta inserito qualsiasi input, la sincronicità andrà persa e avrò un valore 0.00 costante sul div view mentre l'app è in esecuzione.
zahra,

33

Invece di utilizzare thiscome suggerisce la risposta accettata, utilizzare $parentinvece. Quindi nel tuo partial1.htmlavrai:

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

Se vuoi saperne di più sull'ambito di applicazione ng-includeo su altre direttive, dai un'occhiata a: https://github.com/angular/angular.js/wiki/Understanding-Scopes#ng-include


1
Per ogni lettore, intende $scope.$parentinvece che $parentnon è definito secondo Angular.
Sebastialonso,

1
Questa risposta mi salva la giornata! Grazie mille per aver sottolineato l'uso di $ parent.
Derek Webb,

è $ scope. $ parent passa per riferimento? o è solo una copia del genitore?
OMGPOP,

1
@Sebastiallonso è sbagliato. $ scope. $ parent.lineText non è definito. $ parent.lineText funziona, this.lineText o semplicemente anche lineText funzionano anche
OMGPOP

È $scope.$parentquello che funziona per me in angolare 1.3.20
radtek

4

Ho capito come ovviare a questo problema senza mescolare i dati genitore e secondario. Impostare una ng-ifsul l' ng-includeelemento e impostarlo su una variabile ambito. Per esempio :

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

Nel controller, dopo aver impostato tutti i dati necessari nel proprio ambito secondario, impostare show su true. Il ng-includecopierà in questo momento il set di dati nel campo di applicazione e impostarla nel sub ambito.

La regola empirica è quella di ridurre i dati dell'ambito più in profondità, altrimenti hai questa situazione.

Max


Sto usando questo approccio per un problema simile ma non è adatto a tutti i casi. Soprattutto quando vuoi che l'elemento incluso non
venga
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.