Ext JS Image Field

Yesterday I spent way too much time on another simple thing in EXT that I would have expected to work out of the box. What I needed was to upload a company logo to a profile and, of course, display that logo in the form. While it's very simple to display an image in a panel or box, it's a totally different thing to display the in image in the form and update it together with other form fields. What I needed is something like this:
and after form submit it should automatically load the new image:
For image upload I used the image upload plugin from EXT examples. To display the image I needed to extend the field component like this:
Ext.form.ImageField = Ext.extend(Ext.form.Field, {
    autoCreate: {tag: 'img'}
    ,setValue: function(new_value){
        if (new_value == undefined || new_value == null) {
            this.el.dom.src = '/images/no_image.png';
        } else {
            this.el.dom.src = '/images/thumbnail/' + new_value;
        }
    }
    ,initValue : function(){
          this.setValue(this.value);
    }

    ,initComponent: function() {
        Ext.apply(this, {

        });

        Ext.form.ImageField.superclass.initComponent.apply(this);
    }
});

Ext.reg('image_field', Ext.form.ImageField);

This is a bit simplified version as I removed the rails specific code, but anyway the main points are here:
line 2 creates image tag (rather than the default text field tag)
line 5 defaults the image src property to a placeholder (in case there's no image uploaded)
line 7 - in case there is a valid image it will change the src path to that image - in my case it's routed to Images controller and action thumbnail which returns a downscaled version of the image.
Other than this don't forget to set the FormPanel's fileUpload: true and refresh the form on submit success. I usually send the updated object JSON in the response to update action.:
  def update
    contact = Contact.find(params[:id])
    on_bind(contact)
    success = contact.save
    contact = Contact.find(contact.id) if success
    
    logger.info("saved")
    
    respond_to do |format|
      format.ext_json do
        json = contact.to_ext_json(:success => success,
                                   :methods => [:image_id],
                                   :includes => [:address],
                                   :messages => {:notice => l(:contact_updated), :warning => l(:contact_update_error)})
        render :json => json #:json => {:success => success}
        headers["Content-Type" ] = "text/html"
      end
    end
  end

!!!Notice line 16 - you have to manually set the content type to "text/html" because rails will default to "text/javascript" which will not work with file uploads!!! It works with fileUpload: false but it doesn't with fileUpload: true. I don't really know if Rails or EXT is right here but did take me some time to figure this out.
this will produce the following JSON (I removed the unnecessary fields):
{"success": true,
    "messages": {"notice": "Contact was successfully updated.", "warning": "contact_update_error"},
    "data": {"contact[image_id]": 15, "contact[active]": false, "contact[client_account_id]": 2, "contact[client_account_no]": "100",
        "contact[created_at]": "2009-07-07T10:31:54+08:00", "contact[credit_term_id]": 1}}
Now in the forms success method I can use the result.data to update the form:
success: function(form, action) {
                      form.setValues(action.result.data);
                  },

Multiline Tree nodes in ExtJS

While I really like Ext and the component model behind it, some simple things seems to be missing - an example would be multiline nodes in TreePanel. After some searching I managed to find a  MultilineTreeNodeUI plugin.
Here's how to use it:
new Ext.tree.TreePanel({
 //renderTo:'treecontainer',
 id: 'upcoming_events',

 loader: new Ext.tree.TreeLoader({
  dataUrl:'/datasource/upcoming_events_json',
  baseParams: {},
  baseAttrs: {uiProvider: Ext.ux.tree.MultilineTreeNodeUI}
 }),
 root: new Ext.tree.AsyncTreeNode({
  expanded: true
 }),
 rootVisible: false,
 collapsed: false
})

Just include the MultilineTreeNodeUI.js in the page and create a usual TreePanel. The only difference is to include baseAttrs: {uiProvider: Ext.ux.tree.MultilineTreeNodeUI} in your loader. Multilne tree requires the data in the following format:
{
 text: '09 April 2009',
 iconCls: 'calendar',
 details: ['Program for the day...'],
 uiProvider: Ext.ux.tree.MultilineTreeNodeUI,
 children:[
  {
   text: '9:30',
   iconCls: 'time',
   details: ['Win $1M', 'Sure win...'],
   uiProvider: Ext.ux.tree.MultilineTreeNodeUI,
   leaf: true
  },
  {
   text: '11:30',
   iconCls: 'time',
   details: ['Buy private jet', 'Or something'],
   uiProvider: Ext.ux.tree.MultilineTreeNodeUI,
   leaf: true
  }
 ]
}
Where the additional lines are provided by details attribute. It's an array - one item per line - maybe not an ideal solution but still workable - worst case you just split the longer line by number of characters. The uiProvider will generate the multiple lines. Your controller doesn't have to do anything about it as it will be added automatically by the baseAttrs: {uiProvider: Ext.ux.tree.MultilineTreeNodeUI} we added in the loader.
And here's the outcome: