Tips and tricks for LAMP (Linux Apache MySQL PHP) developers.

When I cant find a suitable solution to a problem and have to work it out for myself I'll post the result here so hopefully others will find it useful. (All code is offered in good faith. It may not be the best solution, just a solution).
Showing posts with label javascript. Show all posts
Showing posts with label javascript. Show all posts

Sunday, 29 June 2014

Jasmine and Jasq

Recently I've started using Jasmine - a BDD framework - to test some pretty complex JavaScript I've been writing for work. We're using RequireJS for our JavaScript and we found a great plugin for Jasmine to make it play nicely with AMD modules called Jasq.

All works beautifully except for one thing: the Jasq docs say to wrap your specifications in a require block but that didn't seem to work for me. Once I changed them to define blocks (see below) everything started working. I don't know why this is and it doesn't seem anyone else had the same issue so perhaps I've done something wrong but I just thought I'd put this out there in case anyone else runs into the same issue.

define(['jasq'], function ()
{
  describe('My Tests', 'thing/to/test', function()
  {
    it('should do something', function(thingToTest)
    {
        //...
    });
  });
});

Saturday, 19 April 2008

Extending classes in JavaScript

Note: This post was originally written in 2008. There's a 2015 update at the bottom.

There are many different ways to achieve Object Orientation in JavaScript and the Internet is littered with examples.

jQuery Uses an extend method within the super-class that allows you to add functionality onto an instance of that class, creating a kind of sub-class (although it is an object):

function SuperClass() {}
SuperClass.prototype = {
// ...
extend: function() {
 var int_count = 0;
 var arr_prop;
 while ( (arr_prop = arguments[int_count++]) != null ) {
  for ( var i in arr_prop ) {
   this[i] = arr_prop[i];
  }
 }
 // Return the modified object
 return this;
}
}

// ...

var obj_subclass = new SuperClass();
obj_subclass.extend({
foo: 'bar',
// ...
});

This is quick and dirty but not proper OO and if you want several instances of the 'sub-class' you need to call extend on each one.

You probably already know that to add member variables/methods to a class you assign them to its prototype property. This can be one value at a time:

function SuperClass() {}
SuperClass.prototype.foo = 'bar';

Or a simple object can be assigned:

function SuperClass() {}
SuperClass.prototype = {
 foo: 'bar',
 x: 'y',
 super_func: function() {
 //...
 }
}

A good way to simulate inheritance is to assign an instance of the super-class to the sub-class' prototype example here:

var obj_super = new SuperClass();
function SubClass() {}
SubClass.prototype = obj_super;

This means that all member variables/functions of SuperClass are now contained within SubClass' prototype.

In order to now extend SuperClass' functionality in SubClass we revert back to adding one new thing at a time with SubClass.prototype.sub_func = function() { //... }. This is fine but if you plan on adding a lot more stuff it's not ideal.

The solution I have come up with (I say "I", maybe other people do this but I can't find any mention of it on the net) is to combine the two methods above:

var obj_super = new SuperClass();
function SubClass() {}
SubClass.prototype = obj_super.extend({
 foo: 'bar',
 sub_func: function() { //... },
 // ...
});

This way we are still creating a proper sub-class and inheriting the super-classes functionality whilst conveniently adding our own.

Note: You can call super-class methods directly from within the sub-class with SuperClass.prototype.super_func.call(this, arg1, arg2, argN);

Update (03/01/2015)

The above used to be how I extended 'classes' in JavaScript but these days I use a different method. Again, there are many ways to achieve JS extension, what follows is just my preference.

This method has two main requirements:

  1. You call the constructor of the parent inside the constructor of the child using the child's context
  2. You copy the parents prototype onto the child's prototype via the Object.create method
For example:

function SuperClass()
{
    var a = 1;
    this.getA = function()
    {
        return a;
    };
}

SuperClass.prototype.functionA = function()
{
    alert('SuperClass functionA');
};

function SubClass()
{
    SuperClass.call(this);
    var b = 2;
    this.getB = function()
    {
         return b;
    };
}

SubClass.prototype = Object.create(SuperClass.prototype);
SubClass.prototype.functionB = function()
{
    var aPlusB = this.getA() + this.getB();
    alert('SubClass functionB. a+b == '+aplusB);
};

var eg = new SubClass();
eg.functionA(); // alerts "SuperClass functionA"
eg.functionB(); // alerts "SubClass functionB. a+b == 3"

Now SubClass extends SuperClass. So why not use SubClass.prototype = new SuperClass(); you ask? Well there's a subtle difference between new and Object.create() in that the latter doesn't actually call SuperClass's constructor, it just copies the prototype so the SuperClass constructor will only get called at the time of creation of the SubClass (as we are calling it explicitly with SuperClass.call(this)).

Note that, as with the old method from this post, the way to call SuperClass function directly is with SuperClass.prototype.functionName.call(this, arg1, argN)

Wednesday, 9 April 2008

Creating a basic select box in ExtJS


I'm currently working on a project that involves generating an entirely ExtJS-based interface from PHP code.

I needed to be able to produce in ExtJS the equivelent of a standard HTML <select> box. This can be achieved with a ComboBox, however, it seems that ComboBoxes are heavily geared towards doing lots of clever things like loading in options over AJAX, allowing the user to type in their own options, auto-completing typed in options, etc. That's all great but if all you want is a standard drop-down with a predefined set of options it takes a bit of work.

I incorrectly assumed that something like the following would work:

obj_combo = new Ext.form.ComboBox({
 name: 'countries',
 items: [
  {value: '1', text: 'UK'},
  {value: '2', text: 'US'},
// ...
]
});

Unfortunaltey, it's not that simple.

Here's an example of the actual code required:
obj_combo = new Ext.form.ComboBox({
 name: 'countries',
// Stop users being able to type in the combobox
 editable: false,
// Even though the user cant type any more
// once they select one option it'll remove any
// others that don't start with the same letters
// unless we turn off filtering

 disableKeyFilter: true,
// Only allow users to pick an option that exists
// in the list of options (not one of their own)

 forceSelection: true,
// This isn't entirely necessary but the combox
// will start off blank otherwise

 emptyText: '--select one--',
// This one's vital: when the user clicks on the
// drop-down show ALL options

 triggerAction: 'all',
// By default it retrieves remote data,
// we're using local data

 mode: 'local',
// ComboBox will only accept data from a Store
// so we have to create a basic one

 store: new Ext.data.SimpleStore({
  id: 0,
  fields: ['value', 'text'],
  data : [['1', 'UK'], ['2', 'US']]
 }),
// Specify which fields in the store hold
// the value and the display text

 valueField: 'value',
 displayField: 'text',
// Important: by default the POST/GET data
// for this item will contain the display text
// not the value. This option creates a hidden field
// with the same name as the dropdown containing the
// selected value so it is that which gets returned

 hiddenName: 'countries'
});

With all those set (plus any of your own) you should have the equivalent of an HTML select box in ExtJS.

For good examples of different ComboBoxes (but unfortunately little explanation of them) check this link:
http://extjs.com/deploy/ext/examples/form/combos.html