Redefinir formulário para estado puro (AngularJS 1.0.x)

Uma function para redefinir os campos de formulário para o estado original (reset estado sujo) está no roteiro para o AngularJS 1.1.x. Infelizmente essa function está faltando na versão estável atual.

Qual é a melhor maneira de redefinir todos os campos de formulário para seu estado inicial puro para o AngularJS 1.0.x.

Gostaria de saber se isso pode ser corrigido com uma diretiva ou outra solução simples. Eu prefiro uma solução sem ter que tocar nas fonts originais do AngularJS. Para esclarecer e demonstrar o problema, um link para o JSFiddle. http://jsfiddle.net/juurlink/FWGxG/7/

O recurso desejado está no roteiro – http://blog.angularjs.org/2012/07/angularjs-10-12-roadmap.html
Solicitação de recurso – https://github.com/angular/angular.js/issues/856
Solução proposta Solicitação pull – https://github.com/angular/angular.js/pull/1127

Atualizado com possível solução alternativa

Bom o suficiente solução?

Acabei de descobrir que posso recompilar a parte HTML e colocá-la de volta no DOM. Ele funciona e é bom para uma solução temporária, mas também como @blesh mencionado nos comentários:

Controladores devem ser usados ​​apenas para lógica de negócios, não para DOM!

E no meu controlador em resetForm() :

  • Salve o HTML original intocado
  • Recompile o HTML original salvo
  • Remover o formulário atual do DOM
  • Inserir o novo modelo compilado no DOM

O JavaScript:

 var pristineFormTemplate = $('#myform').html(); $scope.resetForm = function () { $('#myform').empty().append($compile(pristineFormTemplate)($scope)); } 

Solução sem uma solução alternativa

Eu criei uma solução que usa o AngularJS sem nenhuma solução alternativa. O truque aqui é usar a habilidade AngularJS para ter mais de uma diretiva com o mesmo nome.

Como outros usuários mencionaram, existe uma requisição de pull ( https://github.com/angular/angular.js/pull/1127 ) que foi incluída na ramificação AngularJS 1.1.x, que permite que os formulários sejam redefinidos. A confirmação para esta solicitação de pull altera as diretivas ngModel e form / ngForm (gostaria de adicionar um link, mas o Stackoverflow não quer que eu adicione mais de dois links).

Agora podemos definir nossas próprias diretivas ngModel e form / ngForm e estendê-las com a funcionalidade fornecida na solicitação pull.

Eu coloquei essas diretivas em um módulo AngularJS chamado resettableForm. Tudo o que você precisa fazer é include este módulo em seu projeto e seu AngularJS versão 1.0.x se comporta como se fosse uma versão Angular 1.1.x a esse respeito.

“Quando você atualizar para o 1.1.x você não precisa nem atualizar seu código, apenas remova o módulo e pronto!”

Este módulo também passa todos os testes adicionados à ramificação 1.1.x para a funcionalidade de redefinição de formulário.

Você pode ver o módulo trabalhando em um exemplo em um jsFiddle ( http://jsfiddle.net/jupiter/7jwZR/1/ ) que eu criei.

Etapa 1: include o módulo resformableform no seu projeto

 (function(angular) { // Copied from AngluarJS function indexOf(array, obj) { if (array.indexOf) return array.indexOf(obj); for ( var i = 0; i < array.length; i++) { if (obj === array[i]) return i; } return -1; } // Copied from AngularJS function arrayRemove(array, value) { var index = indexOf(array, value); if (index >=0) array.splice(index, 1); return value; } // Copied from AngularJS var PRISTINE_CLASS = 'ng-pristine'; var DIRTY_CLASS = 'ng-dirty'; var formDirectiveFactory = function(isNgForm) { return function() { var formDirective = { restrict: 'E', require: ['form'], compile: function() { return { pre: function(scope, element, attrs, ctrls) { var form = ctrls[0]; var $addControl = form.$addControl; var $removeControl = form.$removeControl; var controls = []; form.$addControl = function(control) { controls.push(control); $addControl.apply(this, arguments); } form.$removeControl = function(control) { arrayRemove(controls, control); $removeControl.apply(this, arguments); } form.$setPristine = function() { element.removeClass(DIRTY_CLASS).addClass(PRISTINE_CLASS); form.$dirty = false; form.$pristine = true; angular.forEach(controls, function(control) { control.$setPristine(); }); } }, }; }, }; return isNgForm ? angular.extend(angular.copy(formDirective), {restrict: 'EAC'}) : formDirective; }; } var ngFormDirective = formDirectiveFactory(true); var formDirective = formDirectiveFactory(); angular.module('resettableForm', []). directive('ngForm', ngFormDirective). directive('form', formDirective). directive('ngModel', function() { return { require: ['ngModel'], link: function(scope, element, attrs, ctrls) { var control = ctrls[0]; control.$setPristine = function() { this.$dirty = false; this.$pristine = true; element.removeClass(DIRTY_CLASS).addClass(PRISTINE_CLASS); } }, }; }); })(angular); 

Etapa 2: forneça um método no seu controlador que redefina o modelo

Por favor, esteja ciente de que você deve redefinir o modelo quando você redefine o formulário. No seu controlador você pode escrever:

 var myApp = angular.module('myApp', ['resettableForm']); function MyCtrl($scope) { $scope.reset = function() { $scope.form.$setPristine(); $scope.model = ''; }; } 

Etapa 3: inclua esse método no seu modelo HTML

 
(Required, but no other validators)

Field is required

Pristine: {{form.$pristine}}

Eu acho que vale a pena mencionar que em versões posteriores do Angular (por exemplo, 1.1.5), você pode chamar $setPristine no formulário.

 $scope.formName.$setPristine(true) 

Isso definirá todos os controles de formulário para o estado original também.

FormController. $ SetPristine

EDIT … Estou removendo minha resposta antiga, pois não era adequada.

Na verdade, acabei de me deparar com essa questão e aqui estava a minha solução: eu fiz um método de extensão para angular. Eu fiz isso seguindo um pouco do que $ scope.form. $ SetValidity () estava fazendo (ao contrário) …

Aqui está uma demo plnkr em ação

Aqui está o método auxiliar que eu fiz. É um hack, mas funciona:

 angular.resetForm = function (scope, formName, defaults) { $('form[name=' + formName + '], form[name=' + formName + '] .ng-dirty').removeClass('ng-dirty').addClass('ng-pristine'); var form = scope[formName]; form.$dirty = false; form.$pristine = true; for(var field in form) { if(form[field].$pristine === false) { form[field].$pristine = true; } if(form[field].$dirty === true) { form[field].$dirty = false; } } for(var d in defaults) { scope[d] = defaults[d]; } }; 

Espero que isso seja útil para alguém.

Seus campos de formulário devem estar vinculados a uma variável dentro do seu escopo $. Você pode redefinir o formulário redefinindo as variables. Deve ser provavelmente um único object como $ scope.form.

Vamos dizer que você tem um formulário simples para um usuário.

 app.controller('Ctrl', function Ctrl($scope){ var defaultForm = { first_name : "", last_name : "", address: "", email: "" }; $scope.resetForm = function(){ $scope.form = defaultForm; }; }); 

Isso funcionará muito bem, desde que seu html se pareça com:

 

Talvez eu não esteja entendendo a questão aqui, então se isso não resolver sua pergunta, você poderia explicar por quê?

Aqui encontrei uma solução para colocar o From em seu estado original.

 var def = { name: '', password: '', email: '', mobile: '' }; $scope.submited = false; $scope.regd = function (user) { if ($scope.user.$valid) { $http.post('saveUser', user).success(function (d) { angular.extend($scope.user, def); $scope.user.$setPristine(true); $scope.user.submited = false; }).error(function (e) {}); } else { $scope.user.submited = true; } }; 

Apenas escreva angular.extends (src, dst) , de modo que o object original apenas estenda o object em branco, que aparecerá como em branco e o restante será o padrão.

Usando uma diretiva externa e muita jquery

 app.controller('a', function($scope) { $scope.caca = function() { $scope.$emit('resetForm'); } }); app.directive('form', function() { return { restrict: 'E', link: function(scope, iElem) { scope.$on('resetForm', function() { iElem.find('[ng-model]').andSelf().add('[ng-form]').each(function(i, elem) { var target = $(elem).addClass('ng-pristine').removeClass('ng-dirty'); var control = target.controller('ngModel') || target.controller('form'); control.$pristine = true; control.$dirty = false; }); }); } }; }); 

http://jsfiddle.net/pPbzz/2/

O caminho mais fácil: basta passar o formulário para a function do controlador. Abaixo do formulário “myForm” é referenciado por isso , que é equivalente ao $ escopo.

 

O controlador:

 function MyController(MyService) { var self = this; self.myFormValues = { name: 'Chris' }; self.doSomething = function (form) { var aform = form; MyService.saveSomething(self.myFromValues) .then(function (result) { ... aform.$setPristine(); }).catch(function (e) { ... aform.$setDirty(); }) } }