web-dev-qa-db-fra.com

Perdre la portée lors de l'utilisation de ng-include

J'ai ce module itinéraires:

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'});
}]);

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

Dans la fonction addLine$scope.lineText est undefined, vous pouvez résoudre ce problème en ajoutant ng-controller="HomeCtrl" à partial1.html, mais le contrôleur sera appelé deux fois. Qu'est-ce que j'oublie ici?

179
Shlomi Schwartz

Ceci est dû à ng-include qui crée une nouvelle portée enfant, donc $scope.lineText n’a pas changé. Je pense que this fait référence à la portée actuelle, donc this.lineText devrait être défini.

82

Comme @Renan l'a mentionné, ng-include crée une nouvelle portée enfant. Cette portée hérite de manière prototypique (voir les lignes pointillées ci-dessous) de la portée HomeCtrl. ng-model="lineText" crée en fait une propriété de portée primitive sur la portée enfant, pas celle de HomeCtrl. Cette étendue enfant n'est pas accessible à l'étendue parent/HomeCtrl:

ng-include scope

Pour stocker ce que l'utilisateur a tapé dans le tableau $ scope.lines de HomeCtrl, je vous suggère de transmettre la valeur à la fonction addLine:

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

De plus, comme lineText appartient au scope/partial de ngInclude, j'estime qu'il devrait être responsable de le nettoyer:

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

La fonction addLine () deviendrait alors:

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

violon .

Alternatives:

  • définir une propriété d'objet sur $ scope de HomeCtrl et l'utiliser dans le partiel: ng-model="someObj.lineText; violon
  • non recommandé, il s’agit plutôt d’un hack: utilisez $ parent dans le partiel pour créer/accéder à une propriété lineText sur le champ HomeCtrl $ scope: ng-model="$parent.lineText"; violon

Il est un peu compliqué d'expliquer pourquoi les deux alternatives ci-dessus fonctionnent, mais cela est expliqué en détail ici: Quelles sont les nuances de l'héritage prototypal/prototypique de scope dans AngularJS?

Je ne recommande pas d'utiliser this dans la fonction addLine (). Il devient beaucoup moins clair quelle étendue est en cours d'accès/manipulée.

258
Mark Rajcok

Au lieu d'utiliser this comme le suggère la réponse acceptée, utilisez plutôt $parent. Donc, dans votre partial1.htmlvous aurez:

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

Si vous voulez en savoir plus sur la portée de ng-include ou d'autres directives, consultez ceci: https://github.com/angular/angular.js/wiki/Understanding-Scopes#ng-include

32
ErwinGO

J'ai découvert comment contourner ce problème sans mélanger les données parent et secondaire. Définissez un ng-if sur l'élément ng-include et définissez-le sur une variable de portée. Par exemple :

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

Dans votre contrôleur, lorsque vous avez défini toutes les données nécessaires dans votre sous-périmètre, définissez show sur true. Le ng-include va copier à ce moment le jeu de données dans votre portée et le définir dans votre sous-portée.

La règle empirique est de réduire les données de portée plus en profondeur, sinon vous avez cette situation.

Max

3
wascou