Búsqueda de sitios web

javascript - Pérdida de alcance al usar ng-include


Tengo este módulo de rutas:

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

HTML de inicio:

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

En la función addLine $scope.lineText es undefined, esto se puede resolver agregando ng-controller="HomeCtrl" a partial1.html, sin embargo, hace que el controlador se llame dos veces. ¿Qué me estoy perdiendo aquí?

Respuesta #1

Como mencionó @Renan, ng-include crea un nuevo scope hijo. Este scope hereda prototípicamente (ver líneas punteadas a continuación) del scope de HomeCtrl. ng-model="lineText" en realidad crea una propiedad de scope primitiva en el scope hijo, no en el scope de HomeCtrl. Este scope hijo no es accesible para el scope padre/HomeCtrl:

Para almacenar lo que el usuario escribió en el array $scope.lines de HomeCtrl, sugiero que pases el valor a la función addLine:

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

Además, dado que lineText es propiedad del alcance/parte de ngInclude, siento que debería ser responsable de limpiarlo:

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

La función addLine() se convertiría así:

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

Violín.

Alternativas:

  • define una propiedad de objeto en el $scope de HomeCtrl, y úsala en la plantilla parcial: ng-model="someObj.lineText; fiddle
  • no recomendado, esto es más un truco: usa $parent en el partial para crear/acceder a una propiedad lineText en el $scope de HomeCtrl: ng-model="$parent.lineText"; fiddle

Es un poco complicado explicar por qué funcionan las dos alternativas anteriores, pero se explica completamente aquí: ¿Cuáles son las diferencias de matiz de la herencia prototípica/prototípica en AngularJS?

No recomiendo usar this en la función addLine(). Se vuelve mucho menos claro qué alcance se está accediendo/manipulando.

Respuesta #2

Esto se debe a ng-include que crea un nuevo scope hijo, por lo que $scope.lineText no se cambia. Creo que this se refiere al scope actual, por lo que this.lineText debería ser establecido.

Respuesta #3

En lugar de usar this como sugiere la respuesta aceptada, usa $parent en su lugar. Así que en tu partial1.html tendrás:

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

Si quieres aprender más sobre el scope en ng-include u otras directivas, consulta esto: https://github.com/angular/angular.js/wiki/Understanding-Scopes#ng-include

Artículos relacionados