Ripristina il modulo allo stato pristine (AngularJS 1.0.x)

Una funzione per ripristinare i campi modulo allo stato pristine (ripristino stato sporco) si trova sulla tabella di marcia per AngularJS 1.1.x. Sfortunatamente tale funzione non è presente nell’attuale versione stabile.

Qual è il modo migliore per ripristinare tutti i campi modulo al loro stato originario iniziale per AngularJS 1.0.x.?

Mi piacerebbe sapere se questo è risolvibile con una direttiva o altra soluzione semplice. Preferisco una soluzione senza dover toccare le sorgenti originali di AngularJS. Per chiarire e dimostrare il problema, un link a JSFiddle. http://jsfiddle.net/juurlink/FWGxG/7/

La funzionalità desiderata è nella Roadmap : http://blog.angularjs.org/2012/07/angularjs-10-12-roadmap.html
Richiesta di funzionalità – https://github.com/angular/angular.js/issues/856
Soluzione proposta Pull request – https://github.com/angular/angular.js/pull/1127

Aggiornato con ansible soluzione

Soluzione abbastanza buona?

Ho appena capito che posso ricompilare la parte HTML e rimetterla nel DOM. Funziona e va bene per una soluzione temporanea, ma anche come @blesh menzionato nei commenti:

I controller dovrebbero essere usati solo per la logica di business, non per DOM!

E nel mio controller su resetForm() :

  • Salva l’originale HTML non toccato
  • Ricompila l’HTML originale salvato
  • Rimuovi il modulo corrente dal DOM
  • Inserisci il nuovo modello compilato nel DOM

Il JavaScript:

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

Soluzione senza soluzione alternativa

Ho trovato una soluzione che utilizza AngularJS senza alcuna soluzione. Il trucco qui è usare la capacità di AngularJS per avere più di una direttiva con lo stesso nome.

Come altri hanno accennato c’è in realtà una richiesta di pull ( https://github.com/angular/angular.js/pull/1127 ) che è entrata nel ramo 1.1.x di AngularJS che consente il reset dei moduli. Il commit a questa richiesta pull altera le direttive ngModel e form / ngForm (mi sarebbe piaciuto aggiungere un link ma StackOverflow non vuole che aggiunga più di due link).

Ora possiamo definire le nostre direttive ngModel e form / ngForm ed estenderle con la funzionalità fornita nella richiesta pull.

Ho avvolto queste direttive in un modulo AngularJS denominato resettableForm. Tutto quello che devi fare è includere questo modulo nel tuo progetto e la tua versione di AngularJS 1.0.x si comporta come se fosse una versione 1.1.x di Angular a questo proposito.

” Una volta effettuato l’aggiornamento a 1.1.x non è nemmeno necessario aggiornare il codice, basta rimuovere il modulo e il gioco è fatto! ”

Questo modulo passa anche tutti i test aggiunti al ramo 1.1.x per la funzionalità di reimpostazione del modulo.

Puoi vedere il modulo che funziona in un esempio in un jsFiddle ( http://jsfiddle.net/jupiter/7jwZR/1/ ) che ho creato.

Passaggio 1: includere il modulo resettableform nel progetto

 (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); 

Passaggio 2: fornire un metodo sul controller che reimposta il modello

Si prega di essere consapevole del fatto che è necessario ripristinare il modello quando si reimposta il modulo. Nel tuo controller puoi scrivere:

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

Passaggio 3: includi questo metodo nel modello HTML

 
(Required, but no other validators)

Field is required

Pristine: {{form.$pristine}}

Penso che valga la pena ricordare che nelle versioni successive di Angular (ad esempio 1.1.5), è ansible chiamare $setPristine nel modulo.

 $scope.formName.$setPristine(true) 

Questo imposterà anche tutti i controlli del modulo sullo stato originario.

FormController. $ SetPristine

EDIT … Sto rimuovendo la mia vecchia risposta, in quanto non era adeguata.

In realtà mi sono imbattuto in questo problema e qui è stata la mia soluzione: ho realizzato un metodo di estensione per angular. L’ho fatto seguendo un po ‘di cosa $ scope.form. $ SetValidity () stava facendo (al contrario) …

Ecco una demo di plnkr in azione

Ecco il metodo di supporto che ho creato. È un hack, ma funziona:

 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]; } }; 

Spero che questo sia utile a qualcuno.

I campi del modulo devono essere collegati a una variabile all’interno del tuo $ scope. È ansible ripristinare il modulo reimpostando le variabili. Probabilmente dovrebbe essere un singolo object come $ scope.form.

Diciamo che hai un modulo semplice per un utente.

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

Questo funzionerà benissimo a patto che il tuo html assomigli a:

 

Forse non sto capendo il problema qui, quindi se questo non risolve la tua domanda, potresti spiegare perché esattamente?

Qui ho trovato una soluzione per mettere il da al suo stato originario.

 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; } }; 

Basta scrivere angular.extends (src, dst) , in modo che l’object originale si limiti semplicemente all’object vuoto, che apparirà come vuoto e che tutti sono predefiniti.

Utilizzando una direttiva esterna e un sacco di 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/

Il modo semplice: basta passare il modulo nella funzione controller. Sotto il modulo “myForm” viene fatto riferimento da questo , che è equivalente a $ scope.

 

Il controller:

 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(); }) } }