Потеря области при использовании ng-include

У меня есть этот маршрут модуля:

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:

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

В функции addLine $scope.lineText есть undefined, это можно решить, добавив ng-controller="HomeCtrl" в partial1.html, однако это вызывает вызов контроллера дважды. Что мне здесь не хватает?

Ответ 1

Это из-за ng-include, который создает новый дочерний объект, поэтому $scope.lineText не изменяется. Я думаю, что this относится к текущей области, поэтому this.lineText должен быть установлен.

Ответ 2

Как упоминал @Renan, ng-include создает новый дочерний объект. Эта область прототипа наследует (см. Пунктирные линии ниже) из области HomeCtrl. ng-model="lineText" фактически создает примитивное свойство области в области дочернего объекта, а не область HomeCtrl. Эта область дочернего объекта недоступна для области родителя /HomeCtrl:

ng-include scope

Чтобы сохранить то, что пользователь вводил в массив HomeCtrl $scope.lines, я предлагаю передать значение функции addLine:

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

Кроме того, поскольку lineText принадлежит области ngInclude/partial, я считаю, что он должен отвечать за ее очистку:

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

Функция addLine() будет таким образом:

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

Fiddle.

Альтернатива:

  • определить свойство объекта в области HomeCtrl $и использовать его в частичном: ng-model="someObj.lineText; fiddle
  • не рекомендуется, это скорее хак: используйте $parent в частичном создании/доступе к свойству lineText в области HomeCtrl $: ng-model="$parent.lineText"; fiddle

Немного нужно объяснить, почему работают эти две альтернативы, но здесь полностью объясняется: Каковы нюансы объема прототипного/прототипического наследования в AngularJS?

Я не рекомендую использовать this в функции addLine(). Становится гораздо менее понятным, к какой области доступа обращаются/манипулируют.

Ответ 3

Вместо использования this, как предлагает принятый ответ, используйте $parent. Итак, в вашем partial1.html у вас будет:

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

Если вы хотите узнать больше о области в ng-include или других директивах, проверьте это: https://github.com/angular/angular.js/wiki/Understanding-Scopes#ng-include

Ответ 4

Я выяснил, как обойти эту проблему, не смешивая данные родительского и субсайта. Установите ng-if в элементе ng-include и установите для него переменную области видимости. Например:

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

В вашем контроллере, когда вы установили все данные, которые вам нужны, в подпунктовой области, установите show на true. ng-include скопирует в данный момент данные, установленные в вашей области действия, и установит их в вашей области видимости.

Эмпирическое правило состоит в том, чтобы уменьшить объем данных области, более глубоких, чем у вас есть.

Max