I have written a small helper function to make delayed sequential function execution easier.

We have the following case: we need to execute an array of functions. The second one has to execute after the first one finishes, the third after the second and so one. The scenario gets a bit more complicated when wee need some delay between functions. So we have to execute function 1, then after it finishes, wait for 200 ms, and execute function 2, then after another 500 ms execute function 3 and so on.

So the code is the following:

function runSequence(arr, scope, delay){
	arr.push(function(){});
	delay = delay || 0;

	var i = 0,
             len = arr.length;

	for(;i < len-1; i++){
		(function(index, thisObject){
			arr[index] = function(){
				var isFn = !!thisObject.call,
					fn = isFn? thisObject : thisObject.fn,
					fnScope = isFn? scope: thisObject.scope,
					fnDelay = isFn? delay : thisObject.delay,
					fnToExecute = function(){ fn.call(this); arr[index+1](); }

                                fnScope = fnScope || this;
				fnDelay? setTimeout(function(){ fnToExecute.call(fnScope) }, fnDelay) : fnToExecute.call(fnScope);
			}
		})(i, arr[i]);
	}

	arr[0]();
}

We can do the following:

runSequence([
	{ fn: function(){ console.log('executed immediately') }, delay: 0 },
	{ 
          fn: function(){ console.log('this was after 1500 ms, with scope: ', this.name) }, 
          delay: 1500, 
          scope: {name: 'sequence running'} 
        },
	{ fn: function(){ console.log('this was after 2s ') }, delay: 2000 }
], this)
/*
 * The first and the last functions above are executed in the scope of the code executing the runSequence function
 * The second function is instead called with the scope being the passed object, {name: 'sequence running'} 
 */

or the following:

runSequence([
	function(){ console.log('first after 200ms') },
	function(){ console.log('yet another 200 ms') },
	function(){ console.log('the last fn at 200ms') }
], this, 200)
/*
 * A shorter form of the runSequence function call, with functions running at equal timeouts, in the passed 'this' scope
 */

This function can be useful when processing large amounts of data that would otherwise block the browser, or in cases when one would need to trigger ajax calls with a certain delay in between. I’m sure that there are other cases when this could prove useful.
In the case of processing large amounts of data, one could use this to fill up a (non-paginated) grid with data, in chunks of, say, 200 records.

Do you find this pattern useful?

Lately I had to do more work with ExtJS x-templates, and really found them very flexible. One feature I find useful is the support for formatting functions. So you can have a template which outputs different things for plural and singular forms:

new Ext.XTemplate('{0:plural("record","records")} deleted').apply([4]) 
// -> 4 records deleted

This is nice. Yet the formatting functions are not limited to just a few. Templates support all formatting functions in Ext.util.Format. What’s even better is that you can add your own formatting functions and have them in the templates.

One use case for this usage of templates is displaying user feedback in a label or tooltip when deleting records in a grid, or selecting records. In order to be accurate and give a nice user experience, it would be nice to output: ‘No records selected’, and not ’0 records selected’; ‘One record selected’, and not ’1 record selected’. So, a nice solution would be the following:

(function() {

    Ext.apply(Ext.util.Format,{

        /**
         * Label plural formatter : lplural - to be used with templates
         *
         * @param value {Number} number
         * @param singular {String} singular form
         * @param plural {String} plural form
         * @param zero {String} zero form
         * @param addPluralValue {Boolean} whether to add 
         *            the value in the plural form
         */
        lplural: function(value, singular, plural, zero, addPluralValue){
            //make the text for the zero quantity be optional
            if (zero && !value){
                return zero;
            }

            //also the addPluralValue flag is optional - if it is true, 
           //also return the value: eg - 5 records 
            plural = addPluralValue? (value + ' ' + plural) : plural;

            return value != 1 ? plural : singular;
        }
    })

    Ext.onReady(function(){

        var t = new Ext.XTemplate('{0:lplural("one record","records","no records", true)}');

        //add plural value
        console.log(t.apply([5])) // -> 5 records

        console.log(t.apply([0])) // -> no records
        console.log(t.apply([1])) // -> one record

        var t = new Ext.XTemplate('{0:lplural("one record","records", null , false)}');

        //don't output the '5'
        console.log(t.apply([5])) // -> records
       //haven't provided a text for zero, so defaults to the plural form
        console.log(t.apply([0])) // -> records
    })
})();

I really think templates are very powerful, so use them! Any other clever usages? (besides all the ext4 being built on top of them :) )

Recently I got borred with the for loops and I added the “times” function on the prototype of Number. As a result, I can easily iterate over arrays or I can simply call a function how many times I want like this:

     (5).times(function(index /* zero based */){
           console.log(index);
     })
     //or using array length
     arr.length.times(function(){ ... });

     //optionally specify scope for the callback function:
    n.times(function(){ .... }, scope);

Together with this, I’m using another goodie. Whenever I have a function that expects a parameter which can either be a simple value or an array, convert that value to array in one line, like:

    var arr = [].concat(valueOrArray);

See below the source code.

/**
 * extend the Number prototype
 * @param func
 * @param scope [optional]
 */
Number.prototype.times = function(func, scope){
    var v = this.valueOf();
    for (var i=0; i < v; i++){
        func.call(scope||window,i);
    }
};

function test(valueOrArray){
    var arr = [].concat(valueOrArray)
    arr.length.times(function(i){
        console.log(arr[i]);
    })
}

test([1,3,4])
//output: 1   3   4

test(123)
//output: 123

As for the performance, I have tested the times function against the for loop, and it seems to give about same results at a first glance. Any feedback on this?

P.S. Iterating over arrays gets even easier by adding an 'each' function to the Array prototype. Adding to the prototype of standard JavaScript objects is a debatable practice, and should not be abused.

Automation testing of UI is essential in any big project, but it is difficult to achieve this for user interfaces built with ExtJS. Selenium records user actions, by clicks on elements, and memorizes the ids of the selected elements. Yet since ExtJS auto-generates ids which are not guaranteed to stay the same, you cannot rely on this. The same problem is when you simply add a small change (add a label, etc), so the generation (if you relied on it to be the same) will totally change and the automated tests will be ruined.

Instead, Selenium tests for ExtJS should rely on CSS selectors. For every button, grid, label, tab or any significant UI element, I simply chose to use the cls attribute and specify a CSS class.

 
new Ext.Button({
    text: 'Ok',
    cls: 'seleniumOkButton', //can have more classes, separated by space
    scope: this,
    handler: function(){ ... }
})

This is how a basic button that is used in automation testing looks like. And I use the following XPath selector in Selenium:

//table[contains(@class,'seleniumOkButton')]

Happy automated testing!

Well, if you are programming in JavaScript for a while, you are familiar with the arguments ‘array’ which gives you access to function arguments by index, without the need of argument names. And if you are programming JavaScript for a bit longer while, you will know that arguments is not even a normal array. It does not have any methods of an array. You can just use it to access items by index and also access it’s length property. That’s all. What if you want to make a copy of the array? What if you want to push or pop items? Well… you have some work to do… OR …

Or do something smart. Like call the slice method from Array.prototype on the arguments, something like:

//this makes a copy of the arguments and returns a true array
Array.prototype.slice.call(arguments, 0) 

//pushes the value '5' in the arguments
Array.prototype.push(arguments, 5) 
//this is not valid: arguments.push(5)

Well, maybe most of you expert JavaScript programmers have thought about this, and this is not a news. But, let’s share from our experience to the more novice/newcomers to JavaScript and show them the beauty of this language!

JavaScript is a great language! It’s expressive! It’s powerful! That’s why we love JavaScript.

You should make use of the scope config option in components

.

  • in Ajax calls
    var MyPanel = Ext.extend(Ext.Panel, {
        doSave: function(){
    	Ext.Ajax.request({
    	    url: 'your_url',
    	    params: ....
    	    success: function(response){
    		response = Ext.decode(response.responseText);
    		this.onSuccess(response)
    	    },
    	    scope: this //the scope in which the success callback is called
    	})
        },
        onSuccess: function(){ .... }
    }

    In this example, specifying the scope is very useful. By default, the success callback on Ajax calls is executed with the scope being the browser ‘window’ object, which is not very useful. In the code above, we execute the success callback in the ‘this’ scope, ‘this’ being the instance of MyPanel which executes the doSave method. This is why we can safely call this.onSuccess(response), as ‘this’ is a MyPanel object, which has the onSuccess method.
    I find the scope config property very useful, so even though specifying the scope of a function is very natural in JavaScript, the fact that ExtJS made it so natural and easy deserves being noted. Well done ExtJS!

  • in Buttons
    {
        xtype: 'button',
        text: 'Save',
        handler: function(){
    	//do something on pressing the button
        },
        scope: myScope //scope of the handler
    }
  • with Stores
    new Ext.data.Store({
        //...other config options
        autoLoad: {
    	callback: function(){ ... },
    	scope: aScope //for the callback function after loading the store
        }
    })
  • in listeners
    new Ext.Panel({
        listeners: {
    	scope: window, //the scope of all listeners in this config
    	show: function(){ ... },
    	afterrender: function(){ ...this is 'window' }
        }
    })
  • in actions