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


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этот момент будет скопирован набор данных в вашей области и установлен в вашей области.

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

Максимум


Я использую этот подход для аналогичной проблемы, но это не подходит для всех случаев. Особенно, если вы хотите, чтобы включенный элемент никогда не скрывался ...
iSpithash
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.