forms.$valid showing true, but prints out as false - javascript

I have a strange error and I am not sure what's happening.
When I check an object, I can see that the $valid tag is set to true (and $invalid shows false). But when I print out just that tag (such as object.$valid) it prints false (and object.$invalid prints true).
$scope.$watch('ctrl.form', form => {
console.log('The form is set to: ', form);
console.log('The form is valid: ', form.$valid);
});
Does anyone know why this might be happening?

I suspect the issue is, the values are still updating in that function; it is watching for a change in the value, but still hasn't applied the changed values. This can make your code in that handler unpredictable.
Since you mention applying the scope throws the "in progress" error, that seems to be valid (the digest is still working). This code frag checks for an in-progress digest and sidesteps it if necessary.
if ( ! $scope.$$phase ) {
$scope.$apply ();
}
Note that "$$" vars in Angular were "private". You could still access them but you're not "supposed" to. This does however have the benefit of not appearing as randomly vague as a zero timeout.
Alternatively, as you've already seen, a 0 timeout can force an update. That's a hack, but it does work and I've seen it used a few times.
Lastly, one of the lifecycle events may be a better choice for these traces, such that you know you're tracing information in the natural flow of the component, where digests are predictable.
Regarding that lifecycle hook, if you're using 1.5 (the last paragraph seems to fit right here and is probably what you want):
New: $onChanges
This new hook is similar to ng2’s ngOnChanges. It is called whenever one way bindings are updated, with a hash containing the changes objects.
Prior to this hook you sometimes had to use a $watch in order to do some work whenever a value you’re bound to changes. Using this hook makes things clearer and removes the need to introduce a watch and a dependency on $scope.

Related

Zustand state consistency and timing during an event

Ok, here's a puzzler. I have a select input and I'm using Zustand for state. I'm seeing inconsistent state and not getting something I suspect.
It looks like this.
const handleSortChange = async (event) => {
// set a state variable
setSort(event.value)
// do a network call using sortBy and other things
// the call is wrong when using sortBy and I'll replace
// this bug with console.log statements below ...
}
There are two values for the select: "one" and "two".
If I console.log this stuff out, I see the problem and the bug. I can't use the state variable inside of this function. It doesn't await, resolve or behave the way I think it will.
So for my select, if I flip between one and two, I get this funny behavior:
const handleSortChange = async (event) => {
// set a state variable
setSort(event.value) // this sets sortBy
console.log(event.value)
console.log(sortBy) // this is the zustand state variable that is in scope
// I expect these would be the same, but they aren't! :O
}
The console.log output looks like this when switching from "one" to "two" on the select input.
two // event.value
one // the in-scope zustand variable sortBy as a read after the set
When switching to "two" on the select, I get the opposite but these variables aren't the same?
one // event.value
two // the set variable sortBy
When switching to "one" on the select. Because something isn't consistent or resolving like I think it is.
I thought that the zustand state variable would be consistent (especially when I add await and eslint is telling me that await does have effect for this function). This isn't an issue for me right now because I can use the parameter for everything I need. But I just feel like I'm missing something big here and I hope that Zustand isn't going to gotcha me when I need to rely on a state change or consistent store somewhere.
This seems to be the same issue and behavior that React has with setState. With setState in React you wouldn't do this even though this is a common trap. The value is not updated immediately, this way of thinking does not work for a concurrent GUI.
https://twitter.com/acemarke/status/1389376376508227592
In the case of Zustand, it might not even have a callback function to fire after set is called. In other words, this isn't going to work at this time.

Firebase/AngularFire performance issues causing page to become unresponsive? $watch at fault?

I've built a site with angularfire and I've noticed that as the site is left open it begins to lag and eventually freezes the browser.
Is there a way I can trace this to the source to see what's causing it?
It's very likely this double watch function but I can't seem to get the list to sort properly and repopulate when I change .start() and .end() parameters on my $firebase array.
scope.$watch(function(){
scope.list.$watch(updateList);
return scope.list;
}, updateList);
Seems to be related to the nesting. The following works much better. Can anyone please explain why I need to have two $watches setup?
scope.list.$watch(updateList);
scope.$watch(function(scope){
return scope.list;
}, updateList);
As written, this code will recursively establish listeners, increasing the resource usage each time there is a change in scope.
It's unclear why you've chosen to watch both scope and the list's $watch method, but only one of these should be necessary.
list.$watch(function() {
// do whatever needs to be done when the list changes
});
Also, updateList implies that you're changing the list or making copies of it. If you are changing the list inside a $watch event, that's going to trigger more watch events. If you're making copies of the list, those are probably unnecessary.
More context about the use case and end goal could help with specifics.
I think you are misunderstanding how to use $watch. The correct syntax would be.
scope.$watch('list', updateList);
Alternatively,
scope.$watch('list', function(newValue, oldValue) {
if (someConditional) {
updateList()
}
});
See for more details https://docs.angularjs.org/api/ng/type/$rootScope.Scope#$watch

$interval's invokeApply parameter does not change anything

From the angular's documentation of $interval service:
invokeApply (optional) boolean: If set to false skips model dirty checking, otherwise will invoke fn within the $apply block.
Which can lead us to a conclusion that $rootScope.$apply wouldn't be called if I set invokeApply as false.
However, from the source of $interval I learned that deferred.notify is called each tick, which makes sense. What does not, is the fact that during deferred.notify execution $rootScope.$evalAsync is called, which in order calls $rootScope.$digest. So all the dirty checking still happens. Am I missing something here?
Bug already filed!
https://github.com/angular/angular.js/pull/5903
You are missing nothing

Inconsistent jQuery each() behavior with unexplainable fix

I'm writing a plugin based on this handy template for class-based CoffeeScript jQuery plugins: https://gist.github.com/rjz/3610858
Everything works pretty well. However, there is some unexpected behavior at the end when I register the plugin:
$.fn.extend markdownAsides: (option, args...) ->
#each ->
$this = $(this)
data = $this.data('markdownAsides')
if not data?
$this.data 'markdownAsides', (data = new MarkdownAsides(this, option))
if typeof option is 'string'
data[option].apply(data, args)
data # Plugin breaks without this line
Before I added that final line (a solution I discovered purely on accident), the initial construction of the plugin worked fine, but on successive method calls, the jQuery each loop sometimes failed to iterate through every element.
Checking this.size() outside the each loop returned the correct value, and checking individual elements outside the loop also looked fine. But inside the loop, elements would sometimes be skipped, in a pattern I could not discern.
Like I said, the problem is fixed by adding the final line. (Perhaps the return value of the function being passed to each matters somehow?) My question isn't "how do I fix this?" but "why does this work?"
Returning false from the callback function passed to each will break out of the loop. I haven't verified but perhaps jQuery will also break on any falsey value except undefined.
Since in CoffeeScript there's an implicit return, you were possibly returning something falsey or even false from the callback depending on the operation performed in it.
To avoid any issues, just change data for true at the end.

A "too much recursion" error in Firefox only sometimes?

I have a pretty simple thing I'm doing with javascript and basically only sometimes will javascript give me a "too much recursion" error.
The code in question:
if(pageLoad===undefined){
var pageLoad=function(){};
}
var pageLoad_uniqueid_11=pageLoad;
var pageLoad=function(){
pageLoad_uniqueid_11();
pageLoad_uniqueid_12();
};
var pageLoad_uniqueid_12=function(){
alert('pageLoad');
};
$(document).ready(function(){
pageLoad();
});
(yes I know there are better way of doing this. This is difficult to change though, especially because of ASP.Net partial postbacks which aren't shown).
Anyway, when the too much recursion error happens, it continues to happen until I restart Firefox. when I restart Firefox it all works as normal again. How do I fix this?
I've also made a jsbin example
Update
Ok I've found out how to reliably reproduce it in our code, but it doesn't work for the jsbin example. If I create a new tab and go to the same page(have two tabs of the same address) and then refresh the first tab two times then I get this error consistently. We are not using any kind of session or anything else that I can think of that could cause such a problem to only occur in one tab!
Update 2
Not as reliable as I thought, but it definitely only occurs when more than one tab of the same page is open. It'll occur every few reloads of one of the tabs open
I've also updated my code to show an alert when pageLoad(the if statement) is initially undefined and when it is initially defined. Somehow, both alerts are showing up. This code is not duplicated in the rendered page and there is no way that it is being called twice. It is in a top level script element not surrounded by a function or anything! My code ends up looking like
if(pageLoad===undefined){
var pageLoad=function(){};
alert('new');
} else {
alert('old');
}
The code in question -- by itself -- should never result in an infinite recursion issue -- there is no function-statement and all the function objects are eagerly assigned to the variables. (If pageload is first undefined it will be assigned a No-Operation function, see next section.)
I suspect there is additional code/events that is triggering the behavior. One thing that may cause it is if the script/code is triggered twice during a page lifetime. The 2nd time pageload will not be undefined and will keep the original value, which if it is the function that calls the other two functions, will lead to infinite recursion.
I would recommend cleaning up the approach -- and having any issues caused by the complications just disappear ;-) What is the desired intent?
Happy coding.
This is just some additional info for other people trying to look for similar "too much recursion" errors in their code. Looks like firefox (as an example) gets too much recursion at about 6500 stack frames deep in this example: function moose(n){if(n%100 === 0)console.log(n);moose(n+1)};moose(0) . Similar examples can see depths of between 5000 and 7000. Not sure what the determining factors are, but it seems the number of parameters in the function drastically decrease the stack frame depth at which you get a "too much recursion" error. For example, this only gets to 3100:
function moose(n,m,a,s,d,fg,g,q,w,r,t,y,u,i,d){if(n%100 === 0)console.log(n);moose(n+1)};moose(0)
If you want to get around this, you can use setTimeout to schedule iterations to continue from the scheduler (which resets the stack). This obviously only works if you don't need to return something from the call:
function recurse(n) {
if(n%100 === 0)
setTimeout(function() {
recurse(n+1)
},0)
else
recurse(n+1)
}
Proper tail calls in ECMAScript 6 will solve the problem for some cases where you do need to return something from calls like this. Until then, for cases with deep recursion, the only answers are using either iteration, or the setTimeout method I mentioned.
I came across this error. The scenario in my case was different. The culprit code was something like this (which is simple concatenation recessively)
while(row)
{
string_a .= row['name'];
}
I found that JavaScript throws error on 180th recursion. Up till 179 loop, the code runs fine.
The behaviors in Safaris is exactly the same, except that the error it shows is "RangeError: Maximum call stack size exceeded." It throws this error on 180 recursion as well.
Although this is not related to function call but it might help somebody who are stuck with it.
Afaik, this error can also appear if you state a wrong parameter for your ajax request, like
$.getJSON('get.php',{cmd:"1", elem:$('#elem')},function(data) { // ... }
Which then should be
elem:$('#elem').val()
instead.
This will also cause the "too much recursion" issue:
class account {
constructor() {
this.balance = 0; // <-- property: balance
}
set balance( amount ) { // <-- set function is the same name as the property.
this.balance = amount; // <-- AND property: balance (unintended recursion here)
}
}
var acc = new account();
Using unique names is important.
Ok, so why is this happening?
In the set function it isn't actually setting the property to amount, instead it's calling the set function again because in the scope of the set function it is the same syntax for both setting the property AND calling the set function.
Because in that scope this is the same as account and (account OR this).balance = amount can both call the set function OR set the property.
The solution to this is to simply change the name of either the property or the set function in any way (and of course update the rest of the code accordingly).

Categories