How to get the index value while using ko.utils.arrayForEach - javascript

I am using ko.utils.arrayForEach as mentioned below.
ko.utils.arrayForEach(comments , function(comment) {
tmp.push(comment);
});
Here I am getting all the results and they are pushed to tmp. If I want to access the first record alone, how can I modify the above code for retrieving the index.

Since version 3.1.0 released on 14 May 2014, index is passed to all the array functions as the second argument:
ko.utils.arrayForEach(items, function(item, index) {
/* ... */
});

Unfortunately, it's not possible yet. PimTerry added this functionnality on December (see this commit), but it has not be release yet.
Until now; you can do it manually:
for (var i = 0, j = comments.length; i < j; i++) {
// use an anonymous function to keep the same code structure
(function(comment, i) {
tmp.push(comment);
// do what you need with i here
})(comments[i], i);
}
It's exaclty the code used inside ko.utils.arrayForEach. The migration will be very easy once Knockout will be released

Related

for loop iterates only once

I have a clients array of objects, so i use for loop to iterates over it
I have clients.lenght = 2, but it's iterates only 1. And i don't have variable scope problem here. Just don't get it why it happens.
Code
socket.on('idleDisconnectAllClient', function(receivedData) {
LOG("idleDisconnectAllClient");
var clientIndex = findMainIndexByDataBaseID(receivedData.dataBaseID);
if (clientIndex != -1) {
console.log('clients lenght', clients[clientIndex].data.length);
for (var i = 0; i < clients[clientIndex].data.length; i++) {
var client = clients[clientIndex].data[i];
client.disconnect();
console.log('client ' + i);
}
}
});
Console
2016-03-29 04:13:01 - idleDisconnectAllClient
clients lenght 2
client 0
jpaljasma - https://stackoverflow.com/users/2079695/jpaljasma
helps me to understand the problem.
When i use - client.disconnect() it's just delete current client from clients array. So thats why my loop carried out only 1 time.
you could iterate via the ES5 forEach construct:
clients[clientIndex].data.forEach(client => client.disconnect())
(disclaimer, this uses fat arrows from ES6, might not work on older node versions)

Uncaught ReferenceError: i is not defined

I'm trying to make a for-loop base on my array
var lists = [ "a", "b", "c", "d" ];
JS
for ( i = 0; i < lists.length; i++) {
// console.log(lists[i]);
$(".sa-report-btn-"+lists[i] ).click(function () {
$(".sa-hide-"+lists[i]).removeClass("hidden");
$(".sa-report-"+lists[i]).addClass("hidden");
});
$(".sa-hide-btn-"+lists[i]).click(function () {
$(".sa-hide-"+lists[i]).addClass("hidden");
$(".sa-report-"+lists[i]).removeClass("hidden");
});
}
Am I doing it correctly ? I got Uncaught ReferenceError: i is not defined
Can I concat each loop with my jQuery selector like this --> $(".sa-hide-"+lists[i]) ? just curious ...
First off, it sounds like you're using strict mode — good! It's saved you from falling prey to The Horror of Implicit Globals.
There are two issues with the code.
The first one is that you're missing the declaration for i. You need to add var i; above the loop, e.g:
var i;
for ( i = 0; i < lists.length; i++) {
// ...
or
for (var i = 0; i < lists.length; i++) {
Note, though, that even in that latter example, the i variable is function-wide, not limited to the for loop.
The second one is more subtle, and is outlined in this question and its answers: Your click handlers will have an enduring reference to the i variable, not a copy of it as of where they were created. So when they run in response to a click, they'll see i as the value lists.length (the value it has when the loop has finished).
In your case, it's really easy to fix (and you don't have to declare i anymore): Remove the loop entirely, and replace it with Array#forEach or jQuery.each:
lists.forEach(function(list) {
$(".sa-report-btn-" + list).click(function () {
$(".sa-hide-" + list).removeClass("hidden");
$(".sa-report-" + list).addClass("hidden");
});
$(".sa-hide-btn-" + list).click(function () {
$(".sa-hide-" + list).addClass("hidden");
$(".sa-report-" + list).removeClass("hidden");
});
});
If you need to support really old browsers, you can either shim Array#forEach (which was added in 2009, as part of ECMAScript5), or you can use $.each (jQuery.each) instead:
$.each(lists, function(index, list) {
// Note addition ------^
$(".sa-report-btn-" + list).click(function () {
$(".sa-hide-" + list).removeClass("hidden");
$(".sa-report-" + list).addClass("hidden");
});
$(".sa-hide-btn-" + list).click(function () {
$(".sa-hide-" + list).addClass("hidden");
$(".sa-report-" + list).removeClass("hidden");
});
});
Note that we don't actually use index anywhere in our callback, but we have to specify it because $.each calls our callback with the index as the first argument, and the value as the second. (Which is why I prefer Array#forEach.) So we have to accept two arguments, with the one we want being the second one.

JS Hint - don't make functions within a loop

I can not get around JSHint's error message. Here is the loop I am using:
for (i = 0; i < Collection.length; i += 4) {
data.push({
items : Collection.slice(i, i + 4).map(function(item) {
return {
id: item[0],
title: item[1],
};
})
});
}
You can just move the function outside the loop and pass a reference to it to map:
function mapCallback(item) {
return {
id : item[0],
title : item[1],
};
}
for (i = 0; i < Collection.length; i += 4) {
data.push({
items: Collection.slice(i, i + 4).map(mapCallback)
});
}
Alternatively, you can use a JSHint directive to ignore function expressions inside loops. Just put this at the top of the file in question:
/*jshint loopfunc: true */
Declaring a function in a loop is messy, and potentially error prone. Instead, define the function once, and then enter the loop.
var objMaker = function(item) {
return {
id : item[0],
title : item[1],
};
};
for (i = 0; i < Collection.length; i += 4) {
data.push({
items : Collection.slice(i, i + 4).map(objMaker)
});
}
People say "Declaring a function in a loop is messy and potentially error-prone", but functions within loops is what directly instructed in, for example, Array.prototype.forEach method. Just because the word "function" should theoretically mean defining it anew in every forEach call it does not mean it is actually defined each time by the Javascript engine.
The same goes for outer loops since engines have "lazy" processing of instructions. They are not going to redefine the whole forEach/Map/etc construct-instruction anew if nothing really changed about it, they will just feed new arguments to it.
The times of ancient JS engines which were clueless about such simple things as well as of code context are long gone. And yet we are getting this ancient warning which was conceived when functions were not yet capable of being passed as arguments as in the cases of forEach or Map.

Issue with Javascript For loop

Consider the Code below:
function splicer()
{
var arrayElements = ["elem1","elem2","elem3","elem4"];
for(var index in arrayElements)
{
arrayElements.splice(index,1);
}
alert("Elements: "+arrayElements);
}
The above function is supposed to remove all the elements from the array "arrayElements". But it won't.
Javascript engine maintains the "index" as it is and doesn't mind the array being modified.
People might expect something like "for each" loop that doesn't have this kind of issue
even the following code doesn't seem to work:
function splicer()
{
...
for(var index in arrayElements)
{
arrayElements.splice(index--,1);
}
...
}
even when changing the value of the variable "index" doesn't seem to work.
the changed value is available inside the "for(...){...}" block but, as the loop reaches the next iteration, the value gets reset and continues from the next index as clockwork.
so it seems code like this might be the only solution:
function splicer()
{
var arrayElements = ["elem1","elem2","elem3","elem4"];
for(var index=0;index<arrayElements.length;index++)
{
arrayElements.splice(index--,1);
}
alert("Elements: "+arrayElements);
}
Tested in: Firefox 16 Beta.
But placing a unary Operator inside a "splice()" method seems to be misleading at first sight.
This might be worth considering to the "W3C" or whomever it may concern so that they come up with a nice solution.
You may want to refer to John Resig's array.remove() link.
// Array Remove - By John Resig (MIT Licensed)
Array.prototype.remove = function(from, to) {
var rest = this.slice((to || from) + 1 || this.length);
this.length = from < 0 ? this.length + from : from;
return this.push.apply(this, rest);
};
Try this:
*Splice modifies the original array, hence tge loop skips the alternate values. *
var arrayElements = ["elem1","elem2","elem3","elem4"];
arrayElements.splice(0,arrayElements.length);
alert("Elements: "+arrayElements)

turn array into function, making a javascript loader with jquery

how can we make a function from arrays like
$.loader({
js: [
['1.js','3.js','2.js'],
['4.js'],
['5.js']
]
});
into something that does
$.when(
$.getScript("1.js"),
$.getScript('3.js'),
$.getScript('2.js'))
.then(
function(){
$.getScript('4.js').then(function(){
$.getScript('5.js');
})
});
heres what currently im working on
loader: function(arg){
var js = arg;
var phase = 0;
for (var i = 0; i < o.length; i++) {
console.log(o[i]);
$.each(o[i], function(key,src) {
//append javascript
});
};
}
the problem is i dont know where to start.
heres what i have in mind
i divide them into phases.
set phase 0, it will run the fist array but how can i do it ? $.getScript(src) for each src dosent stack. or chain. maybe put it one var sting ? like string + = $.getScript(src). so it will be like $.getScript("1.js").getScript("3.js").getScript("2.js") until there is arrays of string which is 3 in this example. then do something like append $.when( infront of the string then at the back of the string we put .then(function(){ until it finish then somehow closed the string.
ok i dont know ( and here goes the post at stackoverflow )
function lScripts(startAt){
for (var i = startAt; i < js.length; i++) {
if (js[i].constructor == Array){
for (var j = 0; j < js[i].length; j++) {
if(j==js[i].length){
$.getScript('js[i][j]',function(){
lScripts(startAt+1);
});
}else{
$.getScript('js[i][j]');
}
}
}else{
$.getScript('js[i]',function(){
lScripts(startAt+1);
});
}
}
}
lScripts(0);
Just to be clear, are you talking about writing a solution yourself that loads up a bunch of scripts? If so, dont do it yourself. Stand on someone else's shoulders.
RequireJS already does what you're asking.
http://requirejs.org/
It even has documentation for use with jQuery.
http://requirejs.org/docs/jquery.html
Someone else already did the hard work and wrote and tested a good product. Save yourself time and stress.
I hope this is what you mean: http://jsfiddle.net/pimvdb/hdN3Q/1/.
(function($) {
function load(files, index) {
var arr = [];
// fill arr with getScript requests (fake here)
for(var i = 0; i < files[index].length; i++) {
arr.push(console.log(files[index][i]));
}
// call $.when with arr as array of arguments (using apply)
$.when.apply(null, arr).then(function() {
if(index < files.length - 1) {
// if we have to move to the next chunk,
// load that next one
setTimeout(function() {
// timeout is to show they get processed in chunks
load(files, index + 1);
}, 1000);
}
});
}
$.loader = function(obj) {
load(obj.js, 0);
}
})(jQuery);
$.loader({
js: [
['1.js','3.js','2.js'],
['4.js'],
['5.js']
]
});
.apply essentially does the same thing as calling a function. However, because the amount of arguments to $.when differs depending on the input, you can't just call $.when(...) because you don't have a fixed number of arguments. The way to call a function with a variable amount of arguments is using .apply. It works like this:
someFunction(1, 2, 3);
is equal to:
someFunction.apply(null, [1, 2, 3]);
(The null refers to the execution context which is out of scope here.) The great thing about this is that you can build an array of any size. So you can call the function with any variable amount of arguments this way.
In the load function, arr gets filled with getScript functions, and it works the same way:
var arr = [getScript('file1'), getScript('file2')];
$.when.apply(null, arr);
is equal to:
$.when(getScript('file1'), getScript('file2'));
In load, we fill arr with the files of a chunk, e.g. in your case the first chunk is 1.js, 3.js and 2.js. This is done using a for loop but the array you will end up with you can just pass to .apply.
When all files are loaded, .then is called. The function we pass there should load the next chunk, but only if there is a next chunk. If there are 3 chunks, it should go to the next one when index is 0 or 1. When chunk 2 has finished, there is no next chunk so it should not continue to the next one as there isn't a next one.
So we need this if clause:
if(index < files.length - 1) {
Say files.length is 3. Then this if conditional will only pass when index is 0 or 1, which is what we want.

Categories

Resources