I'm making a simple filtering function where I pass a sorted array into a function which is supposed to clear the wrapper and add the new ordered elements. My natural thought here is to do the removing and adding in the same loop, but I just can't get it to work and I can't really figure out why it wouldn't work.
Function that takes an array as argument. The sorted array is passed inside the function without any issues. The array is an Array.from(nodeList).
function removeAndAdd(sortedArray) {
for (let i = 0; i < allPosts.length; i++) {
const forumPost = allPosts[i]
forumPost.replaceWith(sortedArray[i])
}
}
NOTE: I've also tried (And alot of other stuff)
for (let i = 0; i < allPosts.length; i++) {
const forumPost = allPosts[i]
forumPost.remove()
wrapper.append(orderedArray[i])
}
My expectation is that with a single loop you should be able to clear the elements and at the same time att a new element. I don't want to use two different loops here.
Edit: I solved it by using remove() in an async function outside. I'd still love to learn technically why this didn't work.
Related
I'm new to using JDBC and am learning how to use batch processing. After wasting a lot of time trying to figure out why my combination of JavaScript and SQL stored procs didn't work, I think I learned that you have to use one prepareCall when using addBatch and executeBatch. Is this true? If so, why?
To exemplify, here's some example input:
var vals = [["value1_1","value2_1","value3","value4","value5","value6_1"],
["value1_2","value2_2","value3","value4","value5","value6_2"]]
The below loop works as expected. Note that I prepareCall before entering the loop.
params = Array(vals.length).fill("?")
pstmt = conn.prepareCall("{call "+storedProcedure+"("+params+")}");
for (var i = 0; i < vals.length; i++) { // for each array
for (var j = 0; j < vals[i].length; j++) { // for each value within each array
// set the string
pstmt.setString(j+1, vals[i][j]);
}
pstmt.addBatch();
}
try {
pstmt.executeBatch();
} catch (err) {
//my err msg code
pstmt.close();
conn.close();
}
Now, sometimes I have records that have a different number of parameters so I thought that I could just move prepareCall into the first loop so that I can change the number of parameters as needed for each input array.
for (var i = 0; i < vals.length; i++) { // for each array
// moved prepareCall here
params = Array(vals.length).fill("?")
pstmt = conn.prepareCall("{call "+storedProcedure+"("+params+")}");
for (var j = 0; j < vals[i].length; j++) { // for each value within each array
// set the string
pstmt.setString(j+1, vals[i][j]);
}
pstmt.addBatch();
}
try {
pstmt.executeBatch();
} catch (err) {
//my err msg code
pstmt.close();
conn.close();
}
For this second loop, I don't get any errors from Javascript but I get a foreign constraint error from my stored proc. My stored proc makes a set of CALLs to create records based on the value of the last parameter. I understand that the error that I get is telling me that one of the FKs doesn't exist. This would only happen if the wrong set of CALLs was invoked or the right set of CALLs was invoked but one of the CALLs failed. I'm sure neither is the issue since the first loop works as expected.
Thus, I'm interested to learn why I have to use one prepareCall when I executeBatch? To confirm, I have to use totally separate prepareCalls when I have call different stored procedures with different numbers of parameters?
I don't think it matters but for good measure: I'm using MySQL 5.7.
The method prepareCall returns a CallableStatement object that is compiled for the specific statement that you passed to prepareCall. When you call addBatch, the set of parameters is added to that specific instance of CallableStatement. If you execute prepareCall again, you get a different CallableStatement handle, with its own batch.
So, in your second piece of code in each iteration of the outer loop, you create a new CallableStatement, losing the previous callable statement and its batch (creating a memory leak as well in your code and possibly in your DBMS). As a result, when you call executeBatch, you will only execute the last statement you prepared, with only a single set of parameter values.
If you need to execute distinct statement texts, you will need to prepare and execute them in order, and you cannot use batch(*).
* - You could use batch if multiple sets of parameters use the same statement text, but if there are order dependencies between different statement texts, this might get tricky
I use forEach almost every time that I'm facing a node list or an actual array, but there are times, in which I can't do so, like when I want to create 5 div elements, I'm bound to do this with for loop
for (let i = 0; i < 4; i++) {
//my code to do some repetitive code ...
const myDiv = document.createElement('div');
myDiv.classList.add(`${myDiv}${i}`)
document.appendChild(myDiv);
}
The question is how can I do the same work with forEach, when there is no actual array or node list that can be used forEach method.
since forEach does the work asynchronously unlike for loop, I think it would be more beneficial move, am I wrong, any idea?
Array(3).fill().forEach((e,i) => {
const myDiv = document.createElement('div');
myDiv.classList.add(`${myDiv}${i}`)
document.appendChild(myDiv);
})
There is no problem in using the for loop, and that is exactly the right place to use a for loop (or a while).
First of all, I'm aware there are many questions about closures in JavaScript, especially when it comes to loops. I've read through many of them, but I just can't seem to figure out how to fix my own particular problem. My main experience lies with C#, C++ and some ASM and it is taking some getting used to JavaScript.
I'm trying to populate a 3-dimensional array with new instances of a class (called Tile) in some for loops. All I want to do is pass along a reference to some other class (called Group) that gets instantiated in the first loop (and also added to another array). As you might have guessed, after the loops are done, every instance of the Tile class has a reference to the same Group object, namely the last one to be created.
Apparently instead of passing a reference to the Group object, a reference to some variable local to the function is passed along, which is updated in every iteration of the loop. My assumption is that solving this problem has something to do with closures as this appears to be the case with many similar problems I've come across while looking for a solution.
I've posted some trimmed down code that exposes the core of the problem on jsFiddle:
//GW2 namespace
(function( GW2, $, undefined ) {
//GW2Tile class
GW2.Tile = function(globalSettings, kineticGroup)
{
//Private vars
var tilegroup = kineticGroup;
// console.log(tilegroup.grrr); //Shows the correct value
var settings = globalSettings;
this.Test = function(){
console.log(tilegroup.grrr);
}
this.Test2 = function(group){
console.log(group.grrr);
}
} //Class
}( window.GW2 = window.GW2 || {}, jQuery ));
var zoomGroups = [];
var tiles = [];
var settings = {};
InitArrays();
tiles[0,0,0].Test(); //What I want to work, should give 0
tiles[0,0,0].Test2(zoomGroups[0]); //How I'd work around the issue
function InitArrays(){
var i, j, k, zoomMultiplier, tile;
for(i = 0; i <= 2; i++){
zoomGroups[i] = {};
zoomGroups[i].grrr = i;
tiles[i] = [];
zoomMultiplier = Math.pow(2, i);
for(j = 0; j < zoomMultiplier; j++){
tiles[i,j] = [];
for(k = 0; k < zoomMultiplier; k++){
tile = new GW2.Tile(settings, zoomGroups[i]);
tiles[i,j,k] = tile;
}
}
}
}
Up till now when working with JavaScript, I've generally fiddled with the code a bit to make it work, but I'm tired of using work-arounds that look messy as I know there should actually be some fairly simple solution. I'm just not fond of asking for help, but this is really doing my head in. Any help is very much appreciated.
Multidimensional arrays
The problem
The first issue with your code above is how you are attempting to create multidimensional arrays.
The syntax you are using is:
tiles[0,0,0]
However, the way JavaScript will interpret this is:
tiles[0]
Accessing a multidim array
If you wish to access a multidim array you have to use:
tiles[0][0][0]
And to create a multidim array you would need to do the following:
tiles = [];
tiles[0] = [];
tiles[0][0] = [];
tiles[0][0][0] = 'value';
or:
tiles = [[['value']]];
With respect to your code
In your code you should be using:
tiles[i][j][k] = tile;
But you should also make sure that each sub array actually exists before setting it's value, otherwise you'll get undefined or illegal offset errors.
You can do this by way of:
(typeof tiles[i] === 'undefined') && (tiles[i] = []);
(typeof tiles[i][j] === 'undefined') && (tiles[i][j] = []);
tiles[i][j][k] = tile;
Obviously the above can be optimised depending on how you are traversing your loops i.e. it would be best to make sure the tiles[i] level exists as an array before stepping in to the the [j] loop, and then not worry about checking it's existence again whilst stepping j.
Other options
Depending on what your dataset is, or at least what you hope to do with the tiles array it can be worth considering using an object instead:
/// set up
tiles = {};
/// assignment
tiles[i+','+j+','+k] = 'value';
However this method is likely to be slower, although I've been proved wrong a number of times by my assumptions and differing JavaScript interpreters. This would probably be were jsPerf would be your friend.
Optimisation
One benefit of using the tiles[i][j][k] approach is that it gives you the chance to optimise your references. For example, if you were about to process a number of actions at one level of your multidimensional array, you should do this:
/// set up
var ij = tiles[i][j];
/// use in loops or elsewhere
ij[k] = 'value'
This is only of benefit if you were to access the same level more than once however.
var brands = document.getElementsByName("brand");
for(var brand in brands){
$("input[name='brand']").eq(brand).click(function(){
alert("hello22");
loadDataFN(1);
});
}
This code is not executing in ie6,
Any help would be appreciated.
The problem is likely that you are trying to use a for-in construct to iterate over a numeric array. This often won't give expected results. Use an incremental for loop instead:
var brands = document.getElementsByName("brand");
// Use an incremental for loop to iterate an array
for(var i=0; i<brands.length; i++){
$("input[name='brand']").eq(brands[i]).click(function(){
alert("hello22");
loadDataFN(1);
});
}
However,
after seeing the first part of your code, the loop appears unnecessary. You should only need the following, since you are assigning the same function to all brand inputs.
// These will return the same list of elements (as long as you don't have non-input elements named brand)
// though the jQuery version will return them as jQuery objects
// rather than plain DOM nodes
var brands = document.getElementsByName("brand");
$("input[name='brand']");
Therefore, the getElementsByName() and loop are not necessary.
$("input[name='brand']").click(function() {
alert("hello22");
loadDataFN(1);
});
for-in loops are used for iterating over the properties of an object, not over the elements of an array.
Why don't you write the code without jQuery if this doesn't work?
Something like this:
function getInputByName(name) {
var i, j = document.getElementsByTagName('input').length;
for(i=0;i<j;++i) { // You can also use getAttribute, but maybe it won't work in IE6
if(document.getElementsByTagName('input')[i].name === name) {
return document.getElementsByTagName('input')[i];
}
}
return null;
}
I don't know jQuery, but maybe you can do something like this:
$(getInputByName('brand')).eq(brand).click(function(){
alert("hello22");
loadDataFN(1);
});
I can't seem to find the answer to this anywhere...
I have a function that needs to set the bg color of two tables. Only the first table in the function is being affected. Is only one for loop allowed in a function? ...or is the 1st for loop maybe never exiting?
I can pretty much work around this by creating multiple functions but I really want to understand why this behaves the way it does!
Thanks!
Here is my simplified code:
function setColor()
{
//This works
var t1rows=document.getElementById("table1").getElementsByTagName("tr");
var x;
for (x in t1rows)
{
t1rows[x].style.backgroundColor='yellow';
}
//this one does not work
var t2rows=document.getElementById("table2").getElementsByTagName("tr");
var y;
for (y in t2rows)
{
t2rows[y].style.backgroundColor='yellow';
}
}
getElementsByTagName() returns a NodeList object, and for-in will iterate its properties which you don't want. You want to use a straight for loop:
for(var i=0; i < t2rows.length; i++) {
t2rows[i].style.backgroundColor='yellow';
}
You're not getting to the second loop because the first is failing when it tries to access a non-existent style property on one of the NodeList's members.