0

I'd like to assign several "click" eventlisteners to several elements that I create using a "for" loop. The unique information for each of these elements is stored in a dictionary, and I can access it using the index of the for loop. What I'd like to do, then, is to have the eventlisteners assigned to these buttons retain the index (or the value of the dictionary associated with the index, but it amounts to the same thing), because at the moment I'm only getting what appears to be the loop index when the loop has finished.

Here's the simplified code;

for (var ind = 0; ind < JSON.parse(localStorage.getItem('data')).length; ind++) {
    var sc = document.createElement('div');
    sc.addEventListener('click', function () {
        console.log(ind);
    })
}

I tried googling for answers but couldn't find anything, then I tried putting the index in the parentheses of the event listener function but it returns a strange pointer instead. Something like PointerEvent {...} with a series of attributes.

Ren4rd
  • 13
  • 5
  • `JSON.parse(localStorage.getItem('data')).length` <-- This will fail if `'data'` does not exist in `localStorage` - where are you verifying that the data exists _and_ is valid (i.e. contains an array of elements with the required data-members?) – Dai Jul 16 '23 at 12:47
  • 1
    A better approach (imo) would be to store the `ind` value in the `dataset` of the `sc` element, that way you can use a top-level `function` without the use of any closures (captured variables), i.e. `sc.dataset['ind'] = ind.toString()`, then inside the event-listener add the `ev` parameter and do: `console.log( ev.currentTarget.dataset['ind'] )` – Dai Jul 16 '23 at 12:48
  • 3
    Use let instead of var to initialize ind. see https://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example – James Jul 16 '23 at 12:48
  • `JSON.parse(localStorage.getItem('data')).length` should be a variable outside the loop, or else it gets evaluated every iteration. (unless you want that to happen) – IT goldman Jul 16 '23 at 14:29
  • @Dai It works perfectly, thank you so much for your help, it's absolutely brilliant! And for `JSON.parse(localStorage.getItem('data')).length`, I just forgot to simplify it for the example but that variable will still exist so no problem. Thanks again! – Ren4rd Jul 16 '23 at 16:01
  • @James Thank you both for your suggestions too, I'll rectify that. – Ren4rd Jul 16 '23 at 16:04
  • @ITgoldman (the comment just above applies to you as well) – Ren4rd Jul 16 '23 at 16:04

1 Answers1

0

As per my comment above, change your code to this:

function getStoredDataArray() {

    const storedData = localStorage.getItem( 'data' );
    if( !storedData ) return null;
    try {
        const maybeArray = JSON.parse( storedData );
        if( Array.isArray( maybeArray ) && maybeArray.length > 0 && maybeArray.every( /* TODO: put per-element validation check here */ ) ) {
            return maybeArray;
        }
    }
    catch ( err ) {
        console.log( "Invalid data in localStorage('data'): %o\r\n\r\nInvestigate:\r\n%o", err, storedData );
        return null;
    }
}

const array = getStoredDataArray();
if( !array ) return;

// https://stackoverflow.com/questions/34348937/access-to-es6-array-element-index-inside-for-of-loop
for( const [idx, value] of array.entries() ) { 
    
    const div = document.createElement( 'div' );
    div.dataset['idx'] = idx.toString();
    div.addEventListener( 'click', onDivClick );
}

function onDivClick( ev /*: Event*/ ) {

    const div = ev.currentTarget;
    const idx = parseInt( div.dataset['idx'], 10 );
    console.log( `Clicked on ${idx} th <div>` );
}

Dai
  • 141,631
  • 28
  • 261
  • 374