Pages

Showing posts with label Ext JS. Show all posts
Showing posts with label Ext JS. Show all posts

Friday, October 8, 2010

setting Extjs Menu maximum height

I was recently trying to set the maximum height of an Extjs.menu.Menu and wasted way too much time on it, including posting on the Sencha forums and waiting in vain for a reply. But I now have a solution, and here it is, for the greater good of humanity...

What I tried that failed was something like:


 menu = new Ext.menu.Menu({  
                 id: 'menu',  
                 style: '',  
                 items: items,  
                 renderTo: 'center_region',  
                 showSeparator: false,  
                 maxHeight: 100,  
                 autoScroll: true,  
                 enableScrolling: true  
   
               });  
   
               menu.showAt([x, y]);
I tried various settings of autoHeight, style, etc. as well and nothing seemed to work. Adding the height attribute (height: 100) actually made a difference, but it now set the height permanently to 100px rather that a maximum of 100px, which resulted in a number of unsightly gaps at the bottom of the menu when the number of items was small.

The solution that finally worked for me was the following:


               reportsMenu = new Ext.menu.Menu({  
                 id: 'reportsMenu',  
                 showSeparator: false,  
                 boxMaxHeight: 150,  
                 autoScroll: true,  
                 enableScrolling: true,  
                 items: selectedReports  
               });  
   
               reportsMenu.showAt([x, y]);  
               reportsMenu.syncSize();
How one is supposed to figure that out from the Ext documentation beats me (unless hours of trial and error is intended). FYI I was using Extjs 3.1.1, in case it is ever updated to be more intuitive and the meaning of properties changes in future.

Tuesday, October 5, 2010

Extjs Store not loading

I recently came across the problem of my Extjs Store not loading anything, with no apparent errors. My Ext.data.Store loads data from a remote server and uses a Ext.data.ArrayReader with a converter for one of the fields, like:

    var genericFeaturesStore = new Ext.data.Store({
    proxy: new Ext.data.HttpProxy({url: 'getRecords.do'}),

    reader: new Ext.data.ArrayReader({}, [

        { name: 'title' },
        { name: 'records', convert : convertRecords}
    ]),
    ...
    });

The converter looks like this:

    var convertRecords = function(v, record) {
        for (var i = 0; i < v.length; i++) {
            v[i] = new Record(
                    v[i].title,
                    v[i].description,
                    v[i].serviceType,
                    v[i].serviceURLs,
                    v[i].keywords);
        }
        return v;
    };


The problem I had was that the convertRecords() seemed to begin execution but not complete, although the application was not stuck but appeared as if convertRecords() had returned.


The solution, which should help for any generic Store loading (or not loading) problem:

    genericFeaturesStore.on({
        'load': {
            fn: function(store, records, options) {
                alert("load");
            },
            scope: this
        },
        'loadexception': {
            fn: function(obj, options, response, e) {
                alert("error: "+e);
            },
            scope: this
        }
    });


This allowed me to see that it was throwing an error because it couldn't find the serviceType for one of the many records.
              

Thursday, September 9, 2010

Setting the scope of callbacks with Extjs

I recently ran into a problem where I was attempting to access a record in a collection being iterated over from inside a GDownloadUrl (Google Maps API) callback whose request would be executed as part of that loop. It took me a while to figure out the reason the last record was always getting passed to the callback no matter which callback was executing - GDownloadUrl is asynchronous and by the time any of the callbacks are executed the iteration was usually over!

Extjs provides an easy alternative to GDownloadUrl that allows access to the iteraiton record (or any other object) used when executing the callback - Ext.Ajax. All that needs to be done to retain the object required in the callback is to call createDelegate on the callback and then access the object in the callback using "this". An example is provided below:

for (var i = 0; i < activeLayersStore.getCount(); i++) {

    var record = activeLayersPanel.getStore().getAt(i);

    Ext.Ajax.request({
        url: url,
        timeout        : 180000,
        success: function(response, options) {
        alert("The record for this iteration is: "+ this.get('TypeName'));
        }.createDelegate(record),
        failure: function(response, options) {
            alert("Error requesting data" + response.statusText);
        }
    });

}

The documentation for Extjs Function.createDelegate can be found here: http://dev.sencha.com/deploy/dev/docs/?class=Function&member=createDelegate

Additionally,  if multiple objects are required for use in the callback, the createDelegate may be used as follows:


yourFunction.createDelegate({ o1: obj1, o2: obj2 });

or alternatively, if the signature of your handler is flexible you can pass parameters as follows:
yourFunction.createDelegate(scope, [scope2], 2); 

Friday, September 3, 2010

Image Zoom in Javascript

I recently spent some time investigating how to achieve image zoom using Javascript (as Extjs doesn't support it as of v3). There may be simpler jquery or other ways to achieve this but I wanted some simple Javascript. Suppose we have a couple of synced Extjs images and panels defined as follows:

        /**
         * The first image (BoxComponent)
         */
        var imgBox1 = new Ext.ux.Image({
            id: 'img_box1',   
            src:'http://earthobservatory.nasa.gov/Features/BlueMarble/Images/land_shallow_topo_2048.jpg'
        });

       
        /**
         * Panel for the first image
         */
        var imgPanel1 = new Ext.Panel({
            id: 'img_panel1',
            title: "Migrated",
            height: 280,
            autoScroll: true,
            items:[imgBox1],
            listeners: {
                render: function(p){
                    //sync scrolling between image panel 1 and 2
                    p.body.on('scroll', function(e){
                        var panel2 = Ext.getCmp('img_panel2').body.dom;
                        panel2.scrollLeft = e.target.scrollLeft; 
                        panel2.scrollTop = e.target.scrollTop;
                    }, p);
                  }
                }
        });
       
        /**
         * The second image (BoxComponent)
         */
        var imgBox2 = new Ext.ux.Image({
            id: 'img_box2',
            src:'http://earthobservatory.nasa.gov/Features/BlueMarble/Images/land_shallow_topo_2048.jpg'
        });
       
        /**
         * Panel for the second image
         */
        var imgPanel2 = new Ext.Panel({
            id: 'img_panel2',
            title: "Stacked",
            height: 280,
            autoScroll: true,
            items:[imgBox2],
            listeners: {
                render: function(p){
                    //sync scrolling between image panel 1 and 2
                    p.body.on('scroll', function(e){
                        var panel1 = Ext.getCmp('img_panel1').body.dom;
                        panel1.scrollLeft = e.target.scrollLeft; 
                        panel1.scrollTop = e.target.scrollTop;
                    }, p);
                  }
                }
        });

Zoom can be achieved as follows:

    /**
     * Add zoom functionality to image panels
     */
    'addZoom': function() {
   
        var zooming=function(e){
            e=window.event ||e;
            var o=this,data=e.wheelDelta || -e.detail*40,zoom,size;
                
            //TODO: Zooming in IE doesn't zoom to the correct point?
            if(!+'\v1'){//IE
                var oldWidth=o.offsetWidth;
                var oldHeight=o.offsetHeight;       
   
                zoom = parseInt(o.style.zoom) || 100;
                zoom += data / 12;
                if(zoom > zooming.min)
                    o.style.zoom = zoom + '%';
                e.returnValue=false;
   
                var newWidth=o.offsetWidth*zoom/100;
                var newHeight=o.offsetHeight*zoom/100;
                var scrollLeft = (o.parentNode.scrollLeft/oldWidth)*newWidth;
                var scrollTop = (o.parentNode.scrollTop/oldHeight)*newHeight;
               
                o.parentNode.scrollLeft = scrollLeft;
                o.parentNode.scrollTop = scrollTop;
            }else {
                size=o.getAttribute("_zoomsize").split(",");
                zoom=parseInt(o.getAttribute("_zoom")) ||100;
                zoom+=data/12;
               
                var oldWidth=o.offsetWidth;
                var oldHeight=o.offsetHeight;
                var newWidth=size[0]*zoom/100;
                var newHeight=size[1]*zoom/100;
                var scrollLeft = (o.parentNode.scrollLeft/oldWidth)*newWidth;
                var scrollTop = (o.parentNode.scrollTop/oldHeight)*newHeight;  
   
                if(zoom>zooming.min){
                    o.setAttribute("_zoom",zoom);
                    o.style.width=newWidth+"px";
                    o.style.height=newHeight+"px";
                    //TODO: Zoom is very jerky when setting scrollbars this way, when
                    // either scrollbar is not at position 0. Need to fix it.
                    o.parentNode.scrollLeft = scrollLeft;
                    o.parentNode.scrollTop = scrollTop;
                }
                e.preventDefault();
                e.stopPropagation();//for firefox3.6
            }
        };
   
        zooming.add=function(obj,min){// obj = image box, min defines the minimum image zoom size ,defaults to 50
            zooming.min=min || 50;
            obj.onmousewheel=zooming;
            if(/Firefox/.test(navigator.userAgent))//if Firefox
                obj.addEventListener("DOMMouseScroll",zooming,false);
            if(-[1,]){//if not IE
                    obj.setAttribute("_zoomsize",obj.naturalWidth+","+obj.naturalHeight);
            }
        };
       
        zooming.add(document.getElementById("img_box1"));  
        zooming.add(document.getElementById("img_box2"));      
    }

The above zoom function is as far as I got with it before having to put it aside. As you may notice from the comments, it doesn't work that nicely in IE and setting of the scrollbars is quite jerky when setting both scrollLeft and scrollTop to somthing other than position 0. This is something I will need to investigate further and update here in future.

Sunday, August 8, 2010

Learning Ext JS

Ext JS is a javascript library for building web applications, originally an extension of YUI.

The API documentation can be found at http://dev.sencha.com/deploy/dev/docs/

An excellent source for learning Ext JS are the YouTube tutorials by Jay Garcia from TDG-innovations (http://tdg-i.com/ has the screencasts with a better quality than those on YouTube). Some topics they have covered include:

  • Ext.extend - subclassing with Ext JS
  • Ext.apply - a utility that allows one to easily copy properties over from one object to anothe
  • Ext.each - an alternative to a for loop, used to iteratie over an array (this one gets a little hairy in the screencast, I'm not sure how useful it really is)
  • Containers (Ext.Panel, Ext.Window - add, remove, doLayout, Ext.Element, Ext.Fx - slideOut, fadeOut)
  •  
 
Powered by Blogger