有没有在AngularJSmodal dialog中处理“取消”的模式?
注意:这不是用AngularJS显示一个modal dialog,该主题有很多问题和答案!
这个问题是关于如何对页面上的模式对话框中的确定和取消做出反应。 假设你只有一个variables,
$scope.description = "Oh, how I love porcupines..."
如果我在页面上为您提供了一个模式对话框,并且在该对话框中使用了ng-model =“description”,则所做的所有更改实际上都是在input时对描述本身进行的。 这很糟糕,因为那么你如何取消对话?
有这个问题说,做我下面解释。 被接受的答案是与我想出的相同的“解决scheme”: AngularJS:数据绑定模式 – 仅在单击“保存”时保存更改,或者在单击“取消”时忘记更改
我可以看到如果点击button来调出模态,可以返回到后面的function,并为模态创build相关数据的临时副本,然后popup模态。 然后“确定”(或“保存”或其他)可以将临时值复制到实际的模型值。
main.js(摘录):
$scope.descriptionUncommitted = $scope.description; $scope.commitChanges = function () { $scope.description = $scope.descriptionUncommitted; }
main.html(摘录):
<input type="text" ng-model="descriptionUncommitted"/> <button ng-click="commitChanges()">Save</button>
这个问题是不是说明性的 ! 事实上,这与其他地方的AngularJS不同。 这几乎就像我们需要一个ng-model-uncommitted =“description”,他们可以在其中进行所有需要的更改,但只有在我们用另一个声明触发时才会提交。 在某个插件中是否有这样的事情,或者是AngularJS自己添加的?
编辑:看来,这样做的另一种方式的例子可能是为了。
main.js:
$scope.filename = "panorama.jpg"; $scope.description = "A panorama of the mountains."; $scope.persist = function () { // Some function to hit a back end service. };
main.html中:
<form> <input type="text" ng-model-uncommitted="filename"/> <input type="text" ng-model-uncommitted="description"/> <button ng-commit ng-click="persist()">Save</button> <button ng-discard>Cancel</button> </form>
我在表单上贴了一个表格标签,因为我不知道如何将这些项目分组,所以很清楚它是同一个“事务”的一部分(因为缺less一个更好的单词)。 但是需要有一些方法可以自动完成,模型variables的克隆副本用于初始值,用于input和自动更新,validation等,然后最终丢弃或复制到相同的值最初是用来创build它们,如果用户决定提交。
是不是像这样的事情比在控制器中的代码更容易做到这一点在一个大网站20模态一遍又一遍? 还是我疯了?
基本上,如果有些东西不是陈述式的,那么你可以做一个指令 。
.directive('shadow', function() { return { scope: { target: '=shadow' }, link: function(scope, el, att) { scope[att.shadow] = angular.copy(scope.target); scope.commit = function() { scope.target = scope[att.shadow]; }; } };
然后:
<div shadow="data"> <input ng-model="data"> <button ng-click="commit()">save</button> </div>
所以shadow
指令内的data
将是原始data
的副本 。 当点击button时,它将被复制回原来的位置。
这里是工作的例子: jsbin
除了这个例子,我还没有对它进行testing,所以在其他情况下可能不起作用,但我认为它给出了可能性的概念。
编辑:
另一个用对象代替string的例子,以及表单中的几个字段(这里需要一个额外的angular.copy
): jsbin
Edit2,angular度版本1.2.x
根据此更改 ,指令内的input
不再访问隔离范围。 另一种方法是创build一个非隔离的子范围( scope:true
),以保存数据的副本并访问父范围以进行保存。
所以对于更高版本的angular度来说,这个方法和之前的做法是一样的:
.directive('shadow', function() { return { scope: true, link: function(scope, el, att) { scope[att.shadow] = angular.copy(scope[att.shadow]); scope.commit = function() { scope.$parent[att.shadow] = angular.copy(scope[att.shadow]); }; } }; });
例如: jsbin
请注意,使用$parent
的问题在于,如果最终中间存在另一个范围,它可能会中断。
从Angular 1.3起,有一个ngModelOptions指令,允许本地执行相同的行为。
<form name="userForm"> <input type="text" ng-model="user.name" ng-model-options="{ updateOn: 'submit' }" name="userName"> <button type="submit">save</button> <button type="button" ng-click="userForm.userName.$rollbackViewValue();">cancel</button> </form>
JSFiddle: http : //jsfiddle.net/8btk5/104/
面对相同的问题,通过这个线程,我想出了lazy-model
指令,其工作方式与ng-model
完全相同,但只在提交表单时才保存更改。
用法:
<input type="text" lazy-model="user.name">
请注意将其包装到<form>
标签中,否则懒惰模型将不知道何时将更改推送到原始模型。
全面工作演示 : http : //jsfiddle.net/8btk5/3/
lazyModel指令代码:
(更好的使用github上的实际版本 )
app.directive('lazyModel', function($parse, $compile) { return { restrict: 'A', require: '^form', scope: true, compile: function compile(elem, attr) { // getter and setter for original model var ngModelGet = $parse(attr.lazyModel); var ngModelSet = ngModelGet.assign; // set ng-model to buffer in isolate scope elem.attr('ng-model', 'buffer'); // remove lazy-model attribute to exclude recursion elem.removeAttr("lazy-model"); return function postLink(scope, elem, attr) { // initialize buffer value as copy of original model scope.buffer = ngModelGet(scope.$parent); // compile element with ng-model directive poining to buffer value $compile(elem)(scope); // bind form submit to write back final value from buffer var form = elem.parent(); while(form[0].tagName !== 'FORM') { form = form.parent(); } form.bind('submit', function() { scope.$apply(function() { ngModelSet(scope.$parent, scope.buffer); }); }); form.bind('reset', function(e) { e.preventDefault(); scope.$apply(function() { scope.buffer = ngModelGet(scope.$parent); }); }); }; } }; });
GitHub上的实际源代码
你似乎在过度思考这个问题。 没有插件,因为这个过程非常简单。 如果你想要一个模型的原始副本,请创build一个并保存在控制器中。 如果用户取消,将模型重置为您的副本,并使用FormController。$ setPristine()方法重新生成表单。
//Controller: myService.findOne({$route.current.params['id']}, function(results) { $scope.myModel = results; var backup = results; } //cancel $scope.cancel = function() { $scope.myModel = backup; $scope.myForm.$setPristine(); }
那么在你看来:
<form name="myForm">
您需要命名表单来创build$ scope.myForm控制器。
另一种方法是在编辑模型之前复制模型,然后取消,恢复原始模型。 angular度控制器代码:
//on edit, make a copy of the original model and store it on scope function edit(model){ //put model on scope for the cancel method to access $scope.modelBeingEdited = model; //copy from model -> scope.originalModel angular.copy(model,$scope.originalModel); } function cancelEdit(){ //copy from scope.original back to your model angular.copy($scope.originalModel, $scope.modelBeingEdited) }
这是我保持简单的尝试,使其声明,而不依赖于表单标签或其他的东西。
一个简单的指令:
.directive("myDirective", function(){ return { scope: { item: "=myDirective" }, link: function($scope){ $scope.stateEnum = { view: 0, edit: 1 }; $scope.state = $scope.stateEnum.view; $scope.edit = function(){ $scope.tmp1 = $scope.item.text; $scope.tmp2 = $scope.item.description; $scope.state = $scope.stateEnum.edit; }; $scope.save = function(){ $scope.item.text = $scope.tmp1; $scope.item.description = $scope.tmp2; $scope.state = $scope.stateEnum.view; }; $scope.cancel = function(){ $scope.state = $scope.stateEnum.view; }; }, templateUrl: "viewTemplate.html" }; })
viewTemplate.html:
<div> <span ng-show="state == stateEnum.view" ng-click="edit()">{{item.text}}, {{item.description}}</span> <div ng-show="state == stateEnum.edit"><input ng-model="tmp1" type="text"/> <input ng-model="tmp2" type="text"/><a href="javascript:void(0)" ng-click="save()">save</a> <a href="javascript:void(0)" ng-click="cancel()">cancel</a></div> </div>
然后设置上下文(item):
<div ng-repeat="item in myItems"> <div my-directive="item"></div> </div>
看到它的行动: http : //plnkr.co/edit/VqoKQoIyhtYnge2hzrFk?p=preview