web-dev-qa-db-fra.com

jQuery sérialiser n'enregistre pas les cases à cocher

J'utilise jQuery.serialize pour récupérer tous les champs de données d'un formulaire.

Mon problème est qu'il ne récupère pas les cases à cocher qui ne sont pas cochées.

Il comprend ceci:

<input type="checkbox" id="event_allDay" name="event_allDay" class="checkbox" checked="checked" />

mais pas ça

<input type="checkbox" id="event_allDay" name="event_allDay" class="checkbox" />

Comment puis-je obtenir des "valeurs" de cases à cocher non cochées?

65
Steven

jQuery serialize imite de près la façon dont un navigateur standardiserait un formulaire avant de l'ajouter à la chaîne de requête ou au corps POST de la demande. Les cases à cocher non cochées ne sont pas incluses par le navigateur, ce qui est logique car elles ont un état booléen - elles sont sélectionnées par l'utilisateur (inclus) ou non sélectionnées par l'utilisateur (non incluses).

Si vous avez besoin qu'il soit dans la publication en série, vous devriez vous demander "pourquoi? Pourquoi ne pas simplement vérifier son existence dans les données?".

Gardez à l'esprit que si la façon dont JavaScript sérialise les données de formulaire se comporte différemment de la façon dont le navigateur le fait, vous éliminez ainsi toute possibilité de dégradation progressive de votre formulaire. Si vous devez absolument le faire, utilisez simplement une boîte <select> avec les options Oui/Non. Au moins dans ce cas, les utilisateurs dont JS est désactivé ne sont pas aliénés de votre site et vous n'allez pas contre le comportement défini dans la spécification HTML.

<select id="event_allDay" name="event_allDay">
   <option value="0" selected>No</option>
   <option value="1">Yes</option>
</select>

J'ai déjà vu cela sur certains sites et je me suis toujours dit: "pourquoi n'utilisent-ils pas simplement une case à cocher"?

64
Andy E

Pour tirer parti de la réponse géniale d'azatoth, je l'ai légèrement étendue pour mon scénario:

    /* Get input values from form */
    values = jQuery("#myform").serializeArray();

    /* Because serializeArray() ignores unset checkboxes and radio buttons: */
    values = values.concat(
            jQuery('#myform input[type=checkbox]:not(:checked)').map(
                    function() {
                        return {"name": this.name, "value": false}
                    }).get()
    );
70
mydoghasworms

Ce n'est pas le cas, car sérialiser est destiné à être utilisé comme chaîne de requête et, dans ce contexte, non coché signifie que ce n'est pas du tout dans la chaîne de requête.

Si vous voulez vraiment obtenir les valeurs des cases à cocher non cochées, utilisez: (non testé)

var arr_unchecked_values = $('input[type=checkbox]:not(:checked)').map(function(){return this.value}).get();
25
azatoth

si vous souhaitez ajouter des cases à cocher non sérialisées à votre chaîne de requête, ajoutez ce qui suit à votre fonction d'envoi jQuery:

var moreinfo = '';

$('input[type=checkbox]').each(function() {     
    if (!this.checked) {
        moreinfo += '&'+this.name+'=0';
    }
});
17
Ash

Voici une autre solution qui étend la méthode "serializeArray" (tout en préservant le comportement d'origine).

//Store the reference to the original method:

var _serializeArray = $ ji.fn.serializeArray;

//Now extend it with newer "unchecked checkbox" functionality:
$ji.fn.extend({
    serializeArray: function () {
        //Important: Get the results as you normally would...
        var results = _serializeArray.call(this);

        //Now, find all the checkboxes and append their "checked" state to the results.
        this.find('input[type=checkbox]').each(function (id, item) {
            var $item = $ji(item);
            var item_value = $item.is(":checked") ? 1 : 0;
            var item_name = $item.attr('name');
            var result_index = null;
            results.each(function (data, index) {
                if (data.name == item_name) {
                    result_index = index;
                }
            });

            if (result_index != null) {
                // FOUND replace previous value
                results[result_index].value = item_value;
            }
            else {
                // NO value has been found add new one
                results.Push({name: item_name, value: item_value});
            }
        });
        return results;
    }
});

Cela ajoutera des résultats booléens "vrais" ou "faux", mais si vous préférez, vous pouvez utiliser "1" et "0" respectivement, en modifiant la valeur en value: $item.is(":checked") ? 1 : 0.

Usage

Comme d'habitude, appelez la méthode sur votre formulaire: $form.serialize() ou $form.serializeArray(). Ce qui se passe, c’est que serialize utilise de toute façon serializeArray, de sorte que vous obtenez les résultats appropriés (bien que le format soit différent) avec la méthode que vous appelez.

4
bigp

Une technique que j'ai utilisée dans mes propres systèmes et que je crois être utilisée par Struts consiste à inclure ... 

<input type="hidden" name="_fieldname" value="fieldvalue"/> 

... immédiatement à côté de la case à cocher dans le cadre de la logique de création de formulaire. 

Cela me permet de reconstituer quelles cases ont été servies dans le formulaire mais non sélectionnées, avec un tout petit peu de logique supplémentaire pour faire ce qui est servi et ce qui a été coché. La soumission est également identique dans le contenu, que vous utilisiez du HTML ou un style de soumission AJAX.

Selon la technologie que vous utilisez côté serveur, vous pouvez utiliser cette syntaxe ...

<input type="hidden" name="_fieldname[]" value="fieldvalue"/>

... pour faciliter la saisie de ces valeurs sous forme de liste.

3
Cefn Hoile

jQuery serialize obtient l'attribut value des entrées.  

Maintenant, comment faire fonctionner la case à cocher et le bouton radio? Si vous définissez l'événement de clic de la case à cocher ou du bouton radio 0 ou 1, vous pourrez voir les modifications.

$( "#myform input[type='checkbox']" ).on( "click", function(){
     if ($(this).prop('checked')){
          $(this).attr('value', 1);
     } else {
          $(this).attr('value', 0);
     }
 }); 

 values = $("#myform").serializeArray();

et aussi chaque fois que vous souhaitez cocher la case avec l'état coché, par exemple. php

<input type='checkbox' value="<?php echo $product['check']; ?>" checked="<?php echo $product['check']; ?>" />
3
Fury

Cela définira les valeurs de vos cases à cocher de formulaire sur les booléens en utilisant leur état coché.

var form = $('#myForm');
var data = form.serializeObject();

$('#myForm input[type=checkbox]').each(function() { data[this.name] = this.checked; });

La structure que nous utilisons crée deux entrées avec le même nom, ce qui entraîne un comportement inattendu lors de la sérialisation du formulaire. J'obtiendrais chaque valeur de case à cocher analysée comme un tableau à deux éléments avec des valeurs de chaîne. Selon la façon dont vous mappez les données côté serveur, vous pouvez obtenir des résultats inattendus.

2
Jecoms

L'astuce consiste à intercepter la publication du formulaire et à changer les cases à cocher en champs de saisie masqués.

Exemple: Plain Submit

$('form').on("submit", function (e) {
    //find the checkboxes
    var $checkboxes = $(this).find('input[type=checkbox]');

    //loop through the checkboxes and change to hidden fields
    $checkboxes.each(function() {
        if ($(this)[0].checked) {
            $(this).attr('type', 'hidden');
            $(this).val(1);
        } else {
            $(this).attr('type', 'hidden');
            $(this).val(0);
        }
    });
});

Exemple: AJAX

Si vous postez le formulaire via ajax pour ne pas mettre à jour l'interface utilisateur, vous devez parcourir quelques étapes supplémentaires.

$('form').on("submit", function (e) {
    e.preventDefault();

    //clone the form, we don't want this to impact the ui
    var $form = $('form').clone();

    //find the checkboxes
    var $checkboxes = $form.find('input[type=checkbox]');

    //loop through the checkboxes and change to hidden fields
    $checkboxes.each(function() {
        if ($(this)[0].checked) {
            $(this).attr('type', 'hidden');
            $(this).val(1);
        } else {
            $(this).attr('type', 'hidden');
            $(this).val(0);
        }
    });

    $.post("/your/path", $form.serialize());
2
muglio

Une des raisons d'utiliser une sérialisation de case à cocher non standard qui n'est pas abordée dans la question ou dans les réponses actuelles est uniquement les champs de désérialisation (modification) explicitement spécifiés dans les données sérialisées - p. Ex. lorsque vous utilisez la sérialisation jQuery et la désérialisation vers/depuis un cookie pour enregistrer et charger les préférences.

Thomas Danemar a implémenté une modification de la méthode standard serialize() afin de prendre éventuellement une option checkboxesAsBools: http://tdanemar.wordpress.com/2010/08/24/jquery-serialize-method-and-checkboxes/ - c'est similaire à la mise en œuvre répertoriée ci-dessus par @mydoghasworms, mais également intégrée dans la norme sérialiser.

Je l'ai copié dans Github au cas où quelqu'un aurait des améliorations à apporter à tout moment: https://Gist.github.com/1572512

De plus, le plug-in "jquery.deserialize" va maintenant désérialiser correctement les valeurs de case à cocher sérialisées avec checkboxesAsBools et ignorer les cases à cocher non mentionnées dans les données sérialisées: https://github.com/itsadok/jquery.deserialize

2
Tao
var checkboxes = $('#myform').find('input[type="checkbox"]');
$.each( checkboxes, function( key, value ) {
    if (value.checked === false) {
        value.value = 0;
    } else {
        value.value = 1;
    }
    $(value).attr('type', 'hidden');
});
$('#myform').serialize();
2
user

Pour ASP.NET MVC, nous avons réussi à enregistrer un formulaire avec checkboxes via un AJAX POST avec ce qui suit, qui est une combinaison de plusieurs méthodes référencées dans cet article. , y compris suggestion de @Jecoms :

var form = $('#myForm');
// Serialize the form into a JavaScript object using the jQuery.serializeObject plugin
// https://plugins.jquery.com/serializeObject/
var data = form.serializeObject();
// Change the submitted value of checkboxes to the value of the checked property
$('#myForm input[type=checkbox]').each( function () { data[this.name] = this.checked; } );
// For a MVC controller, convert the JS object back into a query string using jQuery.param function
data = $.param(data);
// Perform AJAX POST with the form data
$.ajax({
    async: true,
    url: 'mvcActionMethodURL',
    type: 'POST',
    data: data,
    success: function (data, textStatus, xhr) {

    },
    error: function (xhr, status, error) {

    }
});
2
iCode

L'utilisation de champs de sélection, comme suggéré par Andy, n'est pas nécessairement la meilleure option pour l'expérience utilisateur, car elle nécessite deux clics de souris au lieu d'un. 

De plus, une "sélection" utilise beaucoup plus d'espace dans l'interface utilisateur qu'une case à cocher.

La réponse de Ash est une solution simple mais ne fonctionne pas dans le cas de champs de tableau

Dans mon contexte, j'ai un formulaire de longueur variable, qui contient des lignes affichant un mélange de champs de texte et de cases à cocher:

<input type="checkbox" value="1" name="thisIsAChkArray[]"/> 
<input type="text" value="" name="thisIsATxtArray[]"/>

Pour décoder les données publiées, l'ordre ordre des éléments du tableau est important. Le simple ajout des éléments non cochés à une sérialisation Jquery normale ne conserve pas l'ordre des éléments de la ligne.

Voici une solution proposée basée sur la réponse de Ash:

(function($) {
  $.fn.serializeWithChkBox = function() {
    // perform a serialize form the non-checkbox fields
    var values = $(this).find('select')
                        .add(  $(this).find('input[type!=checkbox]') )
                        .serialize();
    // add values for checked and unchecked checkboxes fields
    $(this).find('input[type=checkbox]').each(function() {
      var chkVal = $(this).is(':checked') ? $(this).val() : "0";
      values += "&" + $(this).attr('name') + "=" + chkVal;
    });
    return values;
  }
})(jQuery);
1
eosphere

J'ai eu un problème similaire et ce qui suit m'a permis de collecter toutes les valeurs d'entrée de formulaire et les cases cochées/décochées. 

var serialized = this.$('#myform input').map(function() {
return { name: this.name, id: this.id, value: this.checked ? "checked" : "false" };
});
1
wooz16

Cet exemple suppose que vous souhaitez renvoyer un formulaire via serialize et non pas serializeArray, et qu'une case à cocher non cochée signifie false:

var form = $(formSelector);
var postData = form.serialize();

var checkBoxData = form.find('input[type=checkbox]:not(:checked)').map(function () {
    return encodeURIComponent(this.name) + '=' + false;
}).get().join('&');

if (checkBoxData) {
    postData += "&" + checkBoxData;
}

$.post(action, postData);
1
Dominik Holland

J'ai utilisé cette manière et obtenir les valeurs "0" ou si coché "1". Cela indique que si nom d’entrée de case à cocher n’existe pas dans form_data sérialisé, cela signifie donc qu’elle n’est pas cochée, puis ajoutez une valeur égale à zéro (form_data += '&' + name + '=0'), mais si coché serialize() fonction l'ajoute automatiquement.

   /*get all other form inputs*/ 
   var form_data = form.serialize();

    /*get checkboxes*/
    $.each($("#form_id input[type='checkbox']"), function(){
        var name = $(this).attr('name');
        if(form_data.indexOf(name)===-1)form_data += '&' + name + '=0';
    });
0
WebMan

Vous pouvez obtenir la valeur des entrées avec jquery serialize

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="checkbox" id="event_allDay" name="event_allDay" checked="checked" onchange="isChecked(this)" value="" />
<script>
    function isChecked(element) {
        $(element).val($(element).is(':checked').toString());
    }
    isChecked('#event_allDay');
</script>

0
Mustafa Cevat Boz

ajoutez simplement une entrée cachée

<input type="hidden" name="your_specific_name">

n'a pas besoin de valeur, j'ai testé cela fonctionne pour moi

0
jk jk

parfois non cochée signifie d'autres valeurs, par exemple coché pourrait signifier oui non coché ou 0,1 etc. cela dépend du sens que vous voulez donner .. ainsi pourrait être un autre état en plus de "non coché signifie que ce n'est pas du tout dans la chaîne de requête" 

"Cela faciliterait beaucoup le stockage des informations dans la base de données. Parce qu'alors le nombre de champs de Serialize équivaudrait au nombre de champs de la table. Maintenant, je dois contrôler ceux qui manquent", vous avez raison, c'est aussi mon problème. .. il semble donc que je dois vérifier cette valeur inexistante ....

mais peut-être que cela pourrait être une solution? http://tdanemar.wordpress.com/2010/08/24/jquery-serialize-method-and-checkboxes/

0
geomorillo

Pour ceux qui utilisent la fonction serialize():

(function ($) {
    var serialize = $.fn.serialize;

    $.fn.serialize = function () {
        let values = serialize.call(this);
        let checkboxes = [];

        checkboxes = checkboxes.concat(
            $('input[type=checkbox]:not(:checked)', this).map(
            function () {
                return this.name + '=false';
            }).get()
        );

        if(checkboxes.length > 0)
            values = checkboxes.join('&') + '&' + values;

        return values;
    };
})(jQuery);
0
Isaac Adams

Vous pouvez appeler handleInputs() add dans votre fonction submit avant ajax

function handleInputs(){
    $('input[type=checkbox]').each(function() {     
        if (!this.checked) {
            $(this).attr("value","0");
        }else{
            $(this).attr("value","1");
        }
    });
}

Cela fonctionne parfaitement

0
Ferhat KOÇER

Juste pour développer les réponses ci-dessus, dans mon cas, j’ai demandé l’envoi d’un oui/non contre un seul identifiant sérialisé à mon arriéré. 

Je règle les éléments de case à cocher pour qu'ils contiennent l'ID d'une colonne de base de données particulière, alias (cochée par défaut) :

(Laravel Blade)

<div class="checkbox">
    <label>
        <input type="checkbox" value="{{ $heading->id }}" checked> {{ $heading->name }}
    </label>
</div>

Lors de ma soumission, j'ai saisi les données avec:

(jQuery)

let form = $('#formID input[type="checkbox"]').map(function() {
                return { id: this.value, value: this.checked ? 1 : 0 };
           }).get();

var data = JSON.stringify(form);
$.post( "/your/endpoint", data );
0
Grant