使用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.lineTextundefined,这可以通过添加解决ng-controller="HomeCtrl"partial1.html,但它会导致控制器被调用两次。我在这里想念什么?

Answers:


83

这是因为ng-include它会创建一个新的子范围,因此$scope.lineText不会更改。我认为这this是指当前范围,因此this.lineText应设置。


260

如@Renan所述,ng-include创建一个新的子范围。此范围的原型通常是从​​HomeCtrl范围继承(请参见下面的虚线)。 ng-model="lineText"实际上在子作用域而不是HomeCtrl的作用域上创建原始作用域属性。父/ HomeCtrl范围不能访问此子范围:

ng-include范围

为了存储用户在HomeCtrl的$ scope.lines数组中键入的内容,建议您将值传递给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的$ scope上定义一个对象属性,并在局部对象中使用该属性: ng-model="someObj.lineText ; 小提琴
  • 不推荐,这更是一个黑客:在局部使用$父创建/访问lineText的HomeCtrl $ scope属性:   ng-model="$parent.lineText";小提琴

这里涉及到解释以上两种替代方法为何起作用的一些内容,但在此处进行了详细说明: 进行了 AngularJS中范围原型/原型继承的细微差别是什么?

我不建议this在addLine()函数中使用。不清楚要访问/操纵哪个范围。


1
终于我明白了。
Scott Tesler

1
@Jess有同样的问题,为什么这被认为是黑客?
qbert65536

13
@ qbert65536,它本质上是一种hack /脆弱,因为如果您重组HTML,它可能不再起作用。例如,您可能随后需要使用$parent.$parent...它才能使其工作。换句话说,使用$parent对DOM结构进行了假设。
Mark Rajcok

6
上面的@Jess'链接已更改为此谅解范围ngInclude。阅读整个页面,太好了。
mraaroncruz 2014年

1
这是一个非常详细的答案,但是我尝试了所有这些方法,但都没有成功。我有一个对控制器有一些输入的表格,控制器的结果应该在另一个div上查看。输入任何输入后,同步性将丢失,并且在应用程序运行时,视图div上的值为0.00。
zahra

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>

如果您想了解有关范围in ng-include或其他指令的更多信息,请查看以下内容:https : //github.com/angular/angular.js/wiki/Understanding-Scopes#ng-include


1
对于任何读者来说,他的意思 是Angular $scope.$parent而不是$parentundefined。
Sebastialonso

1
这个答案为我节省了一天!非常感谢您指出$ parent的用法。
德里克·韦伯

是$ scope。$ parent通过引用传递的?还是仅仅是父母的副本?
OMGPOP,2015年

1
@Sebastiallonso是错误的。$ scope。$ parent.lineText未定义。$ parent.lineText正在工作,this.lineText或只是lineText也正在工作
OMGPOP,2015年

它对$scope.$parent我有效,角度为1.3.20
radtek

4

我已经弄清楚了如何解决此问题而不混合父级和子级范围数据。ng-ifng-include元素上设置a 并将其设置为作用域变量。例如 :

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

在控制器中,在子作用域中设置了所有需要的数据后,将show设置为true。此时,ng-include将会复制您范围内的数据集并在您的子范围内进行设置。

经验法则是将作用域数据减少到更深的作用域,否则您将遇到这种情况。

最高


我正在针对类似的问题使用这种方法,但这并不适合所有情况。特别是当您希望包含的元素永远不会被隐藏时……
iSpithash
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.