Skip to content
This repository has been archived by the owner on Jul 1, 2020. It is now read-only.

validation of forms inside ng-repeat #26

Closed
diatoz opened this issue Apr 18, 2015 · 15 comments
Closed

validation of forms inside ng-repeat #26

diatoz opened this issue Apr 18, 2015 · 15 comments

Comments

@diatoz
Copy link

diatoz commented Apr 18, 2015

http://plnkr.co/edit/WSjjdpVC9ck3NUw7iuKy?p=preview

I have run into angular scope issues while trying to apply validation on forms inside ng-repeat.
Since i am creating the forms as well as the fields dynamically i am assigning the form name dynamically. Now i know that ng-repeat creates an isolated scope and i feel that, that is the reason why on calling validation on the form it is giving me error that the form object is not valid since the form exits inside the isolated scope of ng-repeat and not on the controller scope.
My problem is how do i share the scope in this situation. I have bumped into a couple of solutions but nothing seems to work. Was hoping maybe I could get some help here..

@ghiscoding
Copy link
Owner

This is a though one but so far, I manage to find the validationSummary inside the child scope. I get the angular element with the form name given in your for loop and then get the scope() from that object, then I can finally pass that to the checkFormValidity() without it complaining.. like so:

$scope.validate=function(){
      for(var key in $scope.items){
        var formName=$scope.items[key].formName;
        var form1 = angular.element(document.querySelector('[name="'+formName+'"]'));
        var childScope = form1.scope();
        console.debug(childScope[formName]);
        if(new validationService().checkFormValidity(childScope[formName]))
          alert("form "+formName+" is valid");
        else
          alert("form "+formName+" is invalid");
      }
  };

but the problem is that you need the Debug mode enabled, which is a mode you can disable for performance wise in Angular1.3+... See it here: Disabling Debug Data

So I manage to find the $validationSummary inside that child scope, but I did not go further to try to display the errors or anything, you could try and see what happen... Let me know

@diatoz
Copy link
Author

diatoz commented Apr 19, 2015

I added your code and also made the validation rule to be applied dynamically http://plnkr.co/edit/WSjjdpVC9ck3NUw7iuKy?p=preview and have some observations
-after checking for form validity through validate() the last field with required rule remains in error state even after adding text to it
-if you remove the required rule from the last field in form2 the form's validity through validate() comes as valid even though the first required field is not filled

i feel the validation fails for the last required field consistently because of which the form's validation is not calculated correclty...

@ghiscoding
Copy link
Owner

Well I'm sorry, it's hard for to help you debug that one, I rarely have so much dynamic forms. If you find a problem with regular code then I can help you for sure but something that is dynamic is harder to debug. I would suggest you to try using the non-minified code if you want to try debugging it.

@diatoz
Copy link
Author

diatoz commented Apr 20, 2015

I'm working on something with dynamic forms and need to apply validation on those forms too. But, using your framework, validation keeps failing for the last required field and other than that validationservice's checkformvalidity() doesn't show error messages on fields. I can try to debug as you suggested using the non-minified code but as you have developed it ,you have a better understanding of the code rather than me.
Do you have any guess as to where the framework would be failing when validating dynamic forms and fields?
Meanwhile I'll also keep trying to find out and will keep you posted..

@ghiscoding
Copy link
Owner

I made an update to my code last night which seems to have broke even your last code. What I can tell you is that the checkFormValidity() works in combo with the $validationSummary and the summary is empty then your form validity becomes valid, that is how I coded it. Also the summary is saved in 2 locations, the parent $scope and the $scope.form1 (if found) and in your particular case it doesn't seem to exist in any of them which is why it's failing. So the best would be to try debugging why or where does the summary save the failures and in my code that portion happens in the addToValidationSummary(). Not sure when I'll have time to debug it, but if you have time yourself that would help.

@ghiscoding
Copy link
Owner

Alright, I made a copy of your plunker to my local code (it will be under the folder "more-examples") and debug everything, I found something that now seem to work but I need to do more much more tests just to make sure that I don't break anything else. It's getting late, so I'll go to bed, I will probably get something working tomorrow after all my tests are done.

In the mean time, you should try to find another alternative to this piece of code:

var form1 = angular.element(document.querySelector('[name="'+formName+'"]'));
var childScope = form1.scope();

Angular does not recommend finding the scope that way, as it is written in the documentation:

Methods

  • scope() - retrieves the scope of the current element or its parent. Requires Debug Data to be enabled.

@diatoz
Copy link
Author

diatoz commented Apr 21, 2015

I got the code wokring http://plnkr.co/edit/6HwgcYZpy4fgG0gQeQWQ?p=preview
when i added another form field outside ng-repeat i found that the validation summary showed this
interpolationfailed

then i realized that interpolation is failing for the dynamic fields inside ng-repeat and since your validation framework depends on the element name to validate it, it was failing
Adding this directive as suggested in http://stackoverflow.com/questions/21455695/angularjs-dynamic-form-field-validation/21457121#21457121

app.directive("dynamicName",function($compile){
return {
restrict:"A",
link:function(scope,element,attrs){
element.attr('name', scope.$eval(attrs.dynamicName));
element.removeAttr("dynamic-name");
$compile(element)(scope);
}
};
});

added the name to the field and then compiled it during linking. With this the validation is able to find the element using name and validates it :)

@gkalpak
Copy link

gkalpak commented Apr 21, 2015

@ghiscoding, validationCommon is unable to handle dymanic field-names (which are supported in Angular 1.3). E.g. trying to use <input name="{{xyz}}" ... /> will result in the field being registered as {{xyz}} instead of the result of the interpolation.

From a quick look, you seem to be using elm.attr('name') at a point in time where it has not yet been updated with the result of the interpolation (i.e. it is still {{xyz}}). You could/should use attrs.name instead which has the correct value and should be more efficient.

As a sidenote, Angular is able to handle fully dynamic names (e.g. a fields name changing at any time and as many times as we wish). It might be of little value and not worth the trouble trying to support this, but it would be very useful to at least support interpollated names (which are often used for ngRepeated fields).

@ghiscoding
Copy link
Owner

Good, I will consider your approach... I was actually changing my code to use the $interpolate because of another Dynamic Form issue #26 that is open. I have some code change that seems to be working for dynamic names and was going to test everything tonight to make sure nothing is broken. Using your approach though might not always work with my Service implementation, I'll have to look at that.

Thanks for the info, you should expect a code commit later tonight. :)

ghiscoding added a commit that referenced this issue Apr 22, 2015
- Added sample of issue #26
- Fixed issue #26 - validation of dynamic forms inside ng-repeat
- Fixed again issue #28 - unbind all 'blur' in cancelValidation() might
affect other modules.
@ghiscoding
Copy link
Owner

I push the code (v1.3.20) wish should fix your Dynamic Forms with ng-Repeat. I also re-created your plunker in the folder more-examples with the name of dynamicFormIndex.html, which is what I used for troubleshooting your problem.

That should fix it. Enjoy it :)

@diatoz
Copy link
Author

diatoz commented Apr 22, 2015

The plunker http://plnkr.co/edit/WSjjdpVC9ck3NUw7iuKy?p=preview is not working for some time. Its referring to your git repo for validation js. Previously you had mentioned that you had committed the required changes for this issue but it seems its still not fixed.
With an old version (version 1.3.15) of your validation code this works but fails for your latest one 1.3.20.

@ghiscoding
Copy link
Owner

I copied the code from your plunker to recreate a sample in the more-examples folder, your original plunker has couple of issues here and there, so instead of trying to debug that, download my whole project and in the more-examples folder run the dynamicFormIndex.html and as I mentioned you earlier, that one does work, so please use that instead.

@ghiscoding
Copy link
Owner

oh and by the way, your Plunker does not work because you are missing the $translate configuration. I got it working but I will not update it as I want you to use the code in the more-examples folder, it's easier to work with.

ghiscoding added a commit that referenced this issue Jun 3, 2015
- Added possibility to use own isolated scope (issue #37 and #26).
- Fixed an implementation issue found from last revision (issue #35).
- Fixed email validation (issue #38).
- Fixed a performance issue found with onBlur which would run as much
validations as there was characters inside the input when onBlur was
called (abcdef => would make 6 validations) and this was extremely
costly with a Remote validation call.
- Update the code of Remote validation to also accept the "As" alias
"remote:vm.customRemoteValidation".
- Finally added and updated a few Protractor tests to cover all of the
above and more.
@ghiscoding
Copy link
Owner

I added a new functionality see the Wiki - Isolated Scope and this also simplifies the original code I gave you, no more hacking to find the scope and all that weird way of coding. You can now call directly the checkFormValidity(), you only need to explicitly define the property isolatedScope inside the global options, so your code is now much simpler:

  // redefine which scope to use inside the Angular-Validation
  $scope.$validationOptions = { isolatedScope: $scope };

  $scope.validate=function() {
    for(var key in $scope.items) {
      var formName=$scope.items[key].formName;

      if(new validationService().checkFormValidity($scope[formName])) {
        $scope[formName].isValid = true;
      }
      else {
        $scope[formName].isValid = false;
      }
    }
  };

and the bonus is that you can now also disable the debug mode... $compileProvider.debugInfoEnabled(false); and it will still work and that wasn't the case before.

@diatoz
Copy link
Author

diatoz commented Jun 7, 2015

@ghiscoding great work 👍

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants