Etfrerrr
Etfrerrr

Reputation: 115

Extjs beforerender to set async-obtained variable

My ExtJS application displays certain UI elements depending on a boolean variable.

This boolean variable, however, is the result of calling an async function. As a result, the boolean is set to a Promise that is fulfilled, rather than true or false proper. This affects whether the UI elements are actually displayed (a Promise is not exactly a boolean, after all).

The code looks like this:

Ext.define('userDefinedComponent', {
    extend: 'Ext.Container',

    requires: ['someHelperFile'],
    

    initComponent: function () {
        var me = this,
        var enabled = someHelperFile.someAsyncFunc() // enabled is a boolean that is returned as fulfilled Promise instead

        Ext.apply(me, {
            // layout and padding
            items: [

                {
                    xtype: 'internallyDefinedForm',
                    fieldConfigs: {
                        // other fields
                        'someFormField': {
                            hidden: !enabled, // depends on enabled
                        }
                    }
                },

                {
                    xtype: 'internallyDefinedGrid',
                    columnConfigs: {
                        // other columns
                        'someColumn': {
                            hidden: !enabled, // deends on enabled
                        }
                    },
                    
                }
            ]
        })
    }
})

I want the field enabled to really be a boolean rather than a Promise. In other words, I want to wait for the someAsyncFunc to run the result, before setting hidden property of the internallyDefinedForm and internallyDefinedGrid.

What are my possibilities? I was thinking of using a beforerender, like below:

Ext.define('userDefinedComponent', {
    extend: 'Ext.Container',

    requires: ['someHelperFile'],
    

    initComponent: function () {
        var me = this;

        Ext.apply(me, {
            // layout and padding
            items: [

                {
                    xtype: 'internallyDefinedForm',
                    fieldConfigs: {
                        // other fields
                        'someFormField': {
                            hidden: !me.enabled, // depends on enabled
                        }
                    }
                },

                {
                    xtype: 'internallyDefinedGrid',
                    columnConfigs: {
                        // other columns
                        'someColumn': {
                            hidden: !me.enabled, // deends on enabled
                        }
                    },
                    listeners: {
                        beforerender: function() { // this is the beforerender
                            me.enabled = someHelperFile.someAsyncFunc();
                            console.log("beforerender triggered in grid");
                        }
                    },
                    
                }
            ]
        })
    }
})


And in fact, using the beforerender for the internallyDefinedGrid only, I can see the text "beforerender triggered in grid" triggered very early. However, the fact remains that the behavior that I observe does not correspond to what I expect: although the async someAsyncFunc should return true based on the API response it gets, such that me.enabled is true, the actual UI associated with the internallyDefinedGrid behaves as if me.enabled is false instead. I observe that the column on the UI is hidden, and this is only possible when me.enabled is false, such that the column someColumn does not appear on the grid. After all, the hidden field of someColumn is set to !enabled.

I am confident that the UI for the grid behaves not like what I expect it to, so there is a problem with the async behavior. But I'm really lost as to how to set the asynchronously obtained enabled or me.enabled field adequately.

Any help is appreciated.

Upvotes: 0

Views: 532

Answers (1)

Peter Koltai
Peter Koltai

Reputation: 9734

I would suggest to use a View Model and binding, as explained here.

Basically you define what your UI is depending on, under the data tag in the View Model (you can set the initial value here):

Ext.define('MyApp.TestViewModel', {
    extend: 'Ext.app.ViewModel',
    data: {
        something: false,
    },
}

Then you bind the visibility to this value in the view:

bind: {
    hidden: '{something}'
}

or

bind: {
    hidden: '{!something}'
}

You fetch the async data, and once you have the result, set the value in the View Model (this can be either the view or the controller):

this.getViewModel().set('something', RESULT_OF_ASYNC)

With binding ExtJS takes care of refreshing the visibility of your component every time when the value in the View Model is changed. There are good examples at the link I provided. This is a very powerful and complex feature of ExtJS, worth learning.

Upvotes: 1

Related Questions