AngularJS: run after digest loop with $timeout (Safari vs chrome)
AngularJS: run after digest loop with $timeout (Safari vs chrome)
I've written some custom validation code when filling out a form, but need to set the $timeout
to > 100 ms in order to get it to work, and I'm curious to find out why.
$timeout
The required form elements follow this format. I add the "novalidate" class if the input is wrong: (Observe, there's a ton of these elements in the form)
<div class="dottedWrapper" ng-class="novalidate:(newController.jobDescription.length == 0) && newController.formSubmitted">
When submitting the form, I check if any elements has the "novalidate" class and return.
self.formSubmitted = true;
$timeout(function ()
// Validate!
if (document.getElementsByClassName("novalidate").length > 0)
return;
...
, 100); // MUST SET AT LEAST 100ms for it to work in safari
However, this only works if I set the time to about over 100ms in Safari. In chrome, It's only necessary to set it to 1ms.
Correct me if I'm wrong, but here's my thinking, and bare in mind that I'm a newbie in angular:
I set the "self.formSubmitted = true;
" in the beginning. This causes, through the two-way data binding an update on all the divs, since the "formSubmitted" is contained inside the ng-class.
self.formSubmitted = true;
This is done through a digest loop, which means I cannot run the "document.getElementsByClassName("novalidate")
" directly after since the digest loop most run through once and update everything.
document.getElementsByClassName("novalidate")
So... I use the $timeout
, thinking it will let the current digest loop run, and then jump on the next digest loop. At this point, all elements should be updated.
$timeout
I could do this, but there's a ton of elements... With the code I have now, it's just one line to validate.
– BlackMouse
Nov 6 '15 at 7:36
but why you need timeout if you can directly check
newController.jobDescription.length == 0
in js?– Grundy
Nov 6 '15 at 7:39
newController.jobDescription.length == 0
if other programmers see setTimeouts not connected to animation, message timeouts, or game actions, they will make fun of you. figure out something else out, there are many many ways to do this better... as soon as you decide that 100ms is enough, it will start taking 101ms on your bosses computer during a demo, guaranteed.
– dandavis
Nov 6 '15 at 7:41
i don't know the whole story, but it seems to me that one active submit spoils the others. if that's the case, a single busy boolean var/prop that's get and set by all should suffice.
– dandavis
Nov 6 '15 at 7:55
2 Answers
2
Aside from Pixelbits answer (which I totally agree with), you could try replacing $timeout with one of the following;
$evalAsync
$$postDigest
Where the former will trigger a new $digest loop (just like $timeout), and the latter will not.
Even so, I think your best bet would be to harness the built-in input
validation directives. And instead of checking for the existence of a novalidate
class in the DOM, just check the <form>.$valid
property (<form>
gets exposed on your $scope, when given a name
attribute).
input
novalidate
<form>.$valid
<form>
name
Your view would look something like so;
<form name="myForm">
<input ng-model="formData.jobDescription" ng-minlength="1">
</form>
And then in your controller;
// var form = $scope.myForm;
console.log(form.$valid); // true|false
Now, the above suggestion may not work for your use case - We need to see more of your implementation to be able to assist you to a greater extent.
Great! Thanks a lot
– BlackMouse
Nov 6 '15 at 13:28
You're breaking the MVC pattern. Don't - it's bad practice.
Why don't you just do:
if (self.jobDescription.length == 0 && self.formSubmitted)
return;
I could do this, but there's a ton of elements... With the code I have now, it's just one line to validate.
– BlackMouse
Nov 6 '15 at 7:36
@BlackMouse, so why you just not use built-in validation in angular? And anyway you write this code for tons element, why not just move it all to one place?
– Grundy
Nov 6 '15 at 7:49
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
do you need to use the dom to store such info? if you could use JS vars, you would not need to delay, which seems a little janky...
– dandavis
Nov 6 '15 at 7:28