My use case :
I have a multi step form using ui-router like in the plunkr below. I use ng-form to validate information provided by AngularJS, like $valid, $dirty etc.
After each click on the "Next section" button, I send the form data to the server in order to retrieve it, in case the user quits the form before finishing.
If the user submits the first step twice, I ONLY send the edited data (if the $dirty value is true). All of this is not in the plunkr, I chose to show you a simple form, but my form can contain a hundred fields (radio, checkbox, input, select etc.).
The steps to reproduce the issue (plunkr) :
myMultiStepForm.interests.xbox.$dirty = true
myMultiStepForm.interests.xbox.$dirty = false
Why is $dirty value changed to false? I guess it's because the <ng-form>
is displayed again and all validation data is reset.
Is there a way to avoid this ? Or maybe something other than <ng-form>
to handle validation of subsets of fields ?
This is the plunkr : http://plnkr.co/edit/WclqVgiBvUXlsGdSCcj0?p=preview
When you link a form or any controller inside it, it always starts out as $pristine
. The reason is that the models like formData.type
simply have some values, angular has no way to know that those values were the default state, coming from the server, or are the result of previous user interaction; they are a simple string
or something without this kind of metadata attached.
To achieve what you want, you have to manually track the $dirty
state across state transitions, and apply $setDirty
on the form when needed.
Here is a quick example, adding a controller to the form step pages, which saves the form state on exit (to a shared service instance, you could add this via resolve
too) and restores it at construction. The current formPage
is injected via a default parameter value so that the same controller can be used for all steps.
// router:
$stateProvider.state('form.interests', {
url: '/interests',
controller: 'FormStepController',
params: { formPage: 'interests'}
templateUrl: 'form-interests.html'
})
// state
angular.value("formDirtyState", {});
// controller
angular.controller("FormStepController", function($scope, formDirtyState, $stateParams) {
var formPage = stateParams.formPage;
for(var formField in $scope.myMultiStepForm[formPage]) {
if(formDirtyState[formPage] && formDirtyState[formPage][formField])
$scope.myMultiStepForm[formPage][formField].$setDirty()
}
$scope.$on("$destroy", function() {
for(var formField in $scope.myMultiStepForm[formPage])
formDirtyState[formField] = $scope.myMultiStepForm[formPage][formField].$dirty;
})
})