I guess this means there is a circular reference somehwere but for the life of me I can't guess how to fix it.
Anyone have any ideas?
http://plnkr.co/edit/aNcBcU?p=preview
Check the debug console in Chrome (for example) and you'll see the error.
The offending line is
scope.map = map;
scope.map is being "$watched" on the controller via
$scope.$watch("options.map", function (map) { ... }, true);
It's because you're comparing for object for equality rather than for reference. Change your $watch statement to this:
$scope.$watch("options.map", function (map) {
if (map === undefined) {
alert("map has no value");
} else {
alert("map is defined");
}
});
I also had this issue and found out that the objects I was comparing had circular references. (Tried JSON.stringify() which threw 'TypeError: Converting circular structure to JSON').
When I edited my object so that it didn't have circular structure, I fixed this problem and compared objects not by reference but by properties value which was what I needed.
The third parameter of $watch function tells how to compare the watched object. False to reference comparing only. True to recursive equality comparing, if an object contains circular references, then over maximum stack size. For example:
var a = {ref:b};
var b = {ref:a};
$scope.$watch('b', function(){
//code here will never called, because stack overflow when comparing the object b.
}, true)
Related
Here is the code for the create method.
create<+S: ____Styles_Internal>(obj: S): $ReadOnly<S> {
// TODO: This should return S as the return type. But first,
// we need to codemod all the callsites that are typing this
// return value as a number (even though it was opaque).
if (__DEV__) {
for (const key in obj) {
if (obj[key]) {
Object.freeze(obj[key]);
}
}
}
return obj;
},
How does this function work and what does the <+ operator do?
create<+S: ____Styles_Internal>(obj: S): $ReadOnly<S> {
Defines a function called create that has a parameter called obj. It is type annotated, using Flow with the following meaning:
The parameter obj is type S as denoted by obj: S
Where S is of type or a subtype of ____Styles_Internal as denoted by <+S: ____Styles_Internal>. + is a variance sigil signifying covariant types are accepted (types which are a subtype, along with the type itself)
The return type is a readonly version of obj as denoted by $ReadOnly<S>
if (__DEV__) {
for (const key in obj) {
if (obj[key]) {
Object.freeze(obj[key]);
}
}
}
for...in iterates over enumerable properties and if the value of the property is truthy, the value is frozen by Object.freeze. The value would normally be an object (see examples from React Native's documentation on stylesheet) so freezing it would prevent the object from being changed. These things only happen when the __DEV__
variable is true, which signifies the code is running in a development environment.
I did not author the code, so I can only speculate why it behaves like this:
This behaviour only occurs in development potentially because it could break production apps, based on the commit message from the author of code:
I don't really know if we have/need any safer way of rolling this out than just landing it. It can break if the object passed to StyleSheet.create is mutated afterwards but that isn't a practice anywhere I've seen.
I don't know why the test for whether to freeze or not is truthiness.
I'm not certain why the objects need freezing but I suspect it's to remove unintended side effects from mutating style objects as React likely compares style objects between renders by reference.
return obj;
},
Returns the object.
Further reading
Covariance and contravariance
Subtyping
I am fetching an array of objects from an RX/JS call from an http backend. It returns an object which I am then trying to work with. I am making changes to this object using a for loop (in this example I am trying the .forEach because I have tried a number of different things and none of them seem to work.
When I run the code, I get a very weird problem. If I return the values of the properties, I get the new values (i.e. correctionQueued returns as true, etc.) but in the very next line, when I return the object, those same values are the same as the original (correctionQueued === false, etc.) HOWEVER, correctionStatus (which does not exist on the original object from http) sets just fine.
I don't understand how
array[index].correctionQueued can return true, but
array[index] returns an object with correctionQueued as false.
After the loop, the original array (checklistCopy) is identical to the object before the forEach loop, except the new property (correctionStatus) is now set, but all properties that I changed that were part of the original object remain as they were.
I have tried using a for of, for in, and .forEach. I have used the index to alter the original array, always the same result. Preexisting properties do not change, new properties are added. I have even tried working on a copy of the object in case there is something special about the object returned from rxjs, but to no avail.
checklistCopy.forEach((checklistItem, index, array) => {
if (checklistItem.crCode.isirName === correctionSetItem) {
array[index].correctionQueued = true;
array[index].correctionValue = mostRecentCorrection.correctionValue;
array[index].correctionStatus = mostRecentCorrection.status;
console.log(array[index].correctionQueued, array[index].correctionValue, array[index].correctionStatus);
console.log(array[index]);
}
}
);
I don't get an error, but I get..
Original object is:
correctionQueued: false;
correctionValue: JAAMES;
--
console.log(array[index].correctionQueued, array[index].correctionValue, array[index].correctionStatus);
true JAMES SENT
but when I print the whole object:
console.log(array[index]);
correctionQueued: false;
correctionValue: JAAMES;
correctionStatus: "SENT'; <-- This is set correctly but does not exist on original object.
console.log(array[index]) (at least in Chrome) just adds the object reference to the console. The values do not resolve until you expand it, so your console log statement is not actually capturing the values at that moment in time.
Change your console statement to: console.log(JSON.stringify(array[index])) and you should discover that the values are correct at the time the log statement runs.
The behavior you are seeing suggests that something is coming along later and changing the object properties back to the original value. Unless you show a more complete example, we can't help you find the culprit. But hopefully this answers the question about why your logs show what they show.
Your output doesn't make sense to me either but cleaning up your code may help you. Try this:
checklistCopy.forEach(checklistItem => {
checklistItem.correctionQueued = checklistItem.crCode.isirName === correctionSetItem;
if (checklistItem.correctionQueued) {
checklistItem.correctionValue = mostRecentCorrection.correctionValue;
checklistItem.correctionStatus = mostRecentCorrection.status;
console.log('checklistItem', checklistItem)
}
}
);
Javascript array value is undefined ... how do I test for that
and
How to check a not-defined variable in JavaScript
these are wrong as far as I'm concerned :
I ONLY get :
when trying to :
console.log(!fromToParameters[7].value.firstInput);
console.log(!!fromToParameters[7].value.firstInput);
console.log(fromToParameters[7].value.firstInput === undefined);
console.log(typeof fromToParameters[7].value.firstInput == 'undefined');
console.log(fromToParameters[7].value.firstInput !== undefined);
console.log(typeof fromToParameters[7].value.firstInput != 'undefined');
but this (the entry exists) works fine :
console.log(!fromToParameters[0].value.firstInput);
console.log(!!fromToParameters[0].value.firstInput);
console.log(fromToParameters[0].value.firstInput === undefined);
console.log(typeof fromToParameters[0].value.firstInput == 'undefined');
console.log(fromToParameters[0].value.firstInput !== undefined);
console.log(typeof fromToParameters[0].value.firstInput != 'undefined');
false
true
false
true
false
true
is it a question of react being different from js? why can't I do the same as in these stackoverflow threads?
UPDATE :
so you cannot point to a missing array element at all.
Check answers below.
I think I'll be using an array.lenght stored in a const that I then check my increment against it within my "for" loop to allow or disallow modifying my array entries on a case-by-case basis.
it's really annoying that you can't just ask js if a damn var of an unexisting array index exists or not.
it seems like this would be straightforward stuff : can't point to the index? then NO. no not this variable nor any other variable exists at this index. end of.
the guys at js definitely should put in a note for adding something as simple as this.
I'm tempted to post my code as I have something that allows for me to do what I want (calling a index with lots of undefineds and getting a object with ""s instead) but it's a bit monstrous.
You should do like this:
console.log(fromToParameters[7] && fromToParameters[7].value.firstInput);
console.log(!!fromToParameters[7] && fromToParameters[7].value.firstInput);
console.log( fromToParameters[7]&& typeof fromToParameters[7].value.firstInput == 'undefined');
I have just added check. So if fromToParameters[7] is undefined or null, your code will not break.
Check for the index first (ex: console.log(!yourArray[x]), then depending if that test passes or fails, access/add the indexes/properties you want.
The setup is the following :
targets = ['green','orange','red']; //targets are in order of priority
sources = ['redalert','blackadder','greenlantern'];
I am trying to make a function that returns the one source element which contains the highest priority target string. In this case, it would be 'greenlantern', as it contains the string 'green', which has higher priority than 'red' found in 'redalert'.
I have done it already using for loops and temp arrays, but I know these manipulations aren't my forte, and my real-life arrays are way larger, so I'd like to optimize execution. I have tried with Lodash too, but can't figure out how to do it all in one step. Is it possible?
The way I see it, it has to :
for each target, loop through sources, if source elem matches target elem, break and return.
but I'm sure there's a better way.
Here's another lodash approach that uses reduce() instead of sortBy():
_.reduce(targets, function(result, target) {
return result.concat(_.filter(sources, function(source) {
return _.includes(source, target);
}));
}, []);
Since targets is already in order, you can iterate over it and build the result in the same order. You use reduce() because you're building a result iteratively, that isn't a direct mapping.
Inside the reduce callback, you can concat() results by using filter() and includes() to find the appropriate sources.
This gets you the sorted array, but it's also doing a lot of unnecessary work if you only want the first source that corresponds to the first target:
_.find(sources, _.ary(_.partialRight(_.includes, _.first(targets)), 1));
Or, if you prefer not to compose callback functions:
_.find(sources, function(item) {
return _.includes(item, _.first(targets));
});
Essentially, find() will only iterate over the sources collection till there's a match. The first() function gets you the first target to look for.
Keeping it very simple:
var sortedSources = _.sortBy(sources, function(source){
var rank = 0
while(rank < targets.length){
if(source.indexOf(targets[rank]) > -1){
break
}else{
rank++
}
}
return rank
})
Sources are now sorted by target priority, thus sortedSources[0] is your man.
I am fairly new to programming, and I'm trying to do some work with arrays, but I'm getting an error that I don't know how to fix. Any help would be great!
Error: 1084: Syntax error: expecting colon before leftbracket.
Source: hockeyPP({hockeyPlayers[i]});
Error: 1084: Syntax error: expecting identifier before rightbrace.
Source: hockeyPP({hockeyPlayers[i]});
function eliminateAbsentees():void{
for(var i:int=0; i<=hockeyPlayers.length; i++){
if(hockeyPlayers[i].attendance==true){
hockeyPP.push({hockeyPlayers[i]});
}
}
}
remove { and } surrounding hockeyPlayers[i]. Why you want to used it in this way?
function eliminateAbsentees():void{
for(var i:int = 0; i <= hockeyPlayers.length; i++){
if(hockeyPlayers[i].attendance == true){
hockeyPP.push(hockeyPlayers[i]);
}
}
}
As mentioned by Azzy Elvul, your issue was the curly brackets ( "{}" ) around the array item. You'll see curly brackets in a few places:
Function Declarations
Object Declarations
Class Declarations
Loops
Conditionals
I think there is one more, but that is what I came up with off the top of my head. Basically, when you tried to use this line:
hockeyPP.push({hockeyPlayers[i]});
you tried to declare hockeyPlayers[i] as a new Object (the most basic class in ActionScript, and most languages). You can instantiate the Object class by two ways:
var obj:Object = new Object(); and
var obj:Object = {};
You tried to do the second one, the lazy instantiation. So you tried to declare an object with a property of hockeyPlayers[i] without associating a value with it (the basis of all OOP is property:value pairs).
As that first error said, you are missing a colon for that type of instantiation. If you were to try
hockeyPP.push({hockeyPlayers[i] : null}); //null is what an object is when it has no value
you would not have gotten any errors, as that is the correct way to instantiate an Object. For your needs, though, you just want to push an item from one array to another array. So you do
array2.push( array1[ selectedIndex ] );
I would definitely give the LiveDocs some reading. They can seem daunting, but they are incredibly well written and easy to understand once you start going through them.
LiveDocs - Array
LiveDocs - Object