Knockout JS: Passing observable array as argument - javascript

I have a 2d observable array called textFields:
var t1 = ko.observableArray([{val: 0}, {val:0}])
self.textFields = ko.observableArray([t1]);
And I have a function called solve that is supposed to take an argument:
self.solve = function(arr){
console.log(arr);
}
In my html, I have associated that function with a link click that passes textFields as an argument to solve:
<a id='solveBtn' href='#' data-bind='click: solve(textFields)'>Solve</a>
I thought I'd now get my textFields-array printed out. But instead, I get []. When I look at the variable in the debugger in Chrome, I also just see []. Why is that? Why is textFields not properly passed to solve?
EDIT:
I made the js now look like this:
self.solve = function(arr){
console.log(arr());
}
But know I want to pass this observable array to another function (which is supposed to make a 'normal' array out of it:
var normalize = function(arr){
var retArr = [];
console.log(arr().length);
for(var i = 0; i < arr.length; i++){
var temp = [];
for(var j = 0; j < arr()[i]().length; j++){
temp.push(arr()[i]()[j].val);
}
console.log(temp);
retArr.push(temp);
}
return retArr;
}
The console.log(arr()) gives me the following error: Message: object is not a function. When I treat arr as a normal array, the for-loop is never executed. I gues that's because arr[i] has length 0.
Thank you very much for your answers!
Tony

Try doing this in markup to get array values in your solve method
<a id='solveBtn' data-bind='click: function(){solve(textFields())}'>Solve</a>
or modify your script as follows
self.solve = function(arr){
console.log(arr());
}
Quick note : In your sample markup, you are setting a function with parameter to the click event. This will cause the function to get executed during page load. It is always safe to wrap it in a function block as below.
<a id='solveBtn' data-bind='click: function(){solve(textFields)}'>Solve</a>

Related

Sometimes, .splice is not a function

I am stuck with a weird error. I get .splice is not a function in the console, but in fact, I am doing .splice on a array (which is valid). Moreover, it don't get always the error. When I refresh the page, sometimes I get it and other times, I don't get it. I don't understand why. Could you explain me my mistake, what am I doing wrong here?
EDIT : I forget to mention that between my declaration of variable array (var ... = []) and my jQuery.getJSON, I am adding stuff inside my variable (integers). That is why I am using splice. I want to order well my array with my new items from the JSON. Also, all arrays contain the same amount of elements. I am always adding the same quantity of elements in each array.
Here is my problematic code :
var HeightLegs = [];
var IdLegs = [];
var PriceLegs = [];
var QuantityLegs = [];
jQuery.getJSON('/products/legs.js', function (product)
{
for (var i = 0; i < product.variants.length; i++)
{
var indexToAdd = 0;
while (indexToAdd < HeightLegs.length && HeightLegs[indexToAdd] < +(product.variants[i].option1.replace('"', '')))
{
indexToAdd++;
}
IdLegs.splice(indexToAdd, 0, product.variants[i].id);
HeightLegs.splice(indexToAdd, 0, +(product.variants[i].option1.replace('"', '')));
PriceLegs.splice(indexToAdd, 0, product.variants[i].price / 100);
if (product.variants[i].inventory_policy == "continue")
QuantityLegs.splice(indexToAdd, 0, 1);
else {
// MY ERROR IN THE CONSOLE IS ON THIS SPLICE ONLY!!!!
QuantityLegs.splice(indexToAdd, 0, product.variants[i].inventory_quantity);
}
}
});
What I don't understand is that the error is not constant. Sometimes I get it and other times I won't...
Thanks for the help!
According to comments above:
Errors like what.ever is not a function means that what is defined, but method ever is not bound to this object. It causes only two things (if I know):
a) misspelled name of method (ever)
b) wrong type of object/class (what)
In this case, error occured because var ShopifyQuantityLegs was accidentally set to Number (ShopifyQuantityLegs=1) so b) is the clue

JS multidimensional array spacefield

i wanna generate a 3x3 field. I want to do this with JS, it shall be a web application.
All fields shall inital with false. But it seems so that my code is not working correctly, but i don't find my fault. The goal is, that every spacesector is accessible.
Thats my idea:
// define size
var esize = generateSpace(3);
}
space[i] = false is replacing the array with a single boolean value false, not filling in all the entries in array you just created. You need another loop to initialize all the elements of the array.
function generateSpace(x) {
var space = [];
for (var i = 0; i < x; i++) {
space[i] = [];
for (var j = 0; j < x; j++) {
space[i][j] = false;
}
}
return space;
}
Also, your for() loop condition was wrong, as you weren't initializing the last element of space. It should have been i < space.length.
And when it's done, it needs to return the array that it created.
Since I got somewhat bored and felt like messing around, you can also initialize your dataset as shown below:
function generateSpace(x) {
return Array.apply(null, Array(x)).map(function() {
return Array.apply(null, Array(x)).map(function() {
return false;
});
});
}
The other functions work equally well, but here's a fairly simply looking one using ES6 that works for any square grid:
function generateSpace(x) {
return Array(x).fill(Array(x).fill(false));
}

passing an array into a function from within a function

I am trying to pass this arr into a function, one element at a time. I have more work to do beyond that, but I cannot even get it to send the element to the square function, so this is just a hurdle that I don't understand? Anyway, this is the code:
var arr = [1,2,3,4];
function square(element){
return element * element;
}
function applyFunction(arr, square){
for(var i = 0; i <= arr.length-1; ++i){
alert(square(arr[i]));
}
}
applyFunction(arr,square());
Any help would be appreciated, as I am sure this is simple for you guys.
Modify your last line from
applyFunction(arr,square());
to
applyFunction(arr,square);

Can I select 2nd element of a 2 dimensional array by value of the first element in Javascript?

I have a JSON response like this:
var errorLog = "[[\"comp\",\"Please add company name!\"],
[\"zip\",\"Please add zip code!\"],
...
Which I'm deserializing like this:
var log = jQuery.parseJSON(errorLog);
Now I can access elements like this:
log[1][1] > "Please add company name"
Question:
If I have the first value comp, is there a way to directly get the 2nd value by doing:
log[comp][1]
without looping through the whole array.
Thanks for help!
No. Unless the 'value' of the first array (maybe I should say, the first dimension, or the first row), is also it's key. That is, unless it is something like this:
log = {
'comp': 'Please add a company name'
.
.
.
}
Now, log['comp'] or log.comp is legal.
There are two was to do this, but neither avoids a loop. The first is to loop through the array each time you access the items:
var val = '';
for (var i = 0; i < errorLog.length; i++) {
if (errorLog[i][0] === "comp") {
val = errorLog[i][1];
break;
}
}
The other would be to work your array into an object and access it with object notation.
var errors = {};
for (var i = 0; i < errorLog.length; i++) {
errors[errorLog[i][0]] = errorLog[i][1];
}
You could then access the relevant value with errors.comp.
If you're only looking once, the first option is probably better. If you may look more than once, it's probably best to use the second system since (a) you only need to do the loop once, which is more efficient, (b) you don't repeat yourself with the looping code, (c) it's immediately obvious what you're trying to do.
No matter what you are going to loop through the array somehow even it is obscured for you a bit by tools like jQuery.
You could create an object from the array as has been suggested like this:
var objLookup = function(arr, search) {
var o = {}, i, l, first, second;
for (i=0, l=arr.length; i<l; i++) {
first = arr[i][0]; // These variables are for convenience and readability.
second = arr[i][1]; // The function could be rewritten without them.
o[first] = second;
}
return o[search];
}
But the faster solution would be to just loop through the array and return the value as soon as it is found:
var indexLookup = function(arr, search){
var index = -1, i, l;
for (i = 0, l = arr.length; i<l; i++) {
if (arr[i][0] === search) return arr[i][1];
}
return undefined;
}
You could then just use these functions like this in your code so that you don't have to have the looping in the middle of all your code:
var log = [
["comp","Please add company name!"],
["zip","Please add zip code!"]
];
objLookup(log, "zip"); // Please add zip code!
indexLookup(log, "comp"); // Please add company name!
Here is a jsfiddle that shows these in use.
Have you looked at jQuery's grep or inArray method?
See this discussion
Are there any jquery features to query multi-dimensional arrays in a similar fashion to the DOM?

Javascript: push array onto array with for loop

Please explain this to me. I'm trying to create an array of arrays with a for loop. When it didn't work, I tried simplifying the code to understand what Javascript is doing, but the simple code doesn't make sense either.
function test(){
var sub_array = [];
var super_array =[];
for (var i=1;i<=3;i++){
sub_array.push(i);
super_array.push(sub_array);
}
alert(super_array);
}
I expect to see [1; 1,2; 1,2,3].
Instead I get [1,2,3; 1,2,3; 1,2,3].
I get the same phenomenon if I loop 0-2 and assign by index.
You're always pushing a reference to the same array into your super-array.
To solve that problem, you can use slice() to clone the sub-array before pushing it:
function test() {
var sub_array = [];
var super_array = [];
for (var i = 1; i <= 3; i++) {
sub_array.push(i);
super_array.push(sub_array.slice(0));
}
alert(super_array);
}
EDIT: As Dan D. rightfully points out below, you can also call concat() without arguments instead of slice(0). It's faster according to this article (I did not measure it myself):
for (var i = 1; i <= 3; i++) {
sub_array.push(i);
super_array.push(sub_array.concat());
}
When you push "sub_array", you're not pushing a copy of it. You end up with the same array three times in "super_array". (I should say that you're pushing a reference to the same array three times.)
You could do this:
// ...
super_array.push(sub_array.slice(0));
to make a copy.
well. You have to understand, that Array, Objects, Functions, etc. are references in javascript (only Numbers(Int,Floats,etc) and Strings are passed "by-value", which means, that the value is copied/duplicated)!
if you have an var a=[];, und say var b=a and add b.push("bla"), then alerting a, will show you the "bla" entry, even though you added it to b.
In other words; a and b is to javascript like a note on the frige from mom saying "the sandwhich on the left is for you." And then you know, that to take the left one and not just any random sandwich from the fridge. She also could have written another note (variable b) on your house' door, so that you knew where to go and look for the sandwich if you are in a hurry.
If she would have stuck a sandwich to the door.. well, that would be ackward. And JS thinks the same about it :)
so the solution to your problem is as fallows;
function test(){
var super_array =[];
for (var i=1;i<=3;i++){
var subarray=[];
for (var u=1;u<=4-i;u++){
sub_array.push(u);
super_array.push(subarray);
}
}
alert(super_array);
}
by redefining the subarray, you create a new reference. So that the variable b (the second note on the hous' door) now points in the direction of a different sandwich - maybe dad's sandwich.
I hope I could help you understand this.
Note that you are pushing the same array into super_array for each iteration in the for-loop. Try instead the following:
function test(){
var sub_array = [];
var super_array =[];
for (var i=1;i<=3;i++){
sub_array = sub_array.slice(0,sub_array.length);
sub_array.push(i);
super_array.push(sub_array);
}
alert(super_array);
}
It is same sub_array that you are adding to the super_array. So why it has to be different.
You are not creating a new array and pushing into a super_array.
sub_array is stored as a reference in super_array this means that when you change sub_array the change is reflected inside super_array

Categories