I have a scoped variable that stores an archive:
viewScope.MY_SCOPE = new Array();
viewScope.MY_SCOPE.push(["id0", 0, true]);
viewScope.MY_SCOPE.push(["id1", 1, false]);
viewScope.MY_SCOPE.push(["id2", 3, true]);
now I want to update one of item.
viewScope.MY_SCOPE[1][2] = "true";
and this fails with the error:
Error while executing JavaScript action expression put(int index,FBSValue value) not supported in JavaWrapperObject.
How do I update a specific item in the array?
When adding the SSJS array object to the scope, it is converted to a java.util.Vector. Hence, if you want to set the value, you should use
viewScope.MY_SCOPE[1].set(2,"true");
instead of viewScope.MY_SCOPE[1][2] = "true";.
I think the problem is that using ...[2] = "true" tries to execute the put method of the given object. While put is available in Maps like HashMaps or the scope maps, Vectors use set instead of put to change values. For that reason, you get the "action expression put(...) not supported" error. In contrast to this, it's no problem to get the variable with viewScope.MY_SCOPE[1][2] because the get method is availiable in both HashMaps and Vectors.
When storing arrays in scope variables, I like to put the value into a properly typed javascript variable, make edits, and then replace the scope variable with the updated value.
In your case I would do the following:
var tempVar = viewScope.MY_SCOPE.toArray(); //convert to array to make sure properly typed
tempVar[1][2] = true;
viewScope.put(MY_SCOPE,tempVar);
Update:
After testing your code along with mine, I too get the same error. To be honest, I never would have messed with multi dimensional arrays in the first place. This is a perfect opportunity to use an array of objects:
var tempVar = []; // initialize the array
tempVar.push({val1:"id0",val2:0,val3:true});
tempVar.push({val1:"id1",val2:1,val3:false});
tempVar.push({val1:"id2",val2:3,val3:true});
viewScope.put("MY_SCOPE",tempVar);
Then to change the desired value:
var tempVar = [];
tempVar = viewScope.get("MY_SCOPE");
tempVar[1].val3 = true;
viewScope.put("MY_SCOPE",tempVar)
I tested this method and it works fine.
Related
I have a simple array that I'm trying to iterate over but I'm apparently not understanding the 'for of' JavaScript loop. The following code returns exactly has it should;
const callOBJb = ['KD0NBH0BJ','W0DLKOBJ','WA0TJTOBJ'];
for (let i of callOBJb) {
console.log(i);
}
return: KD0NBHOBJ W0DLKOBJ WA0TJTOBJ
But the following code errors out with; "TypeError: i.getCenter is not a function. (In 'i.getCenter()', 'i.getCenter' is undefined)" because the variable 'i' does not resolve to one of the above.
for (let i of callOBJb) {
var Omiddle = i.getCenter();
}
When I manually type the variable in such as;
var Middle = W0DLKOBJ.getCenter();
It works just fine. What am I not understanding about how this should work?
I don't think I can use the ForEach here at least I'm not having any more luck than the for...of.
I was asked what the resolved variable for W0DLKOBJ might look like.
alert(JSON.stringify(KD0NBHOBJ));
{"_southWest":{"lat":39.204385,"lng":-94.60714},"_northEast":{"lat":39.20646,"lng":-94.60481}}
This works:
var Middle = W0DLKOBJ.getCenter();
because this:
W0DLKOBJ
is different from this:
'W0DLKOBJ'
If the array should contain the variable values and not string literals, don't use quotes:
const callOBJb = [KD0NBH0BJ, W0DLKOBJ, WA0TJTOBJ];
The callOBJb variable is an Array of strings, and when you use for..of statement to perform a loop iteration, for each item in your iterable object you will get item at deposition corresponding to the time to loop bloc code is execute.
In you case as all items in the callOBJb array is simple string, javascript String.prototype Object doesn't define a function named getCenter that is the reason why you are getting
"TypeError: i.getCenter is not a function. (In 'i.getCenter()', 'i.getCenter' is undefined)
let callOBJb = ['KD0NBH0BJ','W0DLKOBJ','WA0TJTOBJ'];
for(let item of callOBJb){
console.log(typeof item, item);
}
As you can see on each iteration the typeof item is always string.
I went back to the php and redesigned the output to make conversation to Javascript easier. By doing that I was able to iterate through the values using "for (let val of callOBJb)" successfully.
The solution came in how I received the data from PHP to start with. When I changed the definition to; const callOBJb = <?php echo "[$callOBJb]" ?> to include the square brackets and then used; for (let val of callOBJb) {...etc all of the variables resolved properly.
Why the two scripts behave differently? I want the to use the first script, but in the second drawData() call it changes data; it's weird and not what I want to happen. The second script does not have this problem. Why is it like that, and how can I fix the first script?
First script does not change data:
var data = ["right"];
function drawData(arrs, type) {
if (type == "percentage") {
arrs[0] = "omg";
}
console.log(data[0]); // Changed!?
}
drawData(data);
drawData(data, "percentage");
Second script:
var data = "right";
function drawData(arrs, type) {
if (type == "percentage") {
arrs = "omg";
}
console.log(data); // OK, not changed.
}
drawData(data);
drawData(data, "percentage");
This is the difference between assignment to a local variable and mutation of the given object.
In both pieces of code arrs is a local variable, distinct from data. But the elements and other properties of arrs are exactly the same as those of data. Making changes to those property values (which is commonly called mutation of the object/array) will be visible whether you access them via arrs or via data. And this is exactly what the first script does.
The second script however, does not change a property value of arrs, but assigns an entirely new value to arrs, so that now it does not share any properties any more with data. This is even more apparent, because both data and arrs are primitive values which cannot mutate like explained in the previous paragraph. But even if they were objects or arrays, and you would do the following assignment:
arrs = [1234];
It would not affect data. data would only be affected if you would assign to a property/index of arrs without assigning to arrs directly.
First variant modifies object passed as parameter to function (which happens to be array) - so this change is seen outside function. Second variant assigns new value to function parameter (which happens to be reference to array) but does not change array itself.
I am in a strange condition. I have an array of objects, I used angular.forEach to modify each object price key value but when I am changing it in each it is also changing main array object as well.
Have a look on code, you will understand then what I am trying to say.
var option_1_val = $scope.options.option_1_val;
var option_2_val = $scope.options.option_2_val;
console.log('genies',sc.genies);
var new_arr = [];
var each ;
each = sc.genies;
angular.forEach(each,function(val,key){
var ob = {};
ob = val;
var priceA = angular.fromJson(ob.price);
console.log('price',priceA);
var option = option_1_val.replace(" ","-")+","+option_2_val.replace(" ","-");
console.log(option);
ob.price = priceA[option];
console.log(ob);
new_arr.push(ob);
});
option = 'Non-Vegetarian,' (after calculating)
sc.genies = [{"gs_id":"3","user_id":"25","service_id":"7","price":"{\"Vegetarian,Bengali\":\"200\",\"Vegetarian
,Chinese\":\"3100\",\"Vegetarian,Gujarati\":\"800\",\"Vegetarian,Italian\":\"100\",\"Vegetarian,Maharashtrian
\":\"100\",\"Vegetarian,Punjabi\":\"100\",\"Vegetarian,-South-Indian\":\"300\",\"Vegetarian,Thai\":\"100
\",\"Non-Vegetarian,Bengali\":\"1100\",\"Non-Vegetarian,Chinese\":\"3100\",\"Non-Vegetarian,Gujarati
\":\"100\",\"Non-Vegetarian,Italian\":\"100\",\"Non-Vegetarian,Maharashtrian\":\"100\",\"Non-Vegetarian
,Punjabi\":\"100\",\"Non-Vegetarian,-South-Indian\":\"80\",\"Non-Vegetarian,Thai\":\"100\",\"Jain,Bengali
\":\"2100\",\"Jain,Chinese\":\"2100\",\"Jain,Gujarati\":\"4100\",\"Jain,Italian\":\"100\",\"Jain,Maharashtrian
\":\"100\",\"Jain,Punjabi\":\"100\",\"Jain,-South-Indian\":\"800\",\"Jain,Thai\":\"100\"}","min_price"
:"80","max_price":"4100","username":"abdul quadir","email":"abdul.quadir#kiozen.com","rating":"3"}]
now when I am repeating sc.genie, I have taken it in a new variable already "each" and then I am changing "price" key of each array to undefined but strange point is when I see in console value of price in sc.genies is also changed to "undefined". Huh!
I hope you got my point, please help me why is that happening.
Thanks
You should use angular.copy then when change in each value not affect to original value. because of angular.copy assign old value in new variable without reference.
like:
var each ;
each = angular.copy(sc.genies);
instead of
each = sc.genies;
There is a simple answer. The reason why "both" values changes, is because it is actually the same object. The variable val from this line angular.forEach(each,function(val,key){ ... contains a pointer to an object. It is not another object. It is the same object, it is only accessed via different variable name.
If you really want the original and working copy to be different objects, then you need to manually create new instance with the same values.
You can create copy of an object like this (good for simple objects):
var copy = JSON.parse(JSON.stringify(originalObject));
or as pointed in the comment above, you can use angular.copy(source, destination). See the documentation https://docs.angularjs.org/api/ng/function/angular.copy
I have an intention to set a field value of an object like this
$scope[nameOfField]=value;
which works if nameOfField is just field name.
However, if I define in $scope object "subObject":
$scope.subObject={};
var nameOfField='subObject.someSubField';
$scope[nameOfField]=12345;
this does not work. Apparently I can not address directly sub-object fields like this. I however do need to use nameOfField approach with sub-object fields, and appreciate hints how to make it work. I can not predict if subObject will be featured in nameOfField - it can be both name field and subObject.someSubField.
EDIT: Difference with the question Accessing nested JavaScript objects with string key is that I not only need to access value of object but modify it.
Well your current code would result into
$scope['subObject.someSubField']=12345;
which would be a syntax error. Correct would be
$scope[nameOfField1][nameOfField2]=12345;
So you need a function to archieve this. Here an example (obviously this has to be extended to support more then just the 2 levels):
var scope = {};
function setValue(scopeString, val){
var match = /(\w+)\.(\w+)/.exec(scopeString);
if(!scope[match[1]]) //create if needed
scope[match[1]] = {};
scope[match[1]][match[2]] = val;
}
function getValue(scopeString){
var match = /(\w+)\.(\w+)/.exec(scopeString);
return scope[match[1]][match[2]];
}
setValue('lvl1.lvl2', 1);
console.log(getValue('lvl1.lvl2'));
I was trying to define an array (including other arrays as values) in a single javascript statement, that I can loop through to validate a form on submission.
The function I wrote to (try to) create inline arrays follows:
function arr(){
var inc;
var tempa = new Array(Math.round(arguments.length/2));
for(inc=0; inc<arguments.length; inc=inc+2) {
tempa[arguments[inc]]=arguments[inc+1];
}
return tempa;
}
This is called three times here to assign an array:
window.validArr = arr(
'f-county',arr('maxlen',10, 'minlen',1),
'f-postcode',arr('maxlen',8, 'minlen',6)
);
However in the javascript debugger the variable is empty, and the arr() function is not returning anything. Does anyone know why my expectations on what this code should do are incorrect?
(I have worked out how to create the array without this function, but I'm curious why this code doesn't work (I thought I understood javascript better than this).)
Well from what your code does, you're not really making arrays. In JavaScript, the thing that makes arrays special is the management of the numerically indexed properties. Otherwise they're just objects, so they can have other properties too, but if you're not using arrays as arrays you might as well just use objects:
function arr(){
var inc;
var tempa = {};
for(inc=0; inc<arguments.length; inc=inc+2) {
tempa[arguments[inc]]=arguments[inc+1];
}
return tempa;
}
What you're seeing from the debugger is the result of it attempting to show you your array as a real array should be shown: that is, its numerically indexed properties. If you call your "arr()" function as is and then look at (from your example) the "f-county" property of the result, you'll see something there.
Also, if you do find yourself wanting a real array, there's absolutely no point in initializing them to a particular size. Just create a new array with []:
var tempa = [];
Your code works. Just inspect your variable, and you will see that the array has the custom keys on it. If not expanded, your debugger shows you just the (numerical) indixed values in short syntax - none for you.
But, you may need to understand the difference between Arrays and Objects. An Object is just key-value-pairs (you could call it a "map"), and its prototype. An Array is a special type of object. It has special prototype methods, a length functionality and a different approach: to store index-value-pairs (even though indexes are still keys). So, you shouldn't use an Array as an associative array.
Therefore, their literal syntax differs:
var array = ["indexed with key 0", "indexed with key 1", ...];
var object = {"custom":"keyed as 'custom'", "another":"string", ...};
// but you still can add keys to array objects:
array.custom = "keyed as 'custom'";