Subtitel

A blog by Juri Urbainczyk | Juri on Google+ | Juri on Twitter | Juri on Xing

Monday, August 27, 2012

Textfield with an image: how to write a Sencha Touch 2 component


Let's assume we'd want to write a component, which displays a string together with an image. This would come in handy, if we need to display the name of a customer (e.g. 'Pfefferminzia') and it's logo. The following picture shows the component in action - in the second row of the dialog.


We can achieve that by combining an normal textfield ('Ext.field.Text') with a label ('Ext.Label') which contains the corresponding image. Thus, we need a conatiner, which surrounds the textfield and the image and keeps them together. Lucky as we are, Sencha Touch already offers such a component, called 'Ext.Container'. Since we want name and image to appear on the same line one after the other, we choose a 'hbox' layout for our container. At this point, out new component looks like this:
Ext.define("myapp.view.CustomerDisplayField", {
    extend: 'Ext.Container',

    xtype: 'customerdisplayfield',
    
    config: {   
        layout: 'hbox',
        items: [
            {
                xtype: 'textfield',
                label: 'Customer',
                labelWidth: '37.4%',
                readOnly: true,                               
                flex: 4       
            },
            {
                xtype: 'label',
                html: '<span style="float:right; margin-right:10px;"><img height="32px"  src="resources/images/customer.png"/></span>',
                padding: '6 0 0 0',
                flex: 1       
            }       
        ]       
    }
});

This is all very well, but something is missing: we need the image to change accordingly, whenever the customer changes. In order to achieve this, we add a 'change' listener to the text field. Each time the name of the customer is change (e.g. via a call to 'setvalue()') the image should change as well. But, in the 'change' handler we need to call a function on the label sub-component. How do we get a hold on that? We could, for instance, do something like 'this.up().getComponent(1)' but that would make our component dependent an the structure and on the *order* of the sub-compoenents - which is not good.

Therefore, we add an 'initialize' handler to our component and create all the sub-components in this handler.
Thus, we always have a variable which points directly to our 'image label', which make our life quite easy.
We also add a 'setUrl()' method to our image-label and a 'setValue()' method to our component as a whole. Then we are ready and our source code looks like this:
Ext.define("myapp.view.CustomerDisplayField", {
    extend: 'Ext.Container',

    xtype: 'customerdisplayfield',
   
    textfield : null,
    
    config: {   
        layout: 'hbox',
       
        listeners: {
            initialize : function() {
               
                //this label displays the icon
                var mylabel = Ext.create( 'Ext.Label', {
                    padding: '6 0 0 0',
                    flex: 1,
                   
                    setUrl : function(url) {
                      this.setHtml('<span style="float:right; margin-right:10px;"><img height="32px"  src="'+url+'"/></span>');
                    }
                });
               
                //set a default image
                mylabel.setUrl("resources/images/warning.png");
               
                //this textfield displays the customer's name
                var mytext = Ext.create('Ext.field.Text',{
                    label: 'Customer',
                    labelWidth: '37.4%',
                    readOnly: true,                               
                    flex: 4,
                    listeners: {   

                        change: function(field,newvalue,oldvalue) {
                            //get the correct url for my new customer
                            var url = customernameToUrl(newvalue);                       
                            mylabel.setUrl(url);                       
                        }
                    }
                });                       
               
                this.add(mytext);
                this.add(mylabel);
               
                this.textfield = mytext;
            }
        }       
    },
   
    setValue : function(newvalue) {
        this.textfield.setValue(newvalue);
    }
});

No comments:

Post a Comment