Turn your ExtJS 4 singletons into heavy and useful workers

Turn your ExtJS 4 singletons into heavy and useful workers

This article shows how you can turn your ExtJS (4) singletons into useful and heavy workers. With update on an earlier FontAwesome article.

A singleton is a class that can have only one object instance. In ExtJS 4 a singleton object is instantiated once the application is loaded. I love to use singletons as helpers in my applications. Recently I wrote an article about how to use glyphs with the FontAwesome (link).

In this article I will show you how I use a singleton call Glyphs to make references to icon names a bit easier. But there are some more useful tips on turning your singletons into heavy and useful workers.

In the FontAwesome article a glyph was addressed like this:

{
   xtype: 'button',
   glyph: 'xf002@FontAwesome',
   text: 'Search',
   listeners: {
      click: {
          fn: me.SearchClicked,
          scope: me
      }
   }
}

But 'xf002@FontAwesome' is quite hard to remember if you are using many glyphed icons in your application. It would be so much nicer to just put here:

{
   xtype: 'button',
   glyph: Glyphs.setIcon('search'),
   text: 'Search',
   listeners: {
      click: {
          fn: me.SearchClicked,
          scope: me
      }
   }
}
``` javascript

You can use the following class in your application to make this happen very easy. I have called the class _Glyphs_ and I have added the methods: _setIcon_, _getIcon_ and _getGlyph_ that are all doing the same thing, getting the icon.

``` javascript
Ext.define('yourapp.singleton.Glyphs', {
    singleton: true,
    alternateClassName: ['Glyphs'],
    constructor: function(config) {
        this.initConfig(config);
    },
    config: {
        // Icons that have been addressed directly
        webfont: 'FontAwesome',
        add: 'xf04b',
        cancel: 'xf056',
        checked: 'xf046',
        clock: 'xf017',
        comment: 'xf0e5',
        connect: 'xf0c1',
        create: 'xf04b',
        dashboard : 'xf0e4',
        del: 'xf014',
        desktop: 'xf108',
        edit: 'xf040',
        filter: 'xf0b0',
        file: 'xf15c',
        folder: 'xf114',
        folder_open: 'xf115',
        frown: 'xf119',
        group: 'xf0c0',
        groups: 'xf0c0',
        home: 'xf015',
        info: 'xf129',
        link: 'xf0c1',
        linked: 'xf0c1',
        lock: 'xf023',
        locked: 'xf023',
        log: 'xf013',
        logout: 'xf011',
        message: 'xf10d',
        messages: 'xf10d',
        module: 'xf12e',
        object: 'xf02b',
        project: 'xf009',
        remove: 'xf014',
        save: 'xf0c7', // 'xf00c',
        settings: 'xf013',
        smile: 'xf118',
        sortasc : 'xf15d',
        sortdesc : 'xf15e',
        unchecked: 'xf096',
        unlink: 'xf127',
        unlinked: 'xf127',
        unlock: 'xf09c',
        unlocked: 'xf09c',
        user: 'xf007',
        users: 'xf0c0'
    },

    setIcon  : function(glyph) {
        return Glyphs.getGlyph(glyph);
    },

    getIcon  : function(glyph) {
        return Glyphs.getGlyph(glyph);
    },

    getGlyph : function(glyph) {
        var font = Glyphs.getWebfont();
        if (typeof Glyphs.config[glyph] === 'undefined') {
            return false;
        }
        return Glyphs.config[glyph] + '@' + font;
    }
});

Some remarks about the usage

Notice that for the "del" (as in delete) I have not used the word "delete", for if you are using Sencha Command, you can't use any identifiers that have reserved JavaScript names. Otherwise it will not pass the YUI compressor and ends up in syntax errors.

You can't use this when you use Sencha Architect, for it will not accept a function on the "glyph" config of your button, it will convert it to string.

You can easily modify the class for usage with other webfonts.

Put this file in the "singleton" folder of your app and add it to the requirements of your app.js file.

requires: [
  'yourapp.singleton.Glyphs',
  ... more singletons maybe...
    ],

Another singleton usage tip

Another handy way of using singletons is to create a toolbox of functions that are used more often in your applications. One example could be the rendering of certain fields that are used in different models. Instead of repeating the code over and over again, you can use a "Toolbox" or "Conversion" singleton.

Ext.define('yourapp.singleton.Toolbox', {
    singleton: true,
    alternateClassName: ['Toolbox', 'Tools'],
    constructor: function(config) {
        this.initConfig(config);
    },
    config: {
        cross: 'resources/images/icons/cross.png',
        tick: 'resources/images/icons/tick.png'
    },
    //--------------------------------------------------------------------------
    // Some handy convertors for models
    //--------------------------------------------------------------------------

    ConvertIcon: function(val, meta, record) {
        if (val.length > 0) {
            if (val.substring(0, 4) != '![](' + val + ')';
            } else {
                return val;
            }
        } else {
            return ' ';
        }
    },
    ConvertOK: function(val) {
        var cross = Toolbox.getCross();
        var tick = Toolbox.getTick();
        var img = (val == true) ? tick : cross;
        return '![](' + img + ')';
    },
    ConvertTick: function(val) {
        var tick = Toolbox.getTick();
        var img = (val == true) ? '![](' + tick + ')' : ' ';
        return img;
    }
    //-----------------------------------------------------------
    // Generic Form Functions
    //-----------------------------------------------------------

    // disable all form fields
    disableFormFields: function(form) {
        form.query('.field, .button').forEach(
                function(c) {
                    c.setDisabled(true);
                }
        );
    },
    // enable all form fields 
    enableFormFields: function(form) {
        form.query('.field, .button').forEach(
                function(c) {
                    c.setDisabled(false);
                }
        );
    }
});

In the class above you can see that the class has alternate names "Toolbox" and "Tools". To use references to items in this object, you have to use the object name "Toolbox" or "Tools" and not use this. When the renderer is calling the methode like ConvertOk, the reference this holds the panel or grid class or whatever you are calling from.

This is how you use the renderer (grid column):

{
   xtype: 'gridcolumn',
   renderer: function(value, metaData, record) {
       var icon = Toolbox.ConvertTick(value);
       return icon;
   },
   width: 50,
   align: 'center',
   dataIndex: 'set_default',
   text: 'Std'
}

or even shorter:

{
   xtype: 'gridcolumn',
   renderer: Toolbox.ConvertTick,
   width: 50,
   align: 'center',
   dataIndex: 'set_default',
   text: 'Std'
}

The methods enableFormFields and disableFormFields are handy if you want to enable or disable all fields in a form with one call. Use it like this:

let me = this;
let formPanel = me.down('#yourformpanel');
Toolbox.disableFormFields(formPanel);

or when your panel is already the class itself:

var me = this;
Toolbox.disableFormFields(me);