Showing posts with label ext js. Show all posts
Showing posts with label ext js. Show all posts

8/17/2012

Drag-Drop from grid to any div in ExtJS 4

In most of the documents of ExtJS, drag dropping between Ext components are explained. The following combinations have their own examples in the web-site:
grid-grid
grid-tree
grid-form
tree-tree
However compared with jQuery UI, there is not much detailed information about how to use drag-drop capabilities among any DOM elements and components using Ext

The most important source for this topic is the following sencha document:
http://docs.sencha.com/ext-js/4-0/#!/guide/drag_and_drop

For starters who just want to apply basic drag drop between a grid and any div element, you can follow the above steps:

1)Create a new grid. Besides of its required properties , this grid must have the following property:

viewConfig: {
    forceFit: false,
    plugins: {
       ptype: 'gridviewdragdrop',
       dragGroup: 'gridDDGroup'
    }
}


model fields: firstName,lastName
2)Add a div to your body.

< div id="droppablezone" style=" background-color: Gray;" >< / div >

The important one is its id name which we will use in third step.

3)Make your div a valid drop target:

Ext.create('Ext.dd.DropTarget', 'droppablezone', {
    ddGroup: ' gridDDGroup ',
    notifyDrop: function (ddSource, e, data) {
        document.getElementById( e.target.id ).innerHTML += data.records[0].data.firstName;
    },
    notifyEnter: function (ddSource, e, data) {
    }
});

First we create an Ext.dd.DropTarget of our 'droppablezone' id. For ddGroup property, we put the same value as grid's dragGroup property.
I put two listeners here:
notifyEnter: Whenever dragged item is in div's area, it is called. e
notifyDrop:When item is dropped in div's area, it is called. data is used to get dragged item's record. In my example I used record's model's firstName. I also used e parameter to show that you can get dropped target information via this parameter's target property.(you can just write 'droppablezone' instead of e.target.id)

You can apply similar structure to trees also.





8/05/2012

Layout Management in Extjs 4.0

I want to share my experience about panel layouts in Extjs 4.0. Some of them may not be valid in future releases.

a)Panel or Container: There is a little difference between two of them. Container has no element intially. If you use an empty conatiner in a panel, you cannot see a difference in panel. But panel gives us a div element which has a white background and a border as default. You can throw out border and frame using properties but still you will get an extra div element. When inserting a new element with a fit layout you will get same screen in both cases.

b)viewport or border: It may be difficult to understand why viewport is used instead of border layout. The main difference is that viewport uses Ext.getBody() when rendering itself. That means you dont need to write renderTo:Ext.getBody() line. However as you guess, you cannot use two viewports in one page, Every page must have a one renderer that uses body. Border layout just use its parent panel when rendering. You should use one viewport as your main layout and any number of border layouts in sub panels.

Collapsible Panels: In both border and viewport, any of subitems(center,north,south,west,east) can be collapsible by setting collapsible:true but there are some issues in collapsible panels.

1)If you collapse center panel, south panel cannot resize itself like flex structure. You need to manually set its height when a collapse occurs. But then when you try to resize center panel, it will not return to its original size since you manually change height of the south panel. In Extjs forums, it is not considered as bug and some guys suggests to use vbox instead of border but vbox has its own limitations.

2)When you set a panel as collapsible, header panel is forced to show. This header in most cases result in an absurd layout if you dont want to use title. You can configure to hide header panel, but this will result in a problematic minimized panel in center region. The obvious solution is to construct your own collapse expand button. You can add this button whenever you want, You just need to set height to 0 or main panels height for minimize and maximize.

3)In IE 8, collapse animation in south panel gives a style error after collapse/expand certain amount. Setting animCollapse ot false fix this issue. I thing they will fix it in future releases.

4)If you dont use center panel, extjs will definitely give you an error.

5)In order to resize sub panels, resizable or split can be used. Resizable will put a border to your panel when you want to resize. Resize property is like resizing an image like element. But split is like Telerik or devexpress split component which is used between panels.

6)Adding removing subpanels: It is vital to know that you cannot dynamically add or remove a component of border layout. It is suggested to use main region panels as containers and add/delete panels within them.

c)vbox and hbox: These are used to vertically and horizantally align panels. In sub panels, there is an important property related with layout: flex.You can give an exact width or height or use a flex number. When calculating width or height for a sub panel, first exact numbers are summed, these number is substracted from total width or height. Then remaining number is divided into flex number.  For instance, if you have two sub panels with flex:1 and a sub panel with width:10. Then 10  is substracted from main panels's width.Remaining number is divided by two. These result will be remaining panels' width. Flex also dynamically change when you change one of the panel's width or height.

d)Removing panels permanently or temporarily: When you want to change content of a panel, you may want to just destroy content or toggle between panels. Destroying a panel will result in destroying the panel and all sub panels within this panel permanently. If you use an id for calling this panel, you will get an error after destroying it. You can deal with this problem with using dynamic creation of panels(Ext.create) in run time and using dynamically created panel's id(subpanel.id). If you dont want to destroy your panel but hide it for a certain amount of time, you can remove sub panel using this:
mainPanel.remove(subPanel,false);
Beware that using this structure too much may lead to too much resource consumption.

e)Using config or Ext.create for subPanels: Both will give us same results with a small difference. If you keep config objects and use them in your viewport (or a panel which renders to body), all of rendering will be done at the end. You can modify easily among configs before actually showing them. This will save certain amount of time since DOM manipulation is always costly. However before viewport is called, you cannot reach sub panels elements by calling Ext.getCmp('sub panel name') since it is not created yet. you need to change config instead. Since some of the properties cannot be changed after creation (for instance id), you should use config objects instead of creating them.

f)Menu: Menu is generally used in two cases: First one is button. If you add items to button, these items will be considered as menu items. Second one is context menu. When you right click an item(grid or tree item in most cases) you may need to show a menu. It is a bit tricky than button since you need to handle where to show menu. You also need to cancel standard rigt click menu.

Easiest way to combine ExtJS with jQuery UI

Although there are many ways to integrate your jQuery script into a native Extjs based solution, the easiest way is to use html property of a panel. In the area that you want to insert your jQuery based UI, you need to add a panel with the following config:
{
    html:'< div id = "id_area" style="width:100% height:100%" > < /div > '
}
This will be our main container. Using $('#id_area') you can insert any dom element you want. Main element will cover all of your panel by using style width and height properties.
However there are certain rules in that approach.First one is z-index. If you want to use navigation like elements, expanding menu may result in a div element whose level is lower than any other extjs based panel. To cope with this problem, you may want to use main panel's html property instead of using sub panels.
Second problem is about events. If you want to assign a method to an event, you need to implement that method outside of the Extjs onReady function since onReady will create its own scope.
There is also one more thing about html property. It can be cleared using div's innerHTML property, when you add an extjs panel into your main panel, main panel's html content will be ignored and your inserted panel will cover all of your main panel.

5/01/2012

Consuming WCF Service with Ext JS

We decided to use WCF as our primary source for Ajax requests coming from our Ext JS application. However, there are 3 major steps that must be set before using WCF along with any Ajax requests.

1)WCF Service must be configured as WebHttpBinding. In other words, we need a restful service.Example web.config for your service:

First you need to define a behaviour name in serviceBehaviors section and use it in service behaviorConfiguration property.(RN.Service.PopulationServiceBehavior) You need to fill endpoint name property and Contract name property as your service name with its namespace prefix.(RN.Service is namespace and PopulationService is method name). Endpointconfiguration must be defined in endpointBehaviors.(jsonBehavior)

2)You need to add following settings before defining your service method.(you can either use interface or method itself)

        [WebInvoke(Method = "*",
           BodyStyle = WebMessageBodyStyle.Bare,
           //RequestFormat = WebMessageFormat.Json,
           //ResponseFormat = WebMessageFormat.Json,
           UriTemplate = "/GetExtJSList")]
Method can be GET or POST. It allows both. For BodyStyle I used Bare because i dont have any complex returning or parameter. I also want JSON string. UriTemplate is vital since you will be calling your method using these name. (service url/uriTemplate name)

3)You need to allow Ajax requests from different ports. This concept is related with Cross-Domain Call. When you try to test your WCF service along with a web application, you will probably get the following error since these two projects will be run in different ports:
XMLHttpRequest cannot load ... Request header field X-Requested-With is not allowed by Access-Control-Allow-Headers.
The problem is that, Ajax request uses OPTION method instead of GET or POST in request header. If it manages to get a success response a second request is sent with GET or POST. The solution that i provided is working in IE. You can also bypass this problem with opening browsers in cmd with certain parameters.
For Chrome:

chrome.exe --disable-web-security

In order to handle OPTION request header once for all, you need to add a global.asax(if not exist in your poject) and add the following code to Application_BeginRequest:

            HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin",
                          "*");
            if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
            {
                HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods",
                              "GET, POST");
                HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers",
                              "Content-Type, Accept");
                HttpContext.Current.Response.AddHeader("Access-Control-Max-Age",
                              "1728000");
                HttpContext.Current.Response.End();
            }

Instead of *, you can define your application domain.(since * may cause security problems. You accept all domain requests in that case).

At that point, I suggest you to use Fiddler like programs to see what is going on behind the scene.

Now you are ready to consume WCF. I write a basic Ext JS Tree Panel example.(asynchronization approach is not used) You need to consider Tree Store requirements if you want to use JSON Serialize class(children,leaf properties etc.)

                Ext.define('PopulationMenuModel', {
                    extend: 'Ext.data.Model',
                    fields: [
                    { name: 'text', type: 'string' },
                    { name: 'id', type: 'string' },
                    { name: 'leaf', type: 'bool' }
                ]
                });
                var TreePopStore = Ext.create('Ext.data.TreeStore', {
                    proxy: { url: 'http://localhost:50081/PopulationService.svc/GetExtJSList'
                    , type: 'ajax',method:'GET'                    
                     },
                    model: PopulationMenuModel
                });
                var Tree = new Ext.tree.TreePanel(
                                 {
                                     height: 400,
                                     useArrows: true,
                                     title: 'deneme',
                                     autoScroll: true,
                                     animate: true,
                                     renderTo: 'tree-div',
                                     enableDD: true,
                                     containerScroll: true,
                                     border: false,
                                     rootVisible: false,
                                     store: TreePopStore
                                 });

As a last warning, if you plan to return string instead of JSON Serialize + IList approach, you need to be extra careful since we set WebMessageFormat.Json as response format. It may cause double serialize issues. In my case, i get "[{id:12,text:'test'}]" instead of [{id:12,text:'test'}] which is wrong since Ext JS cannot parse JSON with "" tags. I solved this problem using Stream instead of string.

Stream mymethod(){

byte[] byResponse = Encoding.UTF8.GetBytes(mystring);
            return new MemoryStream(byResponse);

}

For JSONP Users:
I also want to explain how to use JSONP since it is a powerful method to consume services in different domain. In WCF side, we need to encapsulate our JSON string with a callback function.
callback1( [your json here] )
Then we can use jsonp instead of json.

 proxy: {
          url: 'http://localhost:50081/PopulationService.svc/GetExtJSList',
          type: 'jsonp'
}

I try to include all problems and solutions that I encountered during 3-4 days.

References:






4/12/2012

Ext JS 4 TreeStore load problem

There is a minor bug in TreeStore load() method. If your tree has no root(dont ask why you use tree if you dont have a root), load method will crash since it calls removeAll() method which tries  and fails to find root.

Solution: set clearOnLoad = false in config.

If you want to clear before load, you can call:
this.fireEvent('clear',this);

References:
http://www.sencha.com/forum/showthread.php?170617-Ext.data.treeStore.removeAll-is-an-unsafe-method
http://docs.sencha.com/ext-js/4-0/#!/api/Ext.data.TreeStore-method-load