Втрата обсягу при використанні 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.lineTextє undefined, це можна вирішити, додавши ng-controller="HomeCtrl"до partial1.html, однак це призводить до виклику контролера двічі. Що я тут пропускаю?

Відповіді:


83

Це через те, ng-includeщо створює нову область дитини, тому $scope.lineTextїї не змінюють. Я думаю, що це thisстосується нинішнього обсягу, тому його this.lineTextслід встановити.


260

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

ng-include область

Щоб зберігати те, що користувач вводив у масив $ range.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
Це ж запитання @Jess, чому це вважається злом?
qbert65536

13
@ qbert65536, це по суті хак / неміцний, тому що якщо ви реструктуруєте свій HTML, він більше не може працювати. Наприклад, вам може знадобитися використовувати $parent.$parent...його для роботи. По-іншому, використовуючи $parentробить припущення про структуру DOM.
Марк Райкок

6
Посилання @Jess вище було змінено на це Поняття про сфери ngInclude . Прочитайте всю сторінку, це чудово.
mraaroncruz

1
Це чудова детальна відповідь, але я спробував їх усіх без жодного успіху. У мене є форма з деяким входом до контролера, а результат контролера слід переглянути в іншому розділі. Після введення будь-якого вводу синхронність буде втрачена, і я матиму постійне значення 0,00 у розділі перегляду під час роботи програми.
захід

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.
Дерек Вебб

це $ range. $ батьківський пропуск за посиланням? чи це просто копія батьків?
OMGPOP

1
@Sebastiallonso помиляється. $ range. $ parent.lineText не визначено. $ parent.lineText працює, працює також this.lineText або просто lineText
OMGPOP

Це $scope.$parentпрацює для мене в кутовому 1.3.20
radtek

4

Я зрозумів, як вирішити цю проблему, не змішуючи дані батьків та підрозділів. Встановіть елемент ng-ifна ng-includeелемент і встановіть його в змінну області. Наприклад :

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

Коли ви встановите всі необхідні дані у своєму контролері у своєму контролері, тоді встановіть показ true. У ng-includeцей момент скопіюється набір даних у вашому обсязі та встановиться у вашому підрозділі.

Основне правило полягає в тому, щоб зменшити дані про область застосування глибше, ніж у інших випадках.

Макс


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