2

I'm trying to serialize and post all form elements that may come from either witin a <form> element, or from within any other elements (div, tr, etc.).

In short, my form will come from either:

<form id="frm1">
  Name: <input ...>
  Gender: <select ...>
  <input type="button" value="Submit" onClick="submitFormData('frm1')"/>
</form>

and sometimes, I have html TABLE so cannot have a <form> in them, therefor I use:

<table>
  <tr id="frm1">
    <td><input type...></td>
    <td><select...></td>
    <td><input type="button" value="Submit" onClick="submitFormData('frm1')"/></td>
  </tr>
  <tr id="frm2">
    <td><input type...></td>
    <td><select...></td>
    <td><input type="button" value="Submit" onClick="submitFormData('frm2')"/></td>
  </tr>
</table>

I can't seem to figure out how to pull out and serialize all form elements (inputs, selects, etc.) FROM within a given element.

My code so far :

const ERROR_TYPE_FATALERROR = 1;
const ERROR_TYPE_INPUTERROR = 2;
const ERROR_TYPE_GLOBALMESSAGE = 3;

function submitFormData(formid) {

  var formNode = document.getElementById(formid);

  $.ajax({
    type: 'POST',
    url: $(location).attr('href'),
    // data: jQuery('#' + formid + ' input').serialize(), // this works, but will only get <INPUT...>s
    data: formNode.serialize(), // this doesn't work
    dataType : "json",
  }).done(function(response) {

    // If we have response, then it's PHP that returned an error!
    if(response) {

      // error type
      switch (response.type) {

        case ERROR_TYPE_GLOBALMESSAGE:
          // unhide informational box (i.e. "Data saved!")
          $('#globalMessage').addClass('d-block');
          $('#globalMessagePH').empty();
          $('#globalMessagePH').append(response.message);

          break;

        case ERROR_TYPE_FATALERROR:
          // unhide form fatal error message box showing response.message
          $('#fatalError').addClass('d-block');
          $('#fatalErrorMessagePH').empty();
          $('#fatalErrorMessagePH').append(response.message);

          break;

        case ERROR_TYPE_INPUTERROR:
          // unhide form input error messages based on response.field
          break;

        default:
          // ...
      }
    }

    // Successful post, but not response came back !?
    else {
      console.error("Post sent, but no response came back!?");
    }
  }).fail(function(response) {
    console.error("Unknown Error!"); // not sure yet how I'd get here... ?
  });

}

I had also tried adding a "data2post" class to all form elements in order get all the elements needed for post and serialize them:

var formNode = document.getElementById(formid);
var formData = formNode.getElementsByClassName('data2post');
...
  data: formData.serialize()
...

but it doesn't work: formData.serialize is not a function

As you can see from my JS snippet, I know having just

data: jQuery('#' + formid + ' input').serialize()

works, but this will only get the <INPUT...>. I need to be able to get all form elements regardless of type (inputs, select, textarea, etc.)

And even for the sake of it, might I ask at the same time, considering you folks see what I'm using this ajax for, in good practice, should I be getting the response.type, etc more in the .fail() section ? Not sure how I to do this yet in PHP, meaning trigger a failure. All I know is if I die() my script with JSON data, it'll be sent as the response...

Thanks a million for your help.

Cheers, Pat

EDIT: here is an example of my SELECT inputs:

<tr id="row_1">
  <!-- STATUS -->
  <td class="text-nowrap">
    <select name="isActive" id="isActive" class="form-control pl-2" aria-label="Account Status" aria-describedby="isActiveReq" required>
      <option value="1"  selected>Enabled</option>
      <option value="0" >Disabled</option>
    </select>

    <!-- missing field: add 'is-invalid' to the <input>'s classes to show OR 'was-validated' to the form's classes -->
    <div id="isActiveReq" class="pl-1 invalid-feedback">
      This field is required! 
    </div>
  </td>
  <td><input type="button" name="btnSave" value="Save" onClick="submitFormData('row_1')"></td>
</tr>
Pat
  • 449
  • 1
  • 4
  • 14

2 Answers2

0

try use $('#frm1').serialize();

var data = $('#frm1').serialize();

$.ajax({
  type: "POST",
  url: url,
  data: data,
  success: function(response){
     console.log(response);
  }
});
Abdo-Host
  • 2,470
  • 34
  • 33
  • This works greate if my form is within a
    tag, but will not work if my form is within a table row or any other
    elements.
    – Pat Jun 28 '20 at 18:57
0

Its OK if you don't have form element,

Clone specified id element, either its div or anything:

$('#myDiv').clone()

Append into a form element:

$('<form>').append($('#myDiv').clone()).serialize();

Below is working example, almost type of element included:

function getSerialize(id){

    let element = $("#"+id);

    // if you are using form element
    if( element.prop("tagName") === "FORM" ){
        var data = element.serialize();
    }

    // if your are using another elements
    else{
        var myInputs = element.clone();
        // this is the bug getting select box selected value when clone, so we have selected value in clone using this hack.
        element.find('select').each(function(i) {
            myInputs.find('select').eq(i).val($(this).val())
        })
        var data = $('<form>').append(myInputs).serialize();
    }

    // you can return 'data' variable from here.
    console.log(data);

}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<h1>Div Serialize</h1>
<div id="myDiv">
    <input type="text" name="name" placeholder="Name"><br><br>
    <select name="age" placeholder="Age">
        <option value="">Age</option>
        <option value="18+">18+</option>
    </select><br><br>
    <textarea name="about" placeholder="About"></textarea><br><br>
    <button onClick="getSerialize('myDiv')">Get Serialize</button>
</div>

<h1>Form Serialize</h1>
<form id="myDivForm" action="" onSubmit="return false;">
    <input type="text" name="name" placeholder="Name"><br><br>
    <select name="age" placeholder="Age">
        <option value="">Age</option>
        <option value="18+">18+</option>
    </select><br><br>
    <textarea name="about" placeholder="About"></textarea><br><br>
    <button onClick="getSerialize('myDivForm')">Get Serialize Form</button>
</form>

Hope this help.

turivishal
  • 34,368
  • 7
  • 36
  • 59
  • Well not quite. I thought it did but two problems: 1) this will only work if I'm not using a
    tag. I need to make my function work with either a
    or a , etc. 2) if I try with a table row: var myInputs = $('#'+formid).clone(); var data = $('').append(myInputs).serialize(); console.log(data); I get output: id=1&isActive=1&days=156&months=18 isActive is a SELECT with 2 possible values: 0 or 1. Regardless of what I choose, the output remains isActive=1 ! The other inputs though seem to be showing the right data
    – Pat Jun 28 '20 at 18:31
  • @Pat, Okay got it, i have updated answer, if you have used `form` then it will detect and if you have used any `other element` then it will detect. – turivishal Jun 28 '20 at 18:42
  • Yep. that par works. I had just found that, but using 'instanceof HTMLFormElement' instead... However, the clone() doesn't seem to get the right form SELECT values.. It sticks to the first value in my test case... – Pat Jun 28 '20 at 18:58
  • I just came accross https://stackoverflow.com/questions/742810/clone-isnt-cloning-select-values. This is a known bug to jQuery !? Would there be a way I could simply add a class say "data2post" on a fields I want submited (input, select, textarea, etc), regardless of what type of form controls? Then pull those in using formNode.getElementsByClassName('data2post'); I'm guessing I would then be obligated to loop the returned array (if it's always an array?) and then $newForm.append(input)... or something ? – Pat Jun 28 '20 at 19:05
  • can you add your select code in you question, if possible i will help. – turivishal Jun 28 '20 at 19:05
  • Can you check my answer, yes you are right there is a bug from JQuery, currently i have added a hack for select, it will work. – turivishal Jun 28 '20 at 19:24
  • Okay, this seems to do it. However, I do wonder with what else form controls will the clone fail (textarea?), etc.. ? Is there a list of documented things that clone doesnt work well with? lol – Pat Jun 28 '20 at 19:44
  • I've just tested with a textarea and a datalist and it seems to work. Guess it's only with SELECTs... Kinda weird this bug wasn't / won't be fixed... – Pat Jun 28 '20 at 19:51