Lazy Loading Components with ComponentLoader


August 4, 2016
Lazy Loading Components with ComponentLoader - Menu

The Ext.ComponentLoader is perhaps one of the least discussed and lesser known features that ExtJS provides. Maybe that’s because only a few know that it can simplify how you build applications. Before showing that in an example, first I’ll briefly introduce the Ext.ComponentLoader class.
This class is available in ExtJS 4.0.0 and is used to load any content via Ext.Ajax into a Ext.Component. At the Component level, there’s a config Ext.Component.loader which accepts a configuration object or an instance of a Ext.ComponentLoader to load any remote content for the Component.

Ext.create('Ext.Component', {
    loader: {
        url: 'content.html',
        autoLoad: true
    },
    renderTo: Ext.getBody()
});

The main configs are the connection ones which are passed to Ext.Ajax and the renderer config. Through renderer, Component knows how to render the loaded content, which can be:

  • html: The response text will be added to the component as raw html, see Ext.Component#html
  • data: The JSON data received from the response is passed to the Ext.Component#update
  • component: The response is expected to be one or many Ext.Component configuration objects which are passed to Ext.container.Container#add
  • custom: Very much like a renderer function, this custom function is used to parse and process the response so that you can configure the Component as desired.

If html, data or component don’t fit your needs, the custom approach allows you to render pretty much anything. For example, one can build a lazy Ext.menu.Menu which will lazily load all of its menuitems from the server. That can be done with the Ext.Component.loader so when the user clicks on any first level menuitem of a Menu, based on the given parameters, the loader loads the menuitems from the server and then the given renderer builds your Menu.

ComponentLoader - Lazy Loading Components - menu


Ext.define('Ux.view.Menu', {
    extend: 'Ext.menu.Menu',
    xtype: 'mymenu'
    minHeight: 100, // Give some space to see the load mask
    loader: {
        loadMask: {
            msg    : 'Loading...'
        },
        url: '/api/load_tree',
        renderer: function(loader, response, active){
            var success = true;
            var target = loader.getTarget();
            var items = [];
            var data;
            var i,ln;

            try {
                data = Ext.decode(response.responseText).data;

                // Loop through the data and build the menuitems configs
                for (i = 0, ln = data.length; i < ln; i++) {
                    items.push(target.getMenuItemConfig(data[i]));
                }

            } catch (e) {
                success = false;
            }

            // Insert the menuitems in the Menu
            if (success) {
                target.suspendLayouts();
                if (active.removeAll) {
                    target.removeAll();
                }
                target.add(items);
                target.resumeLayouts(true);
            }
            
            //Return true if ok, to call the callback and fire 'load' event
            return success;
        }
    }
});

The lazy loading can be done through the Ext.Config and Ext.mixin.Bindable mixin. The Ajax parameters are exposed as an evented Ext.Config config so they can be bound through the Bindable mixin at the Menu level:

  menu: {
      xtype: 'mymenu',
      bind: {
          extraParams: '{myData.myMenuParams}'
      }
  }

Then we have a listener at the config level, so whenever the extraParams changes, the menu loads the remote data and builds itself.

    listeners: {
        extraparamschange: function (menu, value) {
            // If the menu is visible load the subitems,
            // if not load them at first menu show.
            if (menu.isVisible()) {
                menu.loadMenuItems(value);
            } else {
                menu.on('beforeshow', menu.loadMenuItems, menu, {
                    single: true
                });
            }
        }
    },

    // Here you can pre-process your params before applying 
    // them on the Loader
    applyExtraParams: function (myMenuParams) {
        if (Ext.isArray(myMenuParams)){
            return {
                myMenuParams: myMenuParams[0]
            }
        }
    },

    loadMenuItems: function () {
        this.getLoader().load({
            params: this.getExtraParams()
        });
    }

Lastly, in case you have to load the tooltips remotely, you can do it in the menu afterRender:

 getMenuItemConfig: function (rec) {
  return {
      text: rec.get('title'),
      afterRender: function () {
          Ext.Ajax.request({
              url: '/api/mylazymenu/tooltip/?p=' + rec.get('aParam'),
              success: function (response) {
                  if (response.status = 200) {
                      this.setTooltip(response.responseText);
                  }
              }.bind(this)
          });
      }
  };
}

You can find the Fiddle here

Conclusion

You could use Ext.Ajax to load your menu items but with the Ext.ComponentLoader you can do it in an easier, simpler and cleaner way. This, by default, provides you some renderers that you can use to build your Components content.


Popa_Vadim square
Vadim Popa is a web apps engineer and a JavaScript coder. You can find him speaking at Cluj.JS meetups, blogging about Sencha and Angular, and experimenting on GitHub. He likes travelling and mountain biking through the Romanian woods.


What We Do

We’ll work closely with your team to instill Lean practices for ideation, strategy, design and delivery — practices that are adaptable to every part of your business.

See what Modus can do for you.

LET'S GET STARTED

We're Hiring!

Join our awesome team of dedicated engineers.

Loading...

APPLY NOW