Showing posts with label ExtJS. Show all posts
Showing posts with label ExtJS. Show all posts

Tuesday, September 3, 2013

ExtJS overwrite listener

Sometimes you need to overwrite an event listener in ExtJS. Usually listeners are registered like this:
    var myStore = Ext.create("Ext.store.SimpleStore", {
        // ...
    });

    myStore.on('load', this.myFunction, this);

If this is the case, then to remove our previously registered listener, all we have to do is call un (which is an alias for removeListener):
    myStore.un('load', this.myFunction, this);

But, what happens when you don't know what function is registered? Sometimes you will not have a reference to the original function that was registered. This situation may arise if there is code that exists in a different flow or may even come as a package! If that is true, the you may not be able to get a reference to the javascript function or edit the existing code. In this case, we will have to look at all of the functions that are registered for this event. We can then remove the listeners just for a certain event by calling clearListeners.
    // code that you can't delete or change
    Ext.Ajax.on('requestexception', function(cnn, response, options) {
        // the current handler code
    });

    // we can patch it by removing the listener and then adding our own
    if (Ext.Ajax.events.requestexception) {
        Ext.Ajax.events.requestexception.clearListeners();
    }

    Ext.Ajax.on('requestexception', function(con, response, options) {
        // our own very important listener
    });

And that's it! The only thing to remember here is that we may not want to remove all the listeners as we did here, because there could be more than one registered. The ideal solution would be to have the handler method be part of some singleton object, that way we can unregister just that function.

Thursday, August 15, 2013

ExtJS Unable to override class method

I recently ran into a problem where I could not override a mixin class function.
Ext.define("ContainerMixin", {
    override: "Override.ContainerMixin",
    
    initComponent: function() {
        this.callParent(arguments);
    },
    
    /**
     * @inheritdoc
     * @override
     */
    onWidgetClick: function() {
        alert('override');
    }
});
The strange thing was that initComponent was being overridden correctly. If I set a break point in initComponent, it will always hit the break point, but it was never hitting onWidgetClick method! The problem is that mixins are applied at class-definition time. The solution is to instead override the class that will be using it to use this new mixin.

Tuesday, July 23, 2013

ExtJS: Object doesn't support this action

I recently ran into an issue where my ExtJS application was throwing an error in IE8:

Object doesn't support this action

The issue was coming from an inconspicuous block:
        var me = this;
        item = me.getUserContactView();
        item.hide();

The issue here is that IE8 has issues with certain variable names in global scope -- the one here being item.

To fix this issue, all I had to do was put the variable into local scope:

        var me = this,
        item = me.getUserContactView();
        item.hide();

Thursday, June 6, 2013

How to check when setValue is called on a component

I ran into a problem where one of my components, namely a radio button, was being reset somewhere. The problem is to identify when a component's value is being set. To troubleshoot this, all I had to do was listen for a certain event change on the radio and break on that. The change event is fired when the setValue function of the component is called. In my example, the panel containing the radio button had an itemId set, so all I had to do was create a selector in my controller to find it.

In your controller:

init: function() {
    var me = this;

    me.control({
        '#configConfigConfigView radio': {
            change: me.stateChange,
        }
    });
},

stateChange: function(radio, newValue, oldValue) {
    console.log(radio + newValue + oldValue);
},

Then make a breakpoint on that function in Chrome developer tools or Firebug and examine the stack trace.

Monday, April 22, 2013

ExtJS passing parameters to a store proxy

I came across a need to pass parameters to a GET rest request. In my case, the server code was filtering which columns to return based on a parameter received. I started looking for a way to pass along such a parameter to my store proxy. Many solutions suggested to call the load method manually, which would allow you to pass in some parameters with it.

However, this was not possible for my application architecture because the store had to be on autoLoad: true. It is possible to pass an extraParams config to a proxy.



Ext.define('myStore', {
    extend: 'Ext.data.Store',
    model: 'myModel',
    storeId: 'mystore',
    proxy: {
        type: 'rest',
        url: buildServiceUrl('users'),
        simpleSortMode: true,
        extraParams: {
            inclProps: '{userId, shortDesc}'
        },
        reader: {
            type: 'json',
            root: 'data'
        },
        writer: {
            nameProperty: 'mapping'
        }
    },
    
    autoLoad: true
});

Thursday, April 18, 2013

Getting a form from an Ext.form.Panel

Using an Ext.form.Panel is an excellent choice for form-type screens as it can simplify some aspects of the interface. One such simplification is the ability to call isValid(), which allows you to validate all the fields in the form at once. This can, for example, check that fields with a vtype of email are in a format of name@server.com. The problem I ran into however, is that an Ext.form.Panel does not have the method isValid(). The object you want is the underlying Ext.form.BasicForm. To get the child form, you can simply call getForm().


var panel = Ext.create('Ext.form.Panel', {
    items: [...]
});

var validity = panel.getForm().isValid();

Wednesday, April 10, 2013

ExtJS custom textfield validation for natural numbers.

Suppose you have a text field on your form like this:

this.portField= Ext.create('Ext.form.field.Text', {
    fieldLabel: 'Port',
    labelAllign: 'top'
});

And that your goal is to make sure the user enters only a natural number. Here I am referring to a natural number as a non-negative integer.

Your first choice would be to look at the vtype config available for the text field. However, you will notice that there is no available choice to mark strictly an integer. That of course, means we get to write our own! Luckily this is not a difficult task:


Ext.apply(Ext.form.field.VTypes, {
    natural: function(val, field) {
        var reg= /^\d+$/i;
        return reg.test(val);
    },
    naturalText: 'Must be a natural number',
    naturalMask: /^[0-9]/i
});


What this does is apply a regular expression to the contents of the field to check for its validity. This statement will actually disallow any non-numeric characters from being entered into the field! The three configs must all start with the same string which will become your new vtype, here it is natural. Now we can simply add the new vtype to the text field:


this.portField= Ext.create('Ext.form.field.Text', {
    fieldLabel: 'Port',
    labelAllign: 'top',
    vtype: 'natural'
});