Home > other >  In JavaScript how to make a variable to include potentially infinite amount of elements (or somethin
In JavaScript how to make a variable to include potentially infinite amount of elements (or somethin

Time:01-02

I have the code below, which works well:

window.addEventListener('load', () => {
    const values = ['input_1', 'input_2', 'input_3', 'input_4', 'input_5', 'input_6', 'input_7', 'input_8'];
    document.querySelectorAll('.box-ipt').forEach((input) => input.onfocus = (event) => localStorage.setItem('myInputFocused_box1', values[Array.prototype.indexOf.call(document.querySelectorAll('.box-ipt'), input)]));
  });  

But I need a way to not have to go back to this code and add more elements to the variable like "input_9", "input_10" etc when I add more input boxes to my HTML code.

Basically a way to make that variable to accept any amount of "input_X" elements (like "input_∞" - I know ∞ does not exist in JS, just making a point).

Or maybe something else like a for loop like the one below but it is not working because the input gets set to random input instead of the last active one, after the extension reloads:

window.addEventListener('load', () => {
  const inputElements = document.querySelectorAll('.box-ipt');
  const values = [];
  for (let i = 0; i < inputElements.length; i  ) {
    values.push(`input_${i   1}`);
  }
  inputElements.forEach((input) => input.onfocus = (event) => localStorage.setItem('myInputFocused_box2', values[Array.prototype.indexOf.call(inputElements, input)]));
});

I also tried this but it breaks the extension/browser:

window.addEventListener('load', () => {
  let i = 1;
  for (;;) {
    const values = [`input_${i}`];
    document.querySelectorAll('.box-ipt').forEach((input) => input.onfocus = (event) => localStorage.setItem('myInputFocused_box2', values[Array.prototype.indexOf.call(document.querySelectorAll('.box-ipt'), input)]));
    i  ;
  }
});

Any suggestions?

PS:I know the title sucks. Please suggest something else if you have a better idea.

EDIT:

More context to the JS code I have:

// Set focus after checking local storage for last focus

window.addEventListener('load', () => {
    const baseanimdur = getComputedStyle(window.parent.document.documentElement).getPropertyValue('--base-anim-dur').replace('s', '');
    const focusDelay = getComputedStyle(document.documentElement).getPropertyValue('--parent-grid-searchbox-focus-onload');
    setTimeout(() => {
        const inputValue = localStorage.getItem("myInputFocused_box1") || "";
        const inputNumber = inputValue.match(/\d /)?.[0];
        const input = inputNumber ? document.querySelectorAll(".box-ipt")[inputNumber - 1] : document.querySelectorAll(".box-ipt")[0];
        input.focus();
    }, baseanimdur / focusDelay);
});

// Function on get active input on Search BT click in order to if input box empty then BT click goes back to focused box

window.getActiveInputOnBTClick = () => {
    const inputNumber = localStorage.getItem("myInputFocused_box1").match(/\d /)?.[0];
    const input = inputNumber ? document.querySelectorAll(".box-ipt")[inputNumber - 1] : document.querySelectorAll(".box-ipt")[0];
    input.focus();
};

/////////////// REFOCUS WHEN CLICKING BODY ( EMPTY SPACE ) ///////////////

window.addEventListener('load', () => {
    const body = document.querySelector('body');
    document.addEventListener('click', event => {
        event.composedPath().includes(body) ? getActiveInputOnBTClick() : getActiveInputOnBTClick();
    });
});

/////////////// Set local storage item for memorizing last focus

window.addEventListener('load', () => {
    const values = ['input_1', 'input_2', 'input_3', 'input_4', 'input_5', 'input_6', 'input_7', 'input_8'];
    document.querySelectorAll('.box-ipt').forEach((input) => input.onfocus = (event) => localStorage.setItem('myInputFocused_box1', values[Array.prototype.indexOf.call(document.querySelectorAll('.box-ipt'), input)]));
  });   

CodePudding user response:

I think you should be looking to utilize the "index" of the forEach loop to accomplish this. When you use querySelectorAll to get all the inputs in a page- the array you receive indexes each element in the order it appears on the page.

You could simply save that index to local storage and call focus() on that element when you load the page. This scales to infinite inputs.

I can't make a code snippet using localStorage- but try running this locally:

//wait for page to load
window.addEventListener("load", () => {
  //get all the Input elements on the page.
  const inputEls = [...document.querySelectorAll("input")];
  //set our focusPosition to either 0, or the localStorage Variable
  const lastFocus = Number(localStorage.getItem("lastFocus")) || 0;
  //iterate over each input element, using 'i' for the index
  inputEls.forEach((el, i) => {
    //if the index is equal to the lastFocus variable, focus that element
    if (i == lastFocus) {
      el.focus();
    }
    //add an event listener using the index to save that number to local storage
    el.addEventListener("focus", () => {
      localStorage.setItem("lastFocus", Number(i));
    });
  });
});

This kind of solution will work for any amount of inputs on the page, without any special naming or tagging.

The HTML of the page can literally just be

<input />
<input />
<input />
<input />
<input />
<input />
<input />

and this will work fine.

EDIT:

Here is a codePen for this example. The only change I added to the codePen is to wait 400ms after the page loads to change focus- as codepen loads other things and steals focus after the page loads. Click any input, and refresh the page - the input will refocus. https://codepen.io/brandonetter/pen/PoBzWQd

CodePudding user response:

As Brandon writes, you can just use the optional index parameter of the forEach loop to get the index of the input within the list. To achieve the same behaviour as before, just construct the name 'input_n' from the index by adding 1.

By generating the exact same format and numbering as before you don't need to adapt the other parts of the existing code.

window.addEventListener('load', () => {
    document.querySelectorAll('.box-ipt').forEach((input, index) => input.onfocus = (event) => localStorage.setItem('myInputFocused_box1', 'input_'   (index   1)));
});
  • Related