1

First of all, sorry for the post's title.

I am trying to get references from these questions: GetElementsByName with array like name

getElementsByName: control by last partial name

How can I select an element by ID with jQuery using regex?

And more or less I understood how to proceed.

I am using this code to check all the <input> and prevent the form from being submitted if any of the field is empty:

  $('form[id="insertForm"]').on("submit", function (e) {
    var form = document.getElementById("insertPanel");
    var inp = form.getElementsByTagName('input');
    for(var i in inp){
      if(inp[i].type == "text"){
        if(inp[i].value == ""){
          inp[i].focus();
          e.preventDefault();
          $("#formAlert").show(400);
          break;
        }
      }
    }
  });

The "problem", is that I was asked to add an exception, and one of these <input> can be empty.

The form is similar to this, what I post here is simplified:

<form id="insertForm" >
    <div id="insertPanel">
        <input type="text" name="FOO1" id="FOO1" />
        <input type="text" name="FOO2" id="FOO2" />
        <input type="text" name="FOO3" id="FOO3" />
        <input type="text" name="FOO4" id="FOO4" />
        <button type="submit" name="submit" value="Submit" >Send</button>

        <table id="tab_logic">
            <thead>
                <tr>
                    <th>Bar1</th>
                    <th>Bar2</th>
                    <th>Bar3</th>
                    <th>Bar4</th>
                    <th>Bar5</th>
                    <th>Bar6</th>
                    <th>Bar7</th>
                    <th>Bar8</th>
                    <th>Bar9</th>
                </tr>
            </thead>
            <tbody>
                <tr id='addr_100'>
                    <td>
                        <input type="text" name='prefs[0][FooBar_A]' />
                    </td>
                    <td>
                        <input type="text" name='prefs[0][FooBar_B]' />
                    </td>
                    <td>
                        <input type="text" name='prefs[0][FooBar_C]' />
                    </td>
                    <td>
                        <input type="text" name='prefs[0][FooBar_D]' />
                    </td>
                    <td>
                        <input type="text" name='prefs[0][FooBar_E]' />
                    </td>
                    <td>
                        <input type="text" name='prefs[0][FooBar_F]' />
                    </td>
                    <td>
                        <input type="text" name='prefs[0][FooBar_G]' />
                    </td>
                    <td>
                        <input type="text" name='prefs[0][FooBar_H]'/>
                    </td>
                    <td>
                        <input type="text" name='prefs[0][FooBar_I]' />
                    </td>
                </tr>
                <tr id='addr_101'/>
            </tbody>
        </table>

        <a id="add_row">Add Row</a>&nbsp;
        <a id='delete_row'>Delete Row</a>
    </form>

I removed all the CSS. Kept is really simple.

I was asked to NOT check the input <input type="text" name='prefs[0][FooBar_G]' />

As you can see, it is an array, at every "add row" click, there is a jquery that adds a new row with name='prefs[1][FooBar_A]' and so on.

I tried to work on the for():

  $('form[id="insertForm"]').on("submit", function (e) {
    var form = document.getElementById("insertPanel");
    var inp = form.getElementsByTagName('input');
    var SKIP = form.querySelectorAll('input[name$="FooBar_G]"]');
    for(var i in inp){
      if(inp[i].type == "text"){
        if(inp[i].value == ""){
          if (SKIP){ console.log("Element " + SKIP.innerText + " found. "); continue; }
          inp[i].focus();
          e.preventDefault();
          $("#formAlert").show(400);
          break;
        }
      }
    }
  });

And many other versions.. failing.

Anyone knows how to make this working?

aPugLife
  • 989
  • 2
  • 14
  • 25
  • I actually would add another property to that specific element. Makes things more simple. And `if(SKIP)` is always true, you might wanna do `if(inp[i] === SKIP) continue;` – Jonas Wilms Feb 05 '18 at 16:28
  • @JonasW. Haven't thought of this, it could really work. My knowledge on JS/jQuery are limited, perhaps I can ask you for a code sample? – aPugLife Feb 05 '18 at 16:33
  • 1
    I think you don't need those crazy name attributes for anything constructive, and you should probably name each field something like `FooBar_G[]`, or `prefs.FooBar_G[]`. Once that's done, excluding fields from validators becomes trivial. – James Feb 05 '18 at 16:43
  • @James good hint, Thanks! – aPugLife Feb 05 '18 at 17:21

3 Answers3

2

let inputs = [...document.querySelectorAll('input')]
let reg = new RegExp('FOO[0-9]', 'g')

let filtered = inputs.filter(({ name }) => name.match(reg))

console.log(filtered)
<input type="text" name="FOO1" id="FOO1" />
<input type="text" name="FOO2" id="FOO2" />
<input type="text" name="FOO3" id="FOO3" />
<input type="text" name="FOO4" id="FOO4" />

<input type="text" name='prefs[0][FooBar_A]' />
<input type="text" name='prefs[0][FooBar_B]' />
<input type="text" name='prefs[0][FooBar_C]' />
<input type="text" name='prefs[0][FooBar_D]' />

$('form[id="insertForm"]').on("submit", function (e) {
  var form = document.getElementById("insertPanel")
  var reg = new RegExp('FOO[0-9]', 'g')
  var inputs = [...document.querySelectorAll('input')].filter(({name}) => name.match(reg))
  inputs.forEach((inp, i) => {
    if(inp[i].type === "text" && inp[i].value === ""){
      inp[i].focus();
      $("#formAlert").show(400);
    }
  })
});
Francis Leigh
  • 1,870
  • 10
  • 25
  • Thanks for your answer, it is a bit too different than the original code, I prefer to keep a simpler syntax and I'm sure it is possible to do that by changing very few things from my code. Mostly because I'm noob in JS. – aPugLife Feb 05 '18 at 16:46
  • What is happening is i am filtering an array of all the inputs. What comes out of the filter is only inputs that' `name` property matches the regex – Francis Leigh Feb 05 '18 at 16:47
  • @Nihvel see second example, Filtering out the un-needed inputs before hand means there is no need to check for 'skipped' inputs. – Francis Leigh Feb 05 '18 at 16:54
  • I found another question that worked, have to test it better. But i upvoted your because I really appreciate your help here!! – aPugLife Feb 05 '18 at 17:00
  • Ok no problem, thanks. It may seem quicker to keep the code as close to how you have it at the moment but i would take the chance to learn about array manipulations :-) It may seem daunting at first but really if you read the MDN documentation, its really informative and easy to read. cheers – Francis Leigh Feb 05 '18 at 17:02
  • True :/ it's just I don't like programming but I have to do it in my company.. I prefer the hardware side of the net :D – aPugLife Feb 05 '18 at 17:08
1

Use querySelectorAll to exclude that input (and to shorten your code). Specifically, the :not([name$=FooBar_G\\]]) selector to exclude the one you want to keep out. It can also be used to specify the text inputs.

You can simply the selector using the *= contains selector if you know that there will not be false positives. :not([name*=FooBar_G])

$('form#insertForm').on("submit", function(event) {
  var inputs = this.querySelectorAll("#insertPanel input[type=text]:not([name$=FooBar_G\\]])");
  for (var i = 0; i < inputs.length; i++) {
    if (!inputs[i].value) {
      inputs[i].focus();
      event.preventDefault()
      $("#formAlert").show(400);
      break;
    }
  }
});

And to do it in a more modern way, I'd do this:

document.querySelector('form#insertForm').addEventListener("submit", function(event) {
  const inp = Array.from(
     this.querySelectorAll("#insertPanel input[type=text]:not([name$=FooBar_G\\]])")
  ).find(inp => !inp.value);

  if (inp) {
    inp.focus();
    event.preventDefault()
    $("#formAlert").show(400);
  }
});
  • Thanks for this answer! I'm executing in the test server and the result is not yet the one expected. I see you are also editing it, I will try again it soon and let you know. Anyway, the code is slightly different than the one I used to read, will take me some more minutes to understand it better! – aPugLife Feb 05 '18 at 16:48
  • @Nihvel: I had an extra `preventDefault` line somehow. Anyway, it's just about the same as your original. It just prevents the `FooBar_G` from being included in the selection by using `:not()` to exclude it. That way you don't need to check for it in the loop. It also checks the `type="text"` in the selector. Other than that, I just used `continue` to bypass inputs that have a `.value`. –  Feb 05 '18 at 16:51
  • Oh, I also used a `for-of` loop, but that's pretty new. Using `for-in` is a bad idea. Better to use a typical `for (var i=0; i < inputs.length; i++0) {` loop. –  Feb 05 '18 at 16:53
  • I changed it to the traditional loop and a similar `if` statement in the loop. –  Feb 05 '18 at 16:56
  • Tested, worked! Also, thanks for explaining it! I just have to get used to it, the more I read the code the more I understand it, as simple as this! Anyway, it worked! I only have to test it a bit more, after this, if I get no weird result, I can upvote you answer! Also, if I'm asked to add another exception? should I just add `:not([name$=FooBar_H\\]]` after the previous? – aPugLife Feb 05 '18 at 17:00
  • @Nihvel: Yes, you can use as many separate `:not()` selectors as you need. Will there be one for each letter? Or just a couple? –  Feb 05 '18 at 17:01
  • Not really, I hope not but I never know.. Just for reference and for myself to know how to edit it should it happen! – aPugLife Feb 05 '18 at 17:05
1

Some things:

1) if(SKIP) will always enter the branch as objects are truthy. You need compare sth (===)

2) If you already include such a heavy library like jquery you should use it everywhere to make it worth it

$('form[id="insertForm"]').on("submit", function (e) {
  const inputs = $("#insertPanel > input").toArray();
  const skip = $('input[name$="FooBar_G]"]')[0];
  for(const input of inputs){
    if(input === skip) continue;
    if(!input.value){
      input.focus();
      e.preventDefault();
      $("#formAlert").show(400);
      break;
    }
  }
});
Jonas Wilms
  • 132,000
  • 20
  • 149
  • 151
  • Thank you! I like this code a lot because it is simple, requires very small edits from the original source. However, I tried it and the page skips it and goes to the action="page.php" (where I added a exit; ) -> blank page. Do you see some error? – aPugLife Feb 05 '18 at 16:53
  • @nihvel oh im such an idiot. One cant iterate that jquery object with for...of without converting it to an array. By the way `for...of` is quite new, you might want to use your `for(var i = ..` loop, it will work too – Jonas Wilms Feb 05 '18 at 17:00
  • I upvoted it because I like it! It is, to me, of better understanding compared to others, because I'm old school. i'm testing another answer which worked therefore I'd give priority to this in case I accept it. Thanks anyway! also for having me explained why before it did not work (: – aPugLife Feb 05 '18 at 17:04