web-dev-qa-db-fra.com

jqgrid sélection incorrecte des valeurs d'option déroulantes dans la zone d'édition

J'utilise le formulaire de modification. Il existe deux zones de sélection dans le formulaire. Une zone de sélection est le pays, une autre zone de sélection est l'État. La zone de sélection d'état dépend du pays sélectionné et sera renseignée de manière dynamique. Par exemple:

Pays:

US (valeur d'option = 1)
UK (valeur d'option = 2)

Etat pour US:

Alabama (valeur d'option = 1)
Californie (valeur d'option = 2)
Floride (Valeur d'option = 3)
Hawaii (valeur d'option = 4)

Etat pour le Royaume-Uni:

Londres (valeur d'option = 5)
Oxford (valeur d'option = 6)

Comme vous pouvez le voir ci-dessus, l'id de l'état pour uk commence par 5. Lorsque je modifie un enregistrement contenant Country id=2 (UK) et State id=6 (Oxford), le formulaire de modification s'affiche correctement: le pays est Royaume-Uni et l'État est Oxford. Mais si vous déroulez la boîte de sélection d'état, le texte de l'option est correct (il indique London Oxford) mais la valeur de l'option commencera à 0. Ce qui devrait être correct, c'est que la valeur de l'option commence à 5.

Si vous sélectionnez et modifiez la liste déroulante du pays en États-Unis, puis revenez au Royaume-Uni, la valeur de l'option sera renseignée correctement (à partir de 5).

Ma question est la suivante: comment pouvons-nous renseigner la zone de sélection de l'état avec la valeur d'option correcte en fonction du pays dans la zone d'édition lors du chargement du formulaire de modification?

14
Alex

La réponse à votre question dépend un peu de la source où vous recevez les informations affichées sous "État pour les États-Unis" et "État pour le Royaume-Uni". JqGrid prend en charge deux possibilités: 1) l’utilisation du paramètre value de editoptions 2) l’utilisation des paramètres dataUrl et buildSelect du paramètre editoptions . La première méthode est la meilleure en cas d’édition locale ou si la liste des options possibles est statique. Le second choix sera utilisé dans le cas où les informations sur les états, les pays et les états de certains pays seront obtenues par requête AJAX de la base de données. Je décris la solution sur l'exemple d'utilisation du paramètre value pour ne pas avoir de dépendances avec les composants du serveur. La plupart des parties de l'implémentation sont les mêmes dans les cas d'utilisation de dataUrl et buildSelect.

J'ai fait l'exemple vivant qui montre ce dont vous avez besoin.

Le problème principal est que les valuesur editoptions sont utilisés une seule fois au moment de l’initialisation. À l'intérieur de dataInit function, on peut écraser la value, mais après la modification de la valeur dans la première zone de sélection/liste déroulante avec pays, la seconde zone de sélection/liste déroulante avec états doit être reconstruite manuellement. Pour ce faire, il faut comprendre que l'élément HTML sélectionné a un identifiant construit à partir de l'ID de ligne '_' et du nom de la colonne: rowId + "_State". De plus, il est important que la valeur value de la editoptions soit réinitialisée à la valeur initiale, de sorte que tout identificateur d'état puisse être décodé sous le nom d'état.

Voici le code de l'exemple :

var countries = { '1': 'US', '2': 'UK' };
var states = { '1': 'Alabama', '2': 'California', '3': 'Florida', '4': 'Hawaii', '5': 'London', '6': 'Oxford' };
var statesOfCountry = {
    1: { '1': 'Alabama', '2': 'California', '3': 'Florida', '4': 'Hawaii' },
    2: { '5': 'London', '6': 'Oxford' }
};
var mydata = [
    { id: '0', Country: '1', State: '1', Name: "Louise Fletcher" },
    { id: '1', Country: '1', State: '3', Name: "Jim Morrison" },
    { id: '2', Country: '2', State: '5', Name: "Sherlock Holmes" },
    { id: '3', Country: '2', State: '6', Name: "Oscar Wilde" }
];

var lastSel = -1;
var grid = jQuery("#list");
var resetStatesValues = function () {
    grid.setColProp('State', { editoptions: { value: states} });
};
grid.jqGrid({
    data: mydata,
    datatype: 'local',
    colModel: [
        { name: 'Name', width: 200 },
        { name: 'Country', width: 100, editable: true, formatter: 'select',
            edittype: 'select', editoptions: {
                value: countries,
                dataInit: function (elem) {
                    var v = $(elem).val();
                    // to have short list of options which corresponds to the country
                    // from the row we have to change temporary the column property
                    grid.setColProp('State', { editoptions: { value: statesOfCountry[v]} });
                },
                dataEvents: [
                    {
                        type: 'change',
                        fn: function(e) {
                            // To be able to save the results of the current selection
                            // the value of the column property must contain at least
                            // the current selected 'State'. So we have to reset
                            // the column property to the following
                            //grid.setColProp('State', { editoptions:{value: statesOfCountry[v]} });
                            //grid.setColProp('State', { editoptions: { value: states} });
                            resetStatesValues();

                            // build 'State' options based on the selected 'Country' value
                            var v = parseInt($(e.target).val(), 10);
                            var sc = statesOfCountry[v];
                            var newOptions = '';
                            for (var stateId in sc) {
                                if (sc.hasOwnProperty(stateId)) {
                                    newOptions += '<option role="option" value="' +
                                                  stateId + '">' +
                                                  states[stateId] + '</option>';
                                }
                            }

                            // populate the new
                            if ($(e.target).is('.FormElement')) {
                                // form editing
                                var form = $(e.target).closest('form.FormGrid');
                                $("select#State.FormElement", form[0]).html(newOptions);
                            } else {
                                // inline editing
                                var row = $(e.target).closest('tr.jqgrow');
                                var rowId = row.attr('id');
                                $("select#" + rowId + "_State", row[0]).html(newOptions);
                            }
                        }
                    }
                ]
            }
        },
        {
            name: 'State', width: 100, editable: true, formatter: 'select',
            edittype: 'select', editoptions: { value: states }
        }
    ],
    onSelectRow: function (id) {
        if (id && id !== lastSel) {
            if (lastSel != -1) {
                resetStatesValues();
                grid.restoreRow(lastSel);
            }
            lastSel = id;
        }
    },
    ondblClickRow: function (id, ri, ci) {
        if (id && id !== lastSel) {
            grid.restoreRow(lastSel);
            lastSel = id;
        }
        resetStatesValues();
        grid.editRow(id, true, null, null, 'clientArray', null,
                        function (rowid, response) {  // aftersavefunc
                            grid.setColProp('State', { editoptions: { value: states} });
                        });
        return;
    },
    editurl: 'clientArray',
    sortname: 'Name',
    height: '100%',
    viewrecords: true,
    rownumbers: true,
    sortorder: "desc",
    pager: '#pager',
    caption: "Demonstrate dependend select/dropdown lists (edit on double-click)"
}).jqGrid('navGrid','#pager', 
          { edit: true, add: true, del: false, search: false, refresh: false },
          { // edit options
              recreateForm:true,
              onClose:function() {
                  resetStatesValues();
              }
          },
          { // add options
              recreateForm:true,
              onClose:function() {
                  resetStatesValues();
              }
          });

UPDATED: J'ai mis à jour le code ci-dessus pour qu'il fonctionne également en cas de modification de formulaire. Vous pouvez le voir en direct ici . Comme jqGrid ne prend pas en charge l’édition locale pour l’édition de formulaire, je n’ai pas pu tester le code. Néanmoins, j'espère avoir tiré le meilleur parti des modifications requises.

UPDATED 2 : J'ai étendu le code ci-dessus pour prendre en charge

  1. Édition en ligne, édition de formulaire, barre d'outils de recherche et recherche avancée
  2. Les boutons de navigation précédents ou suivants dans le formulaire de modification
  3. Amélioration de la prise en charge du clavier dans les sélections (le problème de rafraîchissement de la sélection dépendante dans certains navigateurs est résolu)

La nouvelle version de la démo est ici . Le code modifié de la démo que vous trouverez ci-dessous:

var countries = { '1': 'US', '2': 'UK' },
    //allCountries = {'': 'All', '1': 'US', '2': 'UK'},
    // we use string form of allCountries to have control on the order of items
    allCountries = ':All;1:US;2:UK',
    states = { '1': 'Alabama', '2': 'California', '3': 'Florida', '4': 'Hawaii', '5': 'London', '6': 'Oxford' },
    allStates = ':All;1:Alabama;2:California;3:Florida;4:Hawaii;5:London;6:Oxford',
    statesOfUS = { '1': 'Alabama', '2': 'California', '3': 'Florida', '4': 'Hawaii' },
    statesOfUK = { '5': 'London', '6': 'Oxford' },
    // the next maps contries by ids to states
    statesOfCountry = { '': states, '1': statesOfUS, '2': statesOfUK },
    mydata = [
        { id: '0', country: '1', state: '1', name: "Louise Fletcher" },
        { id: '1', country: '1', state: '3', name: "Jim Morrison" },
        { id: '2', country: '2', state: '5', name: "Sherlock Holmes" },
        { id: '3', country: '2', state: '6', name: "Oscar Wilde" }
    ],
    lastSel = -1,
    grid = $("#list"),
    removeAllOption = function (elem) {
        if (typeof elem === "object" && typeof elem.id === "string" && elem.id.substr(0, 3) !== "gs_") {
            // in the searching bar
            $(elem).find('option[value=""]').remove();
        }
    },
    resetStatesValues = function () {
        // set 'value' property of the editoptions to initial state
        grid.jqGrid('setColProp', 'state', { editoptions: { value: states} });
    },
    setStateValues = function (countryId) {
        // to have short list of options which corresponds to the country
        // from the row we have to change temporary the column property
        grid.jqGrid('setColProp', 'state', { editoptions: { value: statesOfCountry[countryId]} });
    },
    changeStateSelect = function (countryId, countryElem) {
        // build 'state' options based on the selected 'country' value
        var stateId, stateSelect, parentWidth, $row,
            $countryElem = $(countryElem),
            sc = statesOfCountry[countryId],
            isInSearchToolbar = $countryElem.parent().parent().parent().hasClass('ui-search-toolbar'),
                              //$(countryElem).parent().parent().hasClass('ui-th-column')
            newOptions = isInSearchToolbar ? '<option value="">All</option>' : '';

        for (stateId in sc) {
            if (sc.hasOwnProperty(stateId)) {
                newOptions += '<option role="option" value="' + stateId + '">' +
                    states[stateId] + '</option>';
            }
        }

        setStateValues(countryId);

        // populate the subset of contries
        if (isInSearchToolbar) {
            // searching toolbar
            $row = $countryElem.closest('tr.ui-search-toolbar');
            stateSelect = $row.find(">th.ui-th-column select#gs_state");
            parentWidth = stateSelect.parent().width();
            stateSelect.html(newOptions).css({width: parentWidth});
        } else if ($countryElem.is('.FormElement')) {
            // form editing
            $countryElem.closest('form.FormGrid').find("select#state.FormElement").html(newOptions);
        } else {
            // inline editing
            $row = $countryElem.closest('tr.jqgrow');
            $("select#" + $.jgrid.jqID($row.attr('id')) + "_state").html(newOptions);
        }
    },
    editGridRowOptions = {
        recreateForm: true,
        onclickPgButtons: function (whichButton, $form, rowid) {
            var $row = $('#' + $.jgrid.jqID(rowid)), countryId;
            if (whichButton === 'next') {
                $row = $row.next();
            } else if (whichButton === 'prev') {
                $row = $row.prev();
            }
            if ($row.length > 0) {
                countryId = grid.jqGrid('getCell', $row.attr('id'), 'country');
                changeStateSelect(countryId, $("#country")[0]);
            }
        },
        onClose: function () {
            resetStatesValues();
        }
    };

grid.jqGrid({
    data: mydata,
    datatype: 'local',
    colModel: [
        { name: 'name', width: 200, editable: true },
        { name: 'country', width: 100, editable: true, formatter: 'select', stype: 'select', edittype: 'select',
            searchoptions: {
                value: allCountries,
                dataInit: function (elem) { removeAllOption(elem); },
                dataEvents: [
                    { type: 'change', fn: function (e) { changeStateSelect($(e.target).val(), e.target); } },
                    { type: 'keyup', fn: function (e) { $(e.target).trigger('change'); } }
                ]
            },
            editoptions: {
                value: countries,
                dataInit: function (elem) { setStateValues($(elem).val()); },
                dataEvents: [
                    { type: 'change', fn: function (e) { changeStateSelect($(e.target).val(), e.target); } },
                    { type: 'keyup', fn: function (e) { $(e.target).trigger('change'); } }
                ]
            }},
        { name: 'state', width: 100, formatter: 'select', stype: 'select',
            editable: true, edittype: 'select', editoptions: { value: states },
            searchoptions: { value: allStates, dataInit: function (elem) { removeAllOption(elem); } } }
    ],
    onSelectRow: function (id) {
        if (id && id !== lastSel) {
            if (lastSel !== -1) {
                $(this).jqGrid('restoreRow', lastSel);
                resetStatesValues();
            }
            lastSel = id;
        }
    },
    ondblClickRow: function (id) {
        if (id && id !== lastSel) {
            $(this).jqGrid('restoreRow', lastSel);
            lastSel = id;
        }
        resetStatesValues();
        $(this).jqGrid('editRow', id, {
            keys: true,
            aftersavefunc: function () {
                resetStatesValues();
            },
            afterrestorefunc: function () {
                resetStatesValues();
            }
        });
        return;
    },
    editurl: 'clientArray',
    sortname: 'name',
    ignoreCase: true,
    height: '100%',
    viewrecords: true,
    rownumbers: true,
    sortorder: "desc",
    pager: '#pager',
    caption: "Demonstrate dependend select/dropdown lists (inline editing on double-click)"
});
grid.jqGrid('navGrid', '#pager', { del: false }, editGridRowOptions, editGridRowOptions);
grid.jqGrid('filterToolbar', {stringResult: true, searchOnEnter: true, defaultSearch : "cn"});

UPDATED 3 : La dernière version du code de la démo, vous trouverez ici .

35
Oleg

J'utilise le formulaire de modification. Il y a trois zones de sélection dans le formulaire. Une zone de sélection est le pays, une zone de sélection est la ville, une autre zone de sélection est la rue. La boîte de sélection de ville dépend du pays sélectionné et sera renseignée dynamiquement. La boîte de sélection de rue dépend de la ville sélectionnée et sera renseignée de manière dynamique. Je sauve Pays 、 Ville 、 Rue dans MySQL. Si je choisis un pays, comment changer de zone de sélection de ville dans le tableau MySQL

0
Owen