second dojo FilteringSelect control onChange event

2019-08-03 07:16发布

问题:

I'm working with arcgis Javascript Api 3.7 (wich includes dojo 1.9.1), and I have been developing a custom templated dijit that has two filteringSelect controls, the first one gets pupulated correctly, and i have a second one that gets populated when the user selects one item from the first one setting its data store at that particular moment. this second filteringSelect gets correctly populated everytime, but something happens with the onchange event, because the function handler never gets fired, I need to do some other staff on the onchange event of the second FilterinSelect.

It seems something gets messed up with the second filteringSelect (guessing something with the handler context) but I can't figure it out yet.

My two filtering controls template declaration (part of my dijit html template:

                <tr>
                <td>
                    Capa:
                </td>
                <td>
                    <input data-dojo-type="dijit.form.ComboBox" name="layerDijit" id="layerDijit"
                           data-dojo-props="autoComplete:true, required:true, searchAttr:'name', style:'width:100%;'"
                           data-dojo-attach-point="layerDijit" data-dojo-attach-event="change:_handleLayerSelected"/>
                </td>
            </tr>
            <tr>
                <td>
                    Campo:
                </td>
                <td>
                    <input data-dojo-type="dijit.form.FilteringSelect" name="fieldDijit" id="fieldDijit"
                           data-dojo-props="autoComplete:true, required:true, searchAttr:'name', style:'width:100%;'"
                           data-dojo-attach-point="fieldDijit" data-dojo-attach-event="change:_handleFieldSelected"/>
                </td>
            </tr>

Dijit JS Script:

The code that populates the first Filtering Select

postCreate: function() {
        this.inherited(arguments);

        ....

        this.rootMapLayer = this.map.getLayer("ELAPAS");
        if (this.rootMapLayer.loaded){
            this.listLayers(this.rootMapLayer);
        }
        else{
            this.rootMapLayer.on("load", lang.hitch(this, this.listLayers));
        }

        //enlace de eventos (tested this, and it doesn't work for the second filtering select either)
        //this.fieldDijit.on('change', lang.hitch(this, this._handleFieldSelected));
        //this.layerDijit.on('change', lang.hitch(this, this._handleLayerSelected));
    },

listLayers: function() {

        var layerInfos = [];

        layerInfos = array.filter(this.rootMapLayer.layerInfos,function(info,index){
            return info.subLayerIds === null;
        });

        if(layerInfos.length === 0) {
            console.error("No se encontro ninguna capa para el servicio de mapa seleccionado");
            return;
        }

        var layersStore = new Memory({
            data: layerInfos
        });

        this.layerDijit.set('store', layersStore);
    },

The code that handles the selection change in the first filteringSelect called layerDijit and loads the data for the second one (FieldDijit):

_handleLayerSelected: function () {
        var selectedLayer = this.layerDijit.item;

        if(this.getSelectedLayerUrl() === null) {
            return;
        }

        //Se limpia el campo actual
        this.fieldDijit.set("value", "");

        //Se arma la url del layer específico para traer la información de la capa (sus campos)
        var layerUrl = this.rootMapLayer.url + "/" + selectedLayer.id;

        esri.request({
            url: layerUrl,
            content: {
                f: "json"
            },
            handleAs: "json",
            callbackParamName: 'callback',
            load: lang.hitch(this, '_handleLayerInfo'),
            error: lang.hitch(this, '_handleLayerInfoError')
        });
    },
_handleLayerInfo: function(data) {
        var layerInfo = data;
        if (!layerInfo.fields) {
            console.error("No se pudo obtener la información de los campos de la capa");
            return;
        }

        var fieldsStore = new Memory({
            data: layerInfo.fields
        });

        this.fieldDijit.set('store', fieldsStore);
    },

    getSelectedLayerUrl: function(){
        var selectedLayer = this.layerDijit.item;
        if(!selectedLayer) {
            return null;
        }
        //Se arma la url del layer específico para traer la información de la capa (sus campos)
        return this.rootMapLayer.url + "/" + selectedLayer.id;
    },

    _handleLayerInfoError: function(err){
        console.error(err);
    },

The function that doesn't get fired, the one that is supossed to handle se change event of the second filtering select:

_handleFieldSelected: function () {
        alert("doesn't get fired");
        /*var selectedField = this.fieldDijit.item;

        if(!selectedField) {
            return;
        } */
    },

Could you give me some advice about this problem?, What am I doing wrong?.

Thanks in advance

回答1:

bishop, thanks for your answer, I think I wasn't clear with my question, I do understand that the "onChange" event is supposed to get fired when the user (or something in the background) changes the selected item in the FilteringSelect, so my problem was that when the user selects an item from the second FilteringSelect control its onchange event didn't get fired.

As you suggested I tryed a simpler example (with a hard coded Memory objects) and it did work, so I started to dig a little bit more and realized that the problem was with my memory object,

Aparently when you declare a Memory object you have to make sure that there is an ID filed in the array collection objects, like in the next example:

var stateStore = new Memory({
            data: [
                {name:"Alabama" id:"AL"},
                {name:"Alaska", id:"AK"},
                {name:"American Samoa", id:"AS"},
                {name:"Arizona", id:"AZ"},
                {name:"Arkansas", id:"AR"},
                {name:"Armed Forces Europe", id:"AE"},
                {name:"Armed Forces Pacific", id:"AP"},
                {name:"Armed Forces the Americas", id:"AA"},
                {name:"California", id:"CA"},
                {name:"Colorado", id:"CO"},
                {name:"Connecticut", id:"CT"},
                {name:"Delaware", id:"DE"}
            ]
        });
        this.fieldDijit.set('store', stateStore);

When you don't explicitly tell it in the memory object declaration, it is asummed that there is a field called "id". In my case, the array that I assing to the memory object in the second filteringSelect didn't have a field called "id"

so I changed:

var fieldsStore = new Memory({
            data: layerInfo.fields
        });

for:

var fieldsStore = new Memory({
            idProperty: "name", //added this
            data: layerInfo.fields
        });

and now the event gets fired when the selected item in the second filterin select changes.



回答2:

Based on what I'm reading, I think you're expecting this code:

this.fieldDijit.set('store', fieldsStore);

to cause the second select in your co-dependent select arrangement to fire its change event -- after all, the select has "changed" in the sense that it has a different store.

But that's not what the change event means. The change event means the user has changed the selected value. So after setting a new store, if you select a value in the second drop down, your change handler should fire.

Here's an example that I think reduces yours to its simplest elements. Notice how when you select the first box's value, the second's store changes but its onchange event does not fire (as expected). But when you select the second box's value, its onchange does fire (as expected):

<!DOCTYPE html>
<html>
    <head>
        <link href='//ajax.googleapis.com/ajax/libs/dojo/1.9.1/dijit/themes/claro/claro.css' rel='stylesheet' type='text/css' />
        <script src='//ajax.googleapis.com/ajax/libs/dojo/1.9.1/dojo/dojo.js'></script>
    </head>
    <body class='claro'>
        <div data-dojo-id='s1' data-dojo-type='dojo/store/Memory' data-dojo-props='data:[{id:1,name:"A"}]'></div>
        <div data-dojo-id='s2' data-dojo-type='dojo/store/Memory' data-dojo-props='data:[{id:1,name:"C"}]'></div>
        <select data-dojo-id='first' data-dojo-type='dijit/form/ComboBox' data-dojo-props='store:s1'>
            <script type='dojo/method' event='onChange'>
                second.set('store', s2);
            </script>
        </select>

        <select data-dojo-id='second' data-dojo-type='dijit/form/ComboBox'>
            <script type='dojo/method' event='onChange'>
                alert('I am changed');
            </script>
        </select>

        <script type='text/javascript'>
        require(['dojo/ready', 'dojo/parser'], function (ready, Parser) {
            ready(function () {
                Parser.parse().then(function () {
                });
            });
        });
        </script>
    </body>
</html>

If I'm not understanding the error you're describing, can you send a simpler test case?