Thanks to visit codestin.com
Credit goes to github.com

Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
refactor(form): use internal counter instead of recursion
  • Loading branch information
linoleum-js committed Jan 16, 2016
commit 4d8c01c458fdaab57e37e082dadf1b3af89a27db
83 changes: 64 additions & 19 deletions src/ng/directive/form.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
var nullFormCtrl = {
$addControl: noop,
$$renameControl: nullFormRenameControl,
$$increasePristine: noop,
$$decreasePristine: noop,
$$updatePristine: noop,
$removeControl: noop,
$setValidity: noop,
Expand Down Expand Up @@ -77,6 +79,7 @@ function FormController(element, attrs, $scope, $animate, $interpolate) {
form.$invalid = false;
form.$submitted = false;
form.$$parentForm = nullFormCtrl;
form.$$pristineChildsCounter = 0;

/**
* @ngdoc method
Expand Down Expand Up @@ -144,6 +147,10 @@ function FormController(element, attrs, $scope, $animate, $interpolate) {
}

control.$$parentForm = form;
// if form was pristine before - it will be after too
if (control.$pristine) {
form.$$pristineChildsCounter++;
}
};

// Private API: rename a form control
Expand Down Expand Up @@ -189,6 +196,10 @@ function FormController(element, attrs, $scope, $animate, $interpolate) {

arrayRemove(controls, control);
control.$$parentForm = nullFormCtrl;

if (control.$pristine) {
form.$$pristineChildsCounter--;
}
};


Expand Down Expand Up @@ -239,6 +250,12 @@ function FormController(element, attrs, $scope, $animate, $interpolate) {
* state (ng-dirty class). This method will also propagate to parent forms.
*/
form.$setDirty = function() {
// see $setPristineBubbling
if (form.$pristine) {
form.$$parentForm.$$decreasePristine();
} else {
form.$$parentForm.$$updatePristine();
}
$animate.removeClass(element, PRISTINE_CLASS);
$animate.addClass(element, DIRTY_CLASS);
form.$dirty = true;
Expand All @@ -261,39 +278,67 @@ function FormController(element, attrs, $scope, $animate, $interpolate) {
* saving or resetting it.
*/
form.$setPristine = function() {
form.$$setPristineSelf();
form.$$setPristineBubbling();
forEach(controls, function(control) {
control.$setPristine();
// since we force pristine state, we don't want nested controls to
// change it
control.$$setPristineCapturing();
});
};

// Private API: Sets the form to its pristine state.
// This method does not affect nested controls.
// This method does not affect nested/parent controls.
form.$$setPristineSelf = function() {
$animate.setClass(element, PRISTINE_CLASS, DIRTY_CLASS + ' ' + SUBMITTED_CLASS);
form.$dirty = false;
form.$pristine = true;
form.$submitted = false;
form.$$parentForm.$$updatePristine();
};

// Private API: update form pristine-ness
form.$$updatePristine = function() {
var isPristine = true,
controlsLength = controls.length,
i;

for (i = 0; i < controlsLength; i++) {
if (!controls[i].$pristine) {
isPristine = false;
break;
}
// Private API: Sets the form to its pristine state.
// Propagates pristine-ness to parent form
form.$$setPristineBubbling = function() {
// propagate only if pristine state was actually changed
if (form.$dirty) {
form.$$parentForm.$$increasePristine();
} else {
// otherwise tell aprent form to calculate current value,
// since it can be changed after adding/removing nested controls.
// The same applies to $setDirty.
form.$$parentForm.$$updatePristine();
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpicking: The above lines can be "summarized" as

var isPristine = controls.every(function(control) { return control.$pristine; });

form.$$setPristineSelf();
};

if (isPristine) {
// All the nested controls are already pristine.
// Set pristine-ness only for the form itself.
form.$$setPristineSelf();
// Private API: Sets the form to its pristine state.
// Propagates pristine-ness to the nested controls
form.$$setPristineCapturing = function() {
form.$$setPristineSelf();
forEach(controls, function(control) {
control.$$setPristineCapturing();
});
};

// Pivate API: nested control become pristine
form.$$increasePristine = function() {
form.$$pristineChildsCounter++;
form.$$updatePristine();
};

// Pivate API: nested control become dirty
form.$$decreasePristine = function() {
form.$$pristineChildsCounter--;
form.$$updatePristine();
};

// Private API: update form pristine-ness
form.$$updatePristine = function() {
if (form.$$pristineChildsCounter === controls.length) {
// since we got update from nested controls, we don't want to
// propagate it to them
form.$$setPristineBubbling();
} else {
form.$setDirty();
}
};

Expand Down
22 changes: 21 additions & 1 deletion src/ng/directive/ngModel.js
Original file line number Diff line number Diff line change
Expand Up @@ -379,11 +379,25 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
* has not been changed from when first compiled.
*/
this.$setPristine = function() {
// propagate only if pristine state was actually changed
if (ctrl.$dirty) {
ctrl.$$parentForm.$$increasePristine();
} else {
// otherwise tell aprent form to calculate current value,
// since it can be changed after adding/removing nested controls.
// The same applies to $setDirty.
ctrl.$$parentForm.$$updatePristine();
}
ctrl.$$setPristineCapturing();
};

// Private API: Sets the control to its pristine state.
// This method does not affect parent form
this.$$setPristineCapturing = function() {
ctrl.$dirty = false;
ctrl.$pristine = true;
$animate.removeClass($element, DIRTY_CLASS);
$animate.addClass($element, PRISTINE_CLASS);
ctrl.$$parentForm.$$updatePristine();
};

/**
Expand All @@ -398,6 +412,12 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
* from when first compiled.
*/
this.$setDirty = function() {
// see $setPristine
if (ctrl.$pristine) {
ctrl.$$parentForm.$$decreasePristine();
} else {
ctrl.$$parentForm.$$updatePristine();
}
ctrl.$dirty = true;
ctrl.$pristine = false;
$animate.removeClass($element, PRISTINE_CLASS);
Expand Down
Loading