-
Notifications
You must be signed in to change notification settings - Fork 58
CheckFormValidity and validation-error-to #16
Comments
Ah that is nice to see there's already some persons using the code I pushed in the weekend haha, so quick :) The code that I made was actually to add a functionality that was requested by another user, I did not even try it in my own project yet (apart from this Git sample) and might not be bulletproof, it is at the very early stage (last weekend). My next step was to actually start looking at Protractor for the tons of checks for this kind of project, it is becoming a must with the tons of functionality that this project is starting to be hehe ;) In the mean time, I am home for lunch and I made a very quick test and your patch might at the end, be a much better solution. I made a quick change and test, I'm using only use the Could you try to replace line 110-113 by the following piece of code: if(!!elm && elm.length > 0) {
elm.blur();
} I won't have time to try everything out, lunch time isn't enough, but I would be curious to see if it work completely with your project. Let me know please... and if it does, I would be happy to have a pull request from your side since you found it :) |
I'm off work now, so I won't have access to the code until tomorrow. |
Cool thanks, I'll wait for the pull request update |
After some more testing, this end up not working (at least not with jqLite), it keeps telling me that BUT I believe that I found your problem and actually fixed it an hour ago with another code change that I pushed to correct an issue I found (a73505b) I am assuming that your problem is because you do not have a // before, this will not work without a form name
new validationService().checkFormValidity($scope.form)
// after, this will work with or without a form name
new validationService().checkFormValidity($scope) The reason of why I accept both arguments is because I found that using I tried myself by removing the form name, then using the validation-error-to and use only the $scope as argument, it now works correctly for me. Let me know if that fixes your problem, please note that you will need to get my new code for that to work. |
Thanks. if(!!elm && elm.length > 0) {
ctrl.$setTouched(); // make the element as it was touched for CSS
elm.blur();
} works fine, but I'm running on jquery 1.11, not jqLite. if(!!elm && elm.length > 0) {
ctrl.$setTouched(); // make the element as it was touched for CSS
self.commonObj.updateErrorMsg(obj.$validationSummary[i].message, {valid: false, elm: elm, submitted: true});
} does not work... A small misunderstanding. My form has a name, but there are other forms on the page before my form. document.querySelectorAll('form');
-->
[
<form action="http://...." method="GET">,
<form action="http://...." method="GET" style="display: inline">,
<form name="formName" novalidate method="POST" class="ng-pristine ng-invalid ng-invalid-validation">
] But I do think I might have some sort of scope problem (that's what I get for taking over someone elses project :) ). But I was thinking... The reason that the |
And an added bonus: But with all the validators available in This might be well out of scope for you, but it's an idea :) |
I did a test and it seems to work for me. What I've basically done is add commonObj to validation-common.js: function updateErrorMsg(message, attrs) {
var self = this;
...
...
function addToValidationSummary(self, message) {
...
// if message is empty, remove it from the validation summary
if(index >= 0 && message === '') {
validationSummary.splice(index, 1);
}else if(message !== '') {
var errorObj = { field: elmName, message: message};
...
... To: function updateErrorMsg(message, attrs) {
// attrs.obj - if set should be a commonObj, and can be self
var self = (!!attrs && attrs.obj) ? attrs.obj : this;
...
...
function addToValidationSummary(self, message) {
...
// if message is empty, remove it from the validation summary
if(index >= 0 && message === '') {
validationSummary.splice(index, 1);
}else if(message !== '') {
var errorObj = { field: elmName, message: message, obj: self}; // Add self to summary
...
... validation-service.js: function checkFormValidity(obj) {
....
// loop through $validationSummary and display errors when found on each field
for(var i = 0, ln = obj.$validationSummary.length; i < ln; i++) {
isValid = false;
elmName = obj.$validationSummary[i].field;
elm = angular.element(document.querySelector('[name="'+elmName+'"]:not([disabled]):not([ng-disabled]'));
ctrl = angular.element(elm).controller('ngModel');
if(!!elm && elm.length > 0) {
ctrl.$setTouched(); // make the element as it was touched for CSS
self.commonObj.updateErrorMsg(obj.$validationSummary[i].message, {valid: false, elm: elm, submitted: true});
}
}
return isValid;
} To: function checkFormValidity(obj) {
...
// loop through $validationSummary and display errors when found on each field
for(var i = 0, ln = obj.$validationSummary.length; i < ln; i++) {
isValid = false;
// I've got it all now, so use it
elm = obj.$validationSummary[i].obj.elm;
ctrl = obj.$validationSummary[i].obj.ctrl;
if(!!elm && elm.length > 0) {
ctrl.$setTouched(); // make the element as it was touched for CSS
// send events commonObj to updateError
self.commonObj.updateErrorMsg(obj.$validationSummary[i].message, { valid: false, obj: obj.$validationSummary[i].obj, submitted: true });
}
}
return isValid;
} And last, my own navigationcontroller: ...
self.NextStep = function () {
if (new ValidationService().checkFormValidity($scope.formName)) {
service.nextStep();
}
};
self.PreviousStep = function () {
$scope.formName.$validationSummary = [];
service.previousStep();
};
... |
Wow you've done a lot, and it looks promising. Let me start by explaining why I chose the Service and why I use the $validationSummary inside the Now for the if( typeof elm.blur() === "function() ) {
elm.blur();
else {
// regular code
} Going further in your code suggestion and I believe that you are on the right path with the code change, I like since it doesn't break current code (adding a new piece to the summary object is perfect idea) and would work with jqLite too. I'm about done with my lunch break so I won't be able to test your code before the evening... as I said I like your code, but I just need to test it out with just the Service controller and make sure that it works in both cases. If you have the time to test the Service controller I made too, then I would be happy to have a pull request with the change. As for your own navigationController (wizard), I would also be happy to have it as a sample, if you have time you can create the wizard and store it inside the Thanks.. I will surely look at all your code tonight. |
By the way, in my design I decided to keep $validationSummary in 2 locations, the In your case, you said that you do have a name on it, but the summary does not appear in your $scope, probably because your $scope is new or re-initialize when you change controller? Just a thought... I saw in your code the property |
Lets see: There's a lot of information in this thread now :)
pseudocode
<div ng-app="app" ng-controller="wizardController">
<form name="formName" novalidate>
<div ng-views>
// several views with own controllers
// the validation-directive is also invoked here, on elements in each view
// the wizardController/wizardService decides which view to show and when to show it
</div>
</form>
</div>
This is your code. I'm just making some suggestions. If they work, and you want to include them, great! If not, such is life :) |
Btw. is there a way to show a custom errormessage? |
Already Easter holiday, lucky you, I only have Friday off and it's just Tuesday here :P Thanks for all the info, I will definitely take a look at your code tonight and tomorrow, and from there we will see what we can tweak. I already like what you have suggested so there is big potential to get something working :) For the custom error message, I was actually thinking about creating another function in the Service that is completely independent from everything (the actual updateErrorMsg relies on the fact that you have a global, elm, scope, etc... which isn't always present). I am thinking about adding a new function in the Service that can be called independently, something like |
Sounds good :) Thinking about the possible Look at it like this: index.html <div ng-app="app" ng-controller="wizardController as wiz">
<form name="formName" novalidate>
<div ng-views>
// several views with own controllers
// the validation-directive is also invoked here, on elements in each view
// the wizardController/wizardService decides which view to show and when to show it
</div>
<button name="next" ng-click="wiz.nextStep">
<button name="prev" ng-click="wiz.previousStep">
</form>
</div> wizardController.js self.nextStep = function () {
if (new ValidationService().checkFormValidity($scope.formName)) {
service.nextStep();
}
};
self.previousStep = function () {
$scope.formName.$validationSummary = [];
service.previousStep();
}; As you can see, all our developers need to think about when developing is to determine which field needs validation, and assign it where it's needed. WizardController will be part of our local framework, and will only need to be referenced in. No custom code for each wizard. Edit: I guess what I'm really thinking is that it would be 'messy' if we have to call
<input type="text" name="txt1" validation="required" > //<-- default message
<input type="text" name="txt1" validation="required" validation-error-to="#displayError" > //<-- default message
<input type="text" name="txt1" validation="required" validation-message="Please do stuff">
<input type="text" name="txt1" validation="required" validation-message="Please do stuff" validation-error-to="#displayError"> I don't know how much more work it will be to do that, and I assume it will mean that the service will have to be extended as well... Oh well... It's an idea :) It's late here, and I'm off to bed. Have a nice evening :) |
I added it as you said, it's 3 lines of code and I pushed it online already (without a Revision tag), you can see it here 17f7216 (line 261-264 of common.js) <!-- If any of the 3 validators fail, it will always display "Please do stuff" in all cases -->
<!-- so you will not be able to know if your text is too short or too long, etc... -->
<input type="text" name="txt1" validation="min_len:15|max_len:255|required" validation-message="Please do stuff"> While the alternate text would have the advantage of being associated to that particular validator. There is no limitation in how many validators you put with alternate text, it just looks funny on your definition of it though because it becomes very long... For example: <input type="text" name="txt1" validation="min_len:15|max_len:255|required:Please do Stuff|match:input2:Your password does not match"> As you can see, it's more flexible this way, it's just longer text within the validation attribute. I did not implement it yet, it's much more code implication so maybe over next weekend. If I ever do that one, I would rather do this feature for all validators, not just on the Happy Easter |
Yeah.. I did not think that through, did I :) |
Nice suggestion but if the translate happens after my interpretation then it would fail, the reason is that I already use the pipe As for your other code, I tried it in the Service and it doesn't work properly but it's related to the way I coded the Hopefully will learn Protractor or Jasmine sometime soon, since there is so much to test under this project that is growing by the weeks..haha Talk later, thanks for the feedback and enjoy your Easter :) |
I think that after a lot of code change and fixes, I made everything working and more. I took your concept of using the object within the Some new functions have been added that might interest you in the commonService, there is 3 new ones: I also added the alternate text, the translate also work with it, you can check the README in the "available validators" section I am explaining how to use it, the html template also has 1 alternate text in both the Directive and Service, you can check each of them, it's on the Hope that everything works for you... You could also favorite my project in Github ;) See ya |
Wow, you've been busy :) |
- Added option to display only last error message instead of all messages at once - Added new template to display ngRepeat examples, also help troubleshooting the follwoing bug. - Fixed a bug (probably linked to issue #16) where changing route on View/Controller would make the ValidationSummary fail when coming back to original View/Controller, this bug was associated to the fact that the ValidationSummary kept growing from Controller to Controller, now this ValidationSummary is wipe out as soon as we detect a route change.
Hello again, been a long time... I think that I finally found and fixed the original bug you had, I just happen to find it out the hard way. I found out that by changing to another View/Controller the validations would work on both but then coming back to the original View/Controller would make my ValidationSummary misbehaving, after troubleshooting for some hours, I found out the cause being that I never cleared up these 2 important array variables (formElements & validationSummary) and so they kept growing and growing and holding values of previous controllers. As soon as I found out, I put in place a reset a of these 2 variables whenever a route change occurs and that fixed my problem. This is the code that I added in the validation-common.js: // watch on route change, then reset some global variables, so that we don't cary over other controller/view validations
$rootScope.$on("$routeChangeStart", function (event, next, current) {
if (!bypassRootScopeReset) {
formElements = []; // array containing all form elements, valid or invalid
validationSummary = []; // array containing the list of invalid fields inside a validationSummary
}
}); In case the last piece of code is giving you problems, I also added a function to let you bypass this new reset that is now default, you can call the bypass through the service object new validationService().setBypassRootScopeReset(true); And finally, I believe that the function I have troubleshoot my problem with the new template I added to show ngRepeat, trying the first time worked but then going to another template and coming back to this ngRepeat would fail on any subsequent try. So I really believe that my new version of 1.3.23 is fixing your original problem and I referenced it in the commit :) I have reopened this issue and would be really happy to get some feedback. If you have no time to test it out, no worries I will close the issue in a week or so. Thanks again! |
Hi. Good job. |
Awesome, thanks for the feedback, I will leave the function there, it's just couple lines of code. |
I use validation with validation-directive like this
When I try to use
I do not get any error messages.
Removing validation-to-error works. But that does not help me. :)
I figured that it is because validation-common.updateErrorMsg is not instantiated with the correct values for self (specifically self.validatorAttrs) since I define it using validation-directive, but checkFormValidity is in validation-service, of which I have just instantiated a new empty instance.
I have made a hack in checkFormValidity lines 110-113 by changing the following:
to
This I assume is not a good idea, but it will fire the original validators that were registered on the controls...
I am at a loss how to get it to work, or if it is even supposed to work like I want it to :)
tlastad
The text was updated successfully, but these errors were encountered: