使用 ng-include 时丢失范围

IT技术 javascript html angularjs angularjs-scope angularjs-ng-include
2021-01-13 09:35:46

我有这个module路线:

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,但是它会导致控制器被调用两次。我在这里错过了什么?

4个回答

正如@Renan 提到的,ng-include 创建了一个新的子作用域。这个范围原型从 HomeCtrl 范围继承(见下面的虚线)。 ng-model="lineText"实际上在子作用域上创建了一个原始作用域属性,而不是 HomeCtrl 的作用域。父/HomeCtrl 范围无法访问此子范围:

ng-包含范围

要将用户输入的内容存储到 HomeCtrl 的 $scope.lines 数组中,我建议您将值传递给 addLine 函数:

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

另外,由于 lineText 归 ngInclude scope/partial 所有,我觉得它应该负责清除它:

 <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; 小提琴
  • 不推荐,这更像是一个黑客:在部分中使用 $parent 来创建/访问lineTextHomeCtrl $scope 上的属性:   ng-model="$parent.lineText"小提琴

解释为什么上述两种替代方案工作有点复杂,但在这里得到了充分解释:AngularJS 中范围原型/原型继承的细微差别是什么?

我不建议this在 addLine() 函数中使用。正在访问/操作哪个范围变得不太清楚。

我使用了objects,但它们的范围仍然被屏蔽。我试过了$parent.,效果很好。为什么你认为这是一个黑客?(我可以看到如果你重构你的 html,它会增加维护)
2021-03-13 09:35:46
@Jess 上面的链接已更改为这个理解范围 ngInclude阅读整页,很棒。
2021-03-16 09:35:46
这是一个非常详细的答案,但我尝试了所有这些都没有成功。我有一个带有控制器输入的表单,控制器的结果应该在另一个 div 上查看。一旦我输入任何输入,同步性将丢失,并且当应用程序运行时,视图 div 上的值将保持恒定 0.00。
2021-03-24 09:35:46
@qbert65536,它本质上是一种黑客/脆弱,因为如果您重组 HTML,它可能不再起作用。例如,您可能需要使用$parent.$parent...来让它工作。换句话说, using$parent对 DOM 结构做出假设。
2021-03-27 09:35:46
@Jess 有同样的问题,为什么这被认为是 hack ?
2021-03-31 09:35:46

这是因为ng-include它创建了一个新的子作用域,所以$scope.lineText不会改变。我认为是this指当前范围,所以this.lineText应该设置。

不要this像接受的答案建议的那样使用,$parent而是使用所以在你的partial1.html你将拥有:

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

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

这个答案为我节省了一天!非常感谢您指出 $parent 的使用。
2021-03-17 09:35:46
$scope.$parent 是通过引用传递的吗?或者它只是父母的副本?
2021-03-17 09:35:46
$scope.$parent在 angular 1.3.20 中对我有用
2021-03-30 09:35:46
@Sebastiallonso 是错误的。$scope.$parent.lineText 未定义。$parent.lineText 正在工作,this.lineText 或只是 lineText 也在工作
2021-04-04 09:35:46
对于任何读者来说,他的意思是 $scope.$parent而不是$parent根据 Angular 是未定义的。
2021-04-07 09:35:46

我已经想出了如何在不混合父级和子级数据的情况下解决这个问题。ng-ifng-include元素设置 a并将其设置为范围变量。例如 :

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

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

经验法则是在范围更深的范围内减少范围数据,否则就会出现这种情况。

最大限度

我正在将这种方法用于类似的问题,但并不适用于所有情况。特别是当您希望包含的元素永远不会被隐藏时......
2021-03-24 09:35:46