当我单击“检查”按钮时,以下代码引发错误“TypeError:无法读取未定义的属性'$ pristine'”。
app.controller('MainCtrl', function($scope) {
// other stuff
})
.controller('Ctrl2', function($scope) {
$scope.product = {description:'pump'};
$scope.output = 'unknown';
// uncomment to avoid undefined error, still can't see $pristine
// $scope.formHolder = {};
$scope.checkForm = function() {
$scope.descriptionTest = $scope.product.description;
if ($scope.formHolder.productForm.$pristine) {
$scope.output = 'yes';
}
if ($scope.formHolder.productForm.$dirty) {
$scope.output = 'no'
}
}
});
html
<body ng-controller="MainCtrl">
<div >
<ng-include ng-controller="Ctrl2" src="'myForm.html'"></ng-include>
</div>
</body>
myForm.html
<form name="productForm" novalidate>
<h2>myForm</h2>
description: <input type="text" name="description" ng-model="product.description"/>
<br>
<button ng-click="checkForm()">Check Form</button>
<br>
Form Pristine: {{output}}
<br><br>
I can see the description: {{descriptionTest}}
</form>
plunkr
问题是我的Ctrl2看不到productForm。最初,我认为这与ng-include在创建子范围时所做的原型(prototype)继承有关,因此我尝试在Ctrl2中添加变量:
$scope.productForm = {};
这消除了错误,但是我的 Controller 仍然无法正确看到$ pristine或$ dirty。
我终于通过在productForm上方添加$ scope.formHolder对象来使其工作:
plunkr
.controller('Ctrl2', function($scope) {
$scope.product = {description:'pump'};
$scope.output = 'unknown';
// uncomment to avoid undefined error, still can't see $pristine
$scope.formHolder = {};
$scope.checkForm = function() {
$scope.descriptionTest = $scope.product.description;
if ($scope.formHolder.productForm.$pristine) {
$scope.output = 'yes';
}
if ($scope.formHolder.productForm.$dirty) {
$scope.output = 'no'
}
}
});
html
<form name="formHolder.productForm" novalidate>
为什么起作用?还有更好的方法吗?
我之所以这样结束,是因为我有一个可以使用的表单和 Controller /模板,并且希望在其他地方重用。我可能应该制定一条指令,但是除了表单的$ pristine和$ dirty功能外,其他所有东西都可以正常工作-所有ng-model vars都正确传递了。
How can I set a form contained inside a ng-include to be prestine?的回答是“违反所有规则”,但看起来更复杂。
当我编写表单 Controller 时,何时将$ pristine添加到作用域以及作用域?
编辑/答案:
我最初的问题可以归结为关于form指令如何写入范围的困惑。我的印象是,它将把事情带入
<form name="productForm">...
并为其添加属性,例如
$scope.productForm.$pristine = function() {...}
但是,它直接在productForm上面写:
$scope.productForm = formObject;
因此,表单对象存储在子对象中,而不是所选答案中说明的父对象中。
子范围继承的关键要素对我有所帮助,那就是在阅读而不是写作中要引用链条。因此,如果您设置诸如childScope.myThing.property ='123'之类的内容,虽然看起来像是写入操作,但它首先必须进行读取才能找出myThing是什么。设置childScope.myThing ='567'是直接写操作,完全不涉及查看父链。所有这些都可以在What are the nuances of scope prototypal / prototypical inheritance in AngularJS?中得到更好的解释。
最佳答案
要了解formHolder
解决方案为何有效,您必须首先了解JavaScript prototypes chain。让我们在下面的伪代码中说明没有formHolder
的第一种情况:
$parentScope = {
//I'm a parent scope inside Ctrl2
productForm:{} //to avoid undefined reference error
}
$childScope = {
//I'm a child scope created by by ng-include
__protototype__: $parentScope
}
解析
form
指令后,它会创建FormController
,该值在$scope
属性值指示的键下的name
属性上设置。这几乎等同于:$childScope.productForm = $formCtrl;
之后,这两个作用域如下所示:
$parentScope = {
//I'm a parent scope inside Ctrl2
productForm:{} //to avoid undefined reference error
}
$childScope = {
//I'm a child scope created by by ng-include
productForm: $formCtrl
__protototype__: $parentScope
}
因此,您实际上在不同范围的上拥有 2个属性,这些属性持有不同的对象。
现在,在第二种情况下,您将遇到以下情况:
$parentScope = {
//I'm a parent scope inside Ctrl2
formHolder:{} //to avoid undefined reference error
}
$childScope = {
//I'm a child scope created by by ng-include
__protototype__: $parentScope
}
当
form
指令这次在FormController
上设置$scope
实例时,它使用不同的属性链:$childScope.formHolder.productForm = $formCtrl;
相当于写:
var formHolder = $childScope.formHolder; //since formHolder isn't defined on $childScope
//the JS runtime will look for it in the prototypes chain and find it inside $parentScope
//so here formHolder is the very same object you created and set on $parentScope
formHolder.productForm = $formCtrl;
希望它有助于理解第二个选项为何起作用。至于问题的第二部分-您的解决方案简单且完全可行-但还有其他几种处理方法,最好取决于实际使用情况:
关于angularjs - 为什么在检查$ pristine或$ setDirty()时在ng-include内形成undefined?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/23686831/