Disconnect then add AngularJS form change action status

You can check this out in this jsFiddle: HERE (better to see the new jsFiddle, see the EDIT section of this post)

I think there is a bug in AngularJS, or at least not the expected result. If I disconnect the form, then re-add it, the ng-invalid class will switch to ng-valid to re-add it to the DOM. This leads to the fact that the submit button is even invalid. Of course, I expected that the status of reality will not switch.

I think this is an angular error, but maybe jquery. I could use jquery to check if the form was valid or not, and then it forces the form class, but doesn't seem to work as a valid form, and then has an invalid status. This is rather strange since I don’t know any other workaround without using data for the saved state form before disconnecting it.

So, has anyone already encountered this problem? Is there any method (if possible, using the AngularJS directive) to get rid of this error?

PS: I need to separate the form (and any other elements) in a single page web application so that the DOM is as clean as possible.

EDIT

I made a new jsFiddle that illustrates my problem, separating content from internal site navigation: http://jsfiddle.net/EWVwa/

UPDATE

I came to this workaround (thanks to CaioToOn)

http://plnkr.co/edit/KIgMz2

 var app = angular.module('plunker', []); app.controller('MainCtrl', function($scope) { $scope.name = 'World'; }); app.directive('customValidation', function() { return { require: ['ngModel', '^?form'], link: function(scope, element, attr, ctrls) { console.log(ctrls); var ngModelCtrl = ctrls[0], formCtrl = ctrls[1]; ngModelCtrl.$parsers.push(function(viewValue) { if (viewValue === 'test') { ngModelCtrl.$setValidity('name', true); formCtrl.$setValidity('name', true); return viewValue; } else { ngModelCtrl.$setValidity('name', false); formCtrl.$setValidity('name', false); return undefined; } }); // custom event element.bind('$append', function() { formCtrl && formCtrl.$addControl(ngModelCtrl); /*** TEST for to keep form validation status ***/ formCtrl.$setValidity('name', ngModelCtrl.$valid); //ngModelCtrl.$setValidity('name', ngModelCtrl.$valid); console.log(formCtrl.$valid); }); //binding on element, not scope. element.bind('$destroy', function() { console.log("gone haven"); }); } }; }); 

This requires more tests related to checking multiple inputs. I will definitely update the answer when all tests are completed.

+4
source share
1 answer

The problem arises because the input directive itself removes from form controls when the element is removed from the DOM. Since it does not bind your ngModel and the form controller again, your input is no longer considered by the form.

Basically you have two three options:

  • change the visibility of an element, but not delete it
  • (prefer below) by setting the "relink" function, which will re-add it to the original form
  • fires a custom event on all controls so that they can move.

Changing the visibility of elements means that you will have unnecessary DOM elements in DOMTree. This is not so bad since you still maintain a reference to the $ compilation element, so that it will still participate in the $digest and "DOM" loops.

(After thinking for a while, the new solution is slightly better than this, so do not expose a repeating function) Providing the reink function is rather strange (albeit functional), and it is not the most reliable solution. One way to achieve this is to require a form controller ( require: ['ngModel', '^?form'] ) and bind the return function to the element data:

 element.data('relink', function(){ formCtrl && formCtrl.$addControl(ngModelCtrl); }); 

And when you add the item to the screen again, you need to call all the replication functions of your control:

 $('.controls').data('relink')(); 

See an example here .

It is not very reliable, but can work for your business.

The triggering of a custom event is pretty much the same as the previous one, but you are sending a custom event for all the elements that need to be overwritten. This is more organized, but still not entirely reliable, because the form and other links can also be broken (again, this should be the suffix of your case). Basically listen for a custom event in your directive:

 element.bind('$append', function(){ formCtrl && formCtrl.$addControl(ngModelCtrl); }); 

And after going to the form, just activate a custom event for all controls:

 $('.control').triggerHandler('$append'); 

The reason this is better is because the directive still decides when to rewrite the component, and the event is kind of "general." Here is a working plunker .

As a last jQuery.fn.append you can override jQuery.fn.append and trigger a custom event for all child elements of the element recursively (this is what Angular does when elements are deleted). This is most organized, but it would affect performance in all append calls.

+3
source

All Articles