angular 嵌套表单验证 setPristine on subForm -> setPristine on parentForm
angular nested form validation setPristine on subForm -> setPristine on parentForm
我有一个包含多个子表单的父表单(例如 http://jsfiddle.net/riemersebastian/9zr00ear/3/)
当用户更改任何字段时,相应的子表单和父表单会得到 class ng-dirty 以指示某些内容已更改。
我在每个子表单上还有一个保存按钮(实际上它是一个 link),它保存所有子表单更改并调用 subform.$setPristine 来更新子表单的状态。
但是,我希望父表单在不再有脏子表单时也能注意到,从而删除它的 ng-dirty class。
我想出了这个解决方案:http://jsfiddle.net/riemersebastian/9zr00ear/3/
如您所见,我使用 jQuery 手动检查控制器是否有任何标记为脏的子表单,如果没有,我将父表单设置为原始。为此,我需要使用 $timeout 延迟 jQuery,否则 $setPristine 的调用可能尚未更改 DOM,因此不会更新父表单。
我想知道,有更好的方法吗?
代码如下:
var myApp = angular.module('myApp',[]);
myApp.controller('FirstCtrl', ['$scope', '$timeout', function($scope, $timeout) {
$scope.setFormPristine = function(subForm) {
console.log(subForm);
subForm.$setPristine();
$timeout(function() {
if (!($('body').find(".subForm").is(".ng-dirty"))) {
console.log("none is dirty, set main form pristine")
$scope.form.$setPristine();
}
}, 10);
}
}]);
angular.bootstrap(document, ['myApp']);
<body>
<div ng-controller="FirstCtrl">
<div>
(outer) form is dirty? <b>{{ form.$dirty }} </b>
</div>
<form name="form" ng-init="variants = [{duration:10, price:100}, {duration:30, price:200}]">
<div>
<div class="subForm" ng-repeat="variant in variants" ng-form="subForm">
<div>
<label>Duration:</label>
<input name="duration" ng-model="variant.duration"/>
</div>
<div>
<label>Price:</label>
<input name="price" ng-model="variant.price"/>
</div>
<a href="" ng-click="setFormPristine(subForm)">Reset Form to pristine</a>
<div>
(inner) subform is dirty? <b>{{ subForm.$dirty }} </b>
</div>
<br></br>
</div>
</div>
</form>
</div>
</body>
啊!把那个 jquery 拿出来! ;)
我的第一个解决方案是指令和控制器 api 让子表单向主表单推送通知,一些伪代码:
app.directice('mainForm', function($scope) {
return {
restrict: 'E',
transclude: true,
controllerAs: 'mainCtrl',
controller: function($scope){
this.publishState = function (childIsDirty) {
if (!$scope.parentForm.$dirty && !childIsDirty)
$scope.parentForm.$setPristine();
if (childIsDirty) {
$scope.parentForm.$setDirty();
}
}
},
templateUrl: 'parentForm.html'
};
});
app.directice('subForm', function ($scope) {
return {
require: '^parentForm',
restrict: 'A',
transclude: true,
controllerAs : 'viewModel',
link: function (scope, element, attrs, parentForm) {
console.log("Hey I am subForm!");
scope.$watch('subForm1.$dirty', function(isDirty, wasDirty) {
parentForm.publishState(isDirty);
});
},
controller : function() {
var viewModel = this;
viewModel.myData = "Hello World";
},
templateUrl: 'subForm.html'
};
});
使用 html 你应该避免嵌套表单,被认为是糟糕的 html 表单(抱歉,不得不这样做),它们真的不需要,因为需要命令将只查看已注入的所有其他控制器。
<div>
<parent-form></parent-form>
<script type="text/ng-template" id="parentForm.html">
<form name="parentForm">
content
</form>
<form name="subForm1" sub-form></form>
</script>
<script type="text/ng-template" id="subForm.html">
<div>
<input type="text" name="myInput" ng-model="viewModel.myData" >
</div>
</script>
</div>
如果你不想link,你也可以将主窗体方法传入子窗体的范围'&'。
另一种方法是创建一个共享的 service/factory 用于发布订阅更改,然后表单控制器将监视属性或将它们的方法注册到单例工厂。
我有一个包含多个子表单的父表单(例如 http://jsfiddle.net/riemersebastian/9zr00ear/3/)
当用户更改任何字段时,相应的子表单和父表单会得到 class ng-dirty 以指示某些内容已更改。
我在每个子表单上还有一个保存按钮(实际上它是一个 link),它保存所有子表单更改并调用 subform.$setPristine 来更新子表单的状态。
但是,我希望父表单在不再有脏子表单时也能注意到,从而删除它的 ng-dirty class。
我想出了这个解决方案:http://jsfiddle.net/riemersebastian/9zr00ear/3/
如您所见,我使用 jQuery 手动检查控制器是否有任何标记为脏的子表单,如果没有,我将父表单设置为原始。为此,我需要使用 $timeout 延迟 jQuery,否则 $setPristine 的调用可能尚未更改 DOM,因此不会更新父表单。
我想知道,有更好的方法吗?
代码如下:
var myApp = angular.module('myApp',[]);
myApp.controller('FirstCtrl', ['$scope', '$timeout', function($scope, $timeout) {
$scope.setFormPristine = function(subForm) {
console.log(subForm);
subForm.$setPristine();
$timeout(function() {
if (!($('body').find(".subForm").is(".ng-dirty"))) {
console.log("none is dirty, set main form pristine")
$scope.form.$setPristine();
}
}, 10);
}
}]);
angular.bootstrap(document, ['myApp']);
<body>
<div ng-controller="FirstCtrl">
<div>
(outer) form is dirty? <b>{{ form.$dirty }} </b>
</div>
<form name="form" ng-init="variants = [{duration:10, price:100}, {duration:30, price:200}]">
<div>
<div class="subForm" ng-repeat="variant in variants" ng-form="subForm">
<div>
<label>Duration:</label>
<input name="duration" ng-model="variant.duration"/>
</div>
<div>
<label>Price:</label>
<input name="price" ng-model="variant.price"/>
</div>
<a href="" ng-click="setFormPristine(subForm)">Reset Form to pristine</a>
<div>
(inner) subform is dirty? <b>{{ subForm.$dirty }} </b>
</div>
<br></br>
</div>
</div>
</form>
</div>
</body>
啊!把那个 jquery 拿出来! ;)
我的第一个解决方案是指令和控制器 api 让子表单向主表单推送通知,一些伪代码:
app.directice('mainForm', function($scope) {
return {
restrict: 'E',
transclude: true,
controllerAs: 'mainCtrl',
controller: function($scope){
this.publishState = function (childIsDirty) {
if (!$scope.parentForm.$dirty && !childIsDirty)
$scope.parentForm.$setPristine();
if (childIsDirty) {
$scope.parentForm.$setDirty();
}
}
},
templateUrl: 'parentForm.html'
};
});
app.directice('subForm', function ($scope) {
return {
require: '^parentForm',
restrict: 'A',
transclude: true,
controllerAs : 'viewModel',
link: function (scope, element, attrs, parentForm) {
console.log("Hey I am subForm!");
scope.$watch('subForm1.$dirty', function(isDirty, wasDirty) {
parentForm.publishState(isDirty);
});
},
controller : function() {
var viewModel = this;
viewModel.myData = "Hello World";
},
templateUrl: 'subForm.html'
};
});
使用 html 你应该避免嵌套表单,被认为是糟糕的 html 表单(抱歉,不得不这样做),它们真的不需要,因为需要命令将只查看已注入的所有其他控制器。
<div>
<parent-form></parent-form>
<script type="text/ng-template" id="parentForm.html">
<form name="parentForm">
content
</form>
<form name="subForm1" sub-form></form>
</script>
<script type="text/ng-template" id="subForm.html">
<div>
<input type="text" name="myInput" ng-model="viewModel.myData" >
</div>
</script>
</div>
如果你不想link,你也可以将主窗体方法传入子窗体的范围'&'。
另一种方法是创建一个共享的 service/factory 用于发布订阅更改,然后表单控制器将监视属性或将它们的方法注册到单例工厂。