"Dependent" not working with a field that is an array

"Dependent" not working with a field that is an array

rf1234rf1234 Posts: 2,801Questions: 85Answers: 406

I noticed that "dependent" wasn't triggered by a change in a field that contains an array of ids (department ids that the user selects in a selectize field).

I have a use case that documents may not be uploaded if the user selects a department that doesn't allow this. Hence I wanted to do an ajax call using "dependent" for this. This didn't work:

editor
    .dependent('ctr_govdept[].id', function (val, data, callback) {
        ... do something
    })

So I ended up rolling my own "poor man's" version of "dependent" and "undependent" like this:

editor
    .on('open', function (e, mode, action) {
        var self = this;
        ctrGovdeptIds = '';
        $( self.field('ctr_govdept[].id').node() ).change( function() {
            if ( self.val("ctr_govdept[].id").toString() !== ctrGovdeptIds ) {
                ctrGovdeptIds = self.val("ctr_govdept[].id").toString();
                $.ajax({
                    type: "POST",
                    url: 'actions.php?action=checkDocUploadPermission',
                    data: {
                        ctrGovdeptIds: ctrGovdeptIds //comma separated string
                    },
                    success: function (blockUpload) {   
                        if ( blockUpload <= 0 ) {
                            $( self.field('file[].id').node() ).removeClass("hidden");
                        } else {
                            self.set( {'file[].id': []} );
                            $( self.field('file[].id').node() ).addClass("hidden");
                        }
                    }
                });
            }
        });
        $( self.field('ctr_govdept[].id').node() ).change();
    })
    .on('close', function() {
        $( this.field('ctr_govdept[].id').node() ).off( 'change' );
    })

I also noticed that this didn't work either:

self.set( {'file[].id': []} )
    .hide(['file[].id']);

I had to replace it with the code above.

Any ideas why "dependent" doesn't work with fields containing an array? Or is that only me having the issue?

This question has an accepted answers - jump to answer

Answers

  • allanallan Posts: 61,446Questions: 1Answers: 10,054 Site admin

    dependent() listens for the change event from whatever element field().input() replies with. So if the field doesn't trigger change, or there are no elements that it can listen on, then unfortunately it just won't work.

    You can use the event option of the third argument passed to dependent() to change the event being listened for if you want. However, in this case I wonder if it is because Selectize doesn't trigger change on the field().input() return.

    Interesting that the chain of set('...', []).hide() doesn't work. Looking at the code, I can't immediately see why that would be. In the short term, you could reverse the calls so you call hide before set in the chain perhaps?

    Allan

  • rf1234rf1234 Posts: 2,801Questions: 85Answers: 406

    I don't think you are right regarding selectize, but I probably caused it to break myself ... see below. :smile:

    I am glad I found the work around relatively quickly. I will just leave it as it is. I checked all of my "dependents" - and they were never with an array of values only with fields that contain individual values. Hence I suspected the array is the problem.

    This here works like a charm - and it is also a selectize field (but may contain only one value):

    contractEditor
        //preset Iban with saved iban from table govdept as soon as department
        //is being selected
        .dependent('contract.govdept_id', function (val, data, callback) {
            if (val > '0' && data.values['contract.iban'] <= '') {
                $.ajax({
                    type: "POST",
                    url: 'actions.php?action=getIban',
                    async: true,
                    data: {govdeptId: val},
                    dataType: "json",
                    success: function (data) {
                        return contractEditor.
                                set({'contract.iban': data.iban});
                    }
                });
            }
        })
    

    So this is the selectize field that works with dependent:

    fields: [{
            label: lang === 'de' ? 'Für:' : 'For:',
            name: "contract.govdept_id", //render gov_name, govdept_name
            type: "selectize",
            opts: {
                create: false,
                maxItems: 1,
                openOnFocus: false,
                allowEmptyOption: false,
                placeholder: placeholder
            }
        },
    

    And this is the one that doesn't work with dependent:

    }, {
                label: lang === 'de' ? 'Abteilungsauswahl:' : 'Department selection:',
                name:  "ctr_govdept[].id" //removed and added dynamically
    

    I suspect that the following might be the cause of it?! On "initCreate" and "initEdit" I remove and add the field dynamically. Maybe that causes "dependent" not to work properly?! What do you think, Allan?

    The code below is needed to dynamically change the field options. Unfortunately Editor only allows to retrieve one set of field options for all records, it does not allow to retrieve individual field options for each record read from the database. Then there is another problem: Using a "select" field you can dynamically change the field options, but not with "selectize": The only way to achieve this is to delete the field and add it with the new options retrieved from the server using a proprietary ajax call.

    Here is the code for this:

    .on ( 'initCreate', function ( e ) {
        this.dependent('ctr.end_date', function (val, data, callback) {
            var self = ctrEditor;
    //            self.set( { 'ctr.original_end_date': self.val('ctr.end_date') } );          
            ctrEndDateStandardDependencies(self);
        })
        ctrTable.rows().deselect(); //we must deselect otherwise the on select action overwrites this
        $.ajax({
            type: "POST",
            url: 'actions.php?action=getCtrGovdeptOptions',
            data: {
    //create: we submit zero to avoid departments, categories etc. being kept from selected records
                ctr_id: 0
            },
            dataType: "json",
            success: function (data) {   
                ctrGovdeptOptions = data;
                ctrEditor.clear("ctr_govdept[].id"); 
                ctrEditor.add( {
                    label: lang === 'de' ? 'Abteilungsauswahl:' : 'Department selection:',
                    name: "ctr_govdept[].id", 
                    type: "selectize",
                    options: ctrGovdeptOptions,
                    opts: {
                        create: false,
                        maxItems: null,
                        openOnFocus: true,
                        allowEmptyOption: false,
                        placeholder: lang === 'de' ? 'Bitte wählen Sie eine oder mehrere Abteilungen' : 'Please select one or more departments',
                    }
                }, "ctr.ctr_partner" );
                $('div.DTE_Body div.DTE_Body_Content div.DTE_Field').addClass("two-cols");
            }
        });
        $.ajax({
            type: "POST",
            url: 'actions.php?action=getCtrLabelOptions',
            data: {
    //create: we submit zero to avoid departments, categories etc. being kept from selected records
                ctr_id: 0
            },
            dataType: "json",
            success: function (data) {   
                ctrLabelOptions = data;
                ctrEditor.clear("ctr_label[].id"); 
                ctrEditor.add( {
                    label: lang === 'de' ? 'Labels:' : 'Labels:',
                    name:  "ctr_label[].id", 
                    type: "selectize", 
                    options: ctrLabelOptions,
                    opts: {
                        create: true,
                        createFilter: function(val) {
                          return ( isNaN(val) || val.indexOf('.') > -1 || val.indexOf('-') > -1 ) ? val : false;
                        },
                        maxItems: null,
                        openOnFocus: true,
                        allowEmptyOption: false,
                        placeholder: lang === 'de' ? 
                            "Bitte Labels wählen oder hinzufügen" : 
                            "Please select labels or add some",                
                        render: {
                            option_create: function(data, escape) {
                                var add = lang === 'de' ? "Neu: " : "Add ";      
                                return '<div class="create">' + add + '<strong>'
                                       + escape(data.input) + '</strong>&hellip;</div>';
                            }
                          }
                        }
                }, "ctr_govdept[].id" );
                $('div.DTE_Body div.DTE_Body_Content div.DTE_Field').addClass("two-cols");
            }
        });
    })
    .on('initEdit', function ( e, node, data, items, type ) {
        this.dependent('ctr.end_date', function (val, data, callback) {
            ctrEndDateStandardDependencies(ctrEditor);
        });
        this.clear("ctr_govdept[].id"); 
        this.add( {
            label: lang === 'de' ? 'Abteilungsauswahl:' : 'Department selection:',
            name: "ctr_govdept[].id", 
            type: "selectize",
            options: ctrGovdeptOptions,
            opts: {
                create: false,
                maxItems: null,
                openOnFocus: true,
                allowEmptyOption: false,
                placeholder: lang === 'de' ? 'Bitte wählen Sie eine oder mehrere Abteilungen' : 'Please select one or more departments',
            }
        }, "ctr.ctr_partner" );
        this.clear("ctr_label[].id"); 
        this.add( {
            label: lang === 'de' ? 'Labels:' : 'Labels:',
            name:  "ctr_label[].id", 
            type: "selectize", 
            options: ctrLabelOptions,
            opts: {
                create: true,
                createFilter: function(val) {
                  return ( isNaN(val) || val.indexOf('.') > -1 || val.indexOf('-') > -1 ) ? val : false;
                },
                maxItems: null,
                openOnFocus: true,
                allowEmptyOption: false,
                placeholder: lang === 'de' ? 
                    "Bitte Labels wählen oder hinzufügen" : 
                    "Please select labels or add some",                
                render: {
                    option_create: function(data, escape) {
                        var add = lang === 'de' ? "Neu: " : "Add ";      
                        return '<div class="create">' + add + '<strong>'
                               + escape(data.input) + '</strong>&hellip;</div>';
                    }
                  }
                }
        }, "ctr_govdept[].id" );
        $('div.DTE_Body div.DTE_Body_Content div.DTE_Field').addClass("two-cols");
    })
    

    Calling "hide" before "set" doesn't make a difference. I suspect the problem arises because the file upload consists of multiple elements?! Otherwise I never had any problems with "set" and "hide".

  • allanallan Posts: 61,446Questions: 1Answers: 10,054 Site admin
    Answer ✓

    On "initCreate" and "initEdit" I remove and add the field dynamically. Maybe that causes "dependent" not to work properly?!

    Yup - that would do it. dependent() binds its event listener to whatever field().input() returns, as I noted above, so if you were to delete the field (and thus also the node) then the event listener is gone. If you add a new field, then it wouldn't automatically be assigned any existing event listeners - you would need to run dependent() again.

    Allan

  • rf1234rf1234 Posts: 2,801Questions: 85Answers: 406

    Thanks for clarifying, Allan!

This discussion has been closed.