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

181

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

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.lineTextIS undefined, это может быть решено путем добавленияng-controller="HomeCtrl" к partial1.html, однако это вызывает вызов контроллера дважды. Что мне здесь не хватает?

Шломи Шварц
источник

Ответы:

83

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

Ренан Томаль Фернандес
источник
260

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

нг-включить область

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

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

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

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

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

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

Скрипки .

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

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

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

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

Марк Райкок
источник
1
Наконец то понял.
Скотт Теслер
1
Тот же вопрос, что и у Джесс, почему это считается хаком?
qbert65536
13
@ qbert65536, это по сути хак / хрупкий, потому что если вы реструктурируете свой HTML, он может больше не работать. Например, вам может понадобиться использовать $parent.$parent...его для работы. Другими словами, использование $parentделает предположения о структуре DOM.
Марк Райкок
6
Ссылка @Jess выше была изменена на эту Понимаемую сферу ngInclude . Прочитайте всю страницу, это здорово.
mraaroncruz
1
Это отличный подробный ответ, но я попробовал все безуспешно. У меня есть форма с некоторым входом в контроллер, и результат контроллера должен быть просмотрен на другом div. Как только я введу любой вход, синхронность будет потеряна, и у меня будет постоянное значение 0,00 в представлении div во время работы приложения.
Захра
33

Вместо использования 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

ErwinGO
источник
1
Для любого читателя он подразумевает $scope.$parentвместо $parentнеопределенного в соответствии с Angular.
Себастьянсо
1
Этот ответ спас мне день! Большое спасибо за указание на использование $ parent.
Дерек Уэбб
такое $ scope. $ родительский проход по ссылке? или это просто копия родительского?
OMGPOP
1
@ Себастиаллонсо не так. $ scope. $ parent.lineText не определен. $ parent.lineText работает, this.lineText или просто просто lineText также работают
OMGPOP
Это $scope.$parentработает для меня в угловой
1.3.20
4

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

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

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

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

Максимум

wascou
источник
Я использую этот подход для аналогичной проблемы, но это не подходит для всех случаев. Особенно, если вы хотите, чтобы включенный элемент никогда не скрывался ...
iSpithash