当我单击“检查”按钮时,以下代码引发错误“ 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>
朋克
问题是我的Ctrl2看不到productForm。最初,我认为这与ng-include在创建子范围时所做的原型继承有关,因此我尝试在Ctrl2中添加变量:
$scope.productForm = {};
这摆脱了错误,但是我的控制器仍然无法正确看到$ pristine或$ dirty。
我终于通过在productForm上方添加$ scope.formHolder对象来使其工作:
.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' } } });
<form name="formHolder.productForm" novalidate>
为什么这样做? 还有更好的方法吗?
之所以以这种方式结束,是因为我有一个可以使用的表单和控制器/模板,并且希望在其他地方重用。我可能应该发出一条指令,但是除了表单的$ pristine和$ dirty功能外,其他所有功能都可以正常工作-所有ng-model vars均正确传递。
如何设置ng-include内包含的表单为prestine?答案是“违反所有规则”,但看起来更复杂。
当我编写表单控制器时,何时将$ pristine添加到作用域以及作用域?
编辑/回答:
我最初的问题可以归结为关于form指令如何写入范围的混乱。我的印象是,它将把事情带入
<form name="productForm">...
并为其添加属性,例如
$scope.productForm.$pristine = function() {...}
但是,它直接在productForm上面写:
$scope.productForm = formObject;
因此,表单对象存储在子对象中,而不是所选答案中说明的父对象中。
子范围继承的关键要素对我有所帮助,那就是在阅读而不是写作中要参考链条。因此,如果您设置类似于childScope.myThing.property=‘123’的内容,虽然看起来像是写入操作,但它首先必须进行读取才能找出myThing是什么。设置childScope.myThing=‘567’是直接写操作,完全不涉及查看父链。
要了解为什么解决方案formHolder有效,您必须首先了解JavaScript原型链。让我们formHolder用以下伪代码说明第一种情况:
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的属性值。这几乎等同于:
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 }
因此,实际上您最终获得了两个包含不同对象的 不同范围的属性 。现在,在第二种情况下,您将遇到以下情况:
$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;
希望它有助于理解第二种选择为何起作用。至于问题的第二部分-您的解决方案简单且完全可行-但是有几种其他处理方法,最好取决于实际使用情况: