7

I have the following problem:

An html form that has N checkbox's used on a FormData to send a request through ajax with its information. On PHP, the $_POST['teste'] variable does not exists...

<form id="teste_form">
    <input type="checkbox" name="teste[]">
    <input type="checkbox" name="teste[]">
    <input type="checkbox" name="teste[]">
    <input type="checkbox" name="teste[]">...
</form>

<script>
    var form_data_obj = new FormData( document.getElementById('teste_form') );
    $.ajax({
        ...
        data: form_data_obj
        ...
    });
</script>

I know that I could use a "if(isset(...))" on PHP, but I really don't like that solution. To me, the best solution would be to send an empty array to PHP from the FormData object.

Obs: I tried somethings like, for example:

  • form_data_obj.append('teste[]', undefined).
  • form_data_obj.append('teste[]', 0).

But without success... The result on PHP is respectively: ["undefined"], ["0"]

I wanted to get $ _POST ['test'] = [] in PHP

Is that possible?

1
  • I'd rather specify the index in the form field names ... then you will exactly know with checked value belongs to which "position". If you foreach over the array in PHP, then "missing" indexes aren't a real problem. Commented Oct 19, 2017 at 12:17

4 Answers 4

3

Smells like this: How to Submit empty array from HTML Form Post to PHP

Workaround: You can use a hidden input element with an empty value on client side, and an empty value check on the server side. With something like this:

var appended = null;
$('.confirm_appointment').submit(function(e) {

  if (appended !== null) appended.remove();
  /************************************/
  if ($("input[name='teste[]']:checked").length == 0) {
    appended = $("<input type='hidden' name='teste[]' value=''>").appendTo($(this));
  }
  /************************************/

  e.preventDefault();
  $(this).append(decodeURIComponent($(this).serialize()) + '<br />');
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form name='confirm_appointment' method='post' class='confirm_appointment'>
  <input type='checkbox' name="teste[]" value='hello1' />
  <input type='checkbox' name="teste[]" value='hello2' />
  <input type='checkbox' name="teste[]" value='hello3' />
  <input type='checkbox' name="teste[]" value='hello4' />
  <input type='submit' class='update_appointment_button' value='submit' /><br />
</form>

And on PHP side:

$teste = array_filter($_POST["teste"]);
Sign up to request clarification or add additional context in comments.

2 Comments

The hidden input with empty value help me to much, it deserve an upvote, but the solution that I am searching for is with JS, something like form_data.append ('test', []) and receive, withou treatment, on PHP, $ _POST ['test'] = [].
Updated my answer.
0

I don't know if this is relevant, but for my implementation, the following works great. After defining the empty array, it then has to loop through the actual array physically declaring the object recursively in order to cater for objects and sub-arrays etc...

formData.append(key + '[]', []);

So used in situ, my entire FormData build looks like this...

/* ............................................................ */
/* .........runPostFetchScripts Can be used throughout [AF].... */
function runPostFetchScripts(id, str) {
    // Try and break out any scripts that need to also be run from the newly acquired HTML body (these don't naturally get run)...
    // Find ALL script tags (most basic form ONLY for now)...
    //console.log(str);
    scripts = str.split('<sc' + 'ript>');
    // First element will be content, so remove it
    if(scripts.length > 1) {
        scripts.splice(0, 1);
        one_biggy = "";
        for(i = 0; i < scripts.length; ++i) {
            // Then get rid of following content after end of script tag
            scripter = scripts[i].split("</sc" + "ript>");
            // And run what is left...
            //console.log(i + ": " + scripter[0]);
            one_biggy += scripter[0];
        }
        //console.log(one_biggy);
        eval(one_biggy);
    }
    // Phew!  This took way longer than expected [AF]!
}

/* ............................................................ */
/* .........New inclusion for FormData Validation and addition of Files, Multiple Files and Arrays to Form uploads via Ajax.... */
function genericBuildFormData(formData, data, previousKey) {
    /*
    console.log("genericBuildFormData(");
    console.log(formData);
    console.log(data);
    console.log(previousKey);
    //*/
    if(data instanceof File) {
        //console.log(previousKey + " file append...");
        formData.append(previousKey, data);

    } else if (data instanceof Object) {
        var keys = Object.keys(data);
        for(var k = 0; k < keys.length; ++k) {
            var key = keys[k];
            var value = data[key];
            /*
            console.log(k + " " + key);
            console.log(!(value instanceof File));
            console.log(value instanceof Object);
            console.log(!(Array.isArray(value)));
            console.log(value);
            //*/
            if(previousKey != '') {
                key = previousKey + '[' + key + ']';
            }
            if (!(value instanceof File) && (value instanceof Object) && !(Array.isArray(value))) {
                //console.log("Is Object, go again... " + key + "[]");
                formData.append(key + '[]', []);
                genericBuildFormData(formData, value, key);
            } else {
                if (Array.isArray(value)) {
                    //console.log(key + " is Array...");
                    // Define empty array first...
                    formData.append(key + '[]', []);
                    // Now loop through all array contents, accounting for embedded objects and sub-arrays...
                    for (var a = 0; a < value.length; ++a) {
                        //console.log(a);
                        genericBuildFormData(formData, value[a], key + '[' + a + ']');
                    }
                } else {
                    //console.log(key + " append...");
                    formData.append(key, value);
                }
            }
        }
    } else {
        //console.log(previousKey + ": " + data + " append...");
        formData.append(previousKey, data);
    }
}
/* ............................................................ */
/* .............genericAjaxCall Can be used throughout [AF].... */
function genericAjaxCall(GetPost, FullUrl, PostParams, Container, id, callback) {
    /*
    console.log("genericAjaxCall(...");
    console.log(FullUrl);
    console.log(PostParams);
    console.log(Container);
    console.log(id);
    //*/
    var GET_POST = GetPost.toUpperCase();
    var jacks = {
        url: FullUrl,
        type: GET_POST,
        async: true,
        processData: false, // Due to contentType, assume WE have got the data right, so do not allow AJAX to find fault with what we have done (files and arrays will fail otherwise) [AF]
        contentType: false, // Let Ajax work this out for us seeing as we are going to be mixing arrays, objects and files as well as primitives, so don't tell it anything [AF]
        success: function(strResult) {
            populateContainer = (Container ? document.getElementById(Container) : false);
            //console.log(populateContainer);
            if(populateContainer) {
                //populateContainer.innerHTML = ""; // To drop possible scroll values
                populateContainer.innerHTML = strResult;

                //console.log(strResult);
                if(callback != null) {
                    window.setTimeout(function() {
                        callback(id, strResult);
                    }, 100);
                }
            } else {
                //console.log("ajax.strResult: " + FullUrl + " " + id + " = " + strResult);
                if(callback != null) {
                    window.setTimeout(function() {
                        callback(id, strResult);
                    }, 100);
                }
            }
        },
        error: function(jqXHR, textStatus, errorThrown) {
            populateContainer = document.getElementById(Container);
            if(populateContainer) {
                populateContainer.innerHTML = "Error: " + textStatus + " - " + errorThrown;
            } else {
                if(callback != null) {
                    window.setTimeout(function() {
                        callback(id, null, 'Error: ' + textStatus + ' - ' + errorThrown);
                    }, 100);
                } else {
                    console.log('Error: ' + textStatus + ' - ' + errorThrown);
                }
            }
        }
    };
    if(GET_POST == "POST") {
        //console.log(PostParams);
        // Use FormData for File Upload inclusion
        var myFormData = new FormData();
        genericBuildFormData(myFormData, PostParams, '');
        jacks.processData = false;
        jacks.contentType = false;
        jacks.data = myFormData;
    }
    //console.log(jacks);
    $.ajax(jacks);
}

And the calling code looks like this (it is recursive, so bear that in mind when considering the parameters sent to the genericBuildFormData function)...

var myFormData = new FormData();
genericBuildFormData(myFormData, PostParams, '');

The resulting data when viewed in chrome's "Network Headers" (on commit) looks something like this...

additional[]: 
additional[0]: null
additional[1][id]: 7715
additional[1][ex]: Permanent Exclusion
additional[1][mi]: 1
additional[2]: null
additional[3]: null
additional[4]: null

... where array elements 0,2,3,4 are empty and element 1 is an embedded object.

Hope this helps. Shalom.

Comments

0

After trying for a few days, I think that the following method is the best option

if you can send null you should do this

yourFormData.append('key', '');

but if your key is not nullable you need to send another request alongSide formData with axios or fetch api for example


let {data} = await axios.post('url',yourFormData,
      {
        headers: {
          'Content-Type': 'multipart/form-data',
          Accept: 'application/json',
        },
      });
await axios.patch('url',{id:data.id,yourKey:[]});

Comments

-1

This is definitely possible even without jQuery.

yourFormData.append('key', []);

4 Comments

PHP Error: array_filter() expects parameter 1 to be array, string given... but even so, my PHP code is generic. I do not want to change it until I'm sure it's not possible to send an empty array by FormData.
This doesnt have anything to do with PHP. An empty array in form data results in an empty string - as can be seen the network tab of developer tools.
it appends string as '[]' but not an empty array.
This is completely wrong, adds an entry with the key of "key" and the value is and empty string! Not even an array as string. After doing this operation, this: Object.fromEntries(yourFormData) will result in this: {key: ''}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.