søndag den 22. april 2012

Popup panel with Sencha Touch 2

So I started working on a webapp with a JavaScript framework called Sencha Touch 2. As this version is fairly new - I believe it was released within the past 3-6 months - people are still trying to figure it out. At least I am. With only a week of experience with this framework I am not an expert, but I will allow myself to present an example I've spent a couple of days searching the web for the right way to do and now I think I've figured out the 'Sencha Touch 2'-way of doing it.

What I'm talking about is popup box. If you need some quick input from the user, but don't want to spend a part of the original user interface on a textbox or selection list or whatever that are only needed on a rare basis, this kind of popup are a great way to go. With the MVC-model that are used in Sencha Touch 2 there are certain steps that needs to be done for it to work.

The goal of this example is to make a custom panel appear with the click/tap of a button and then make it go away by clicking/tapping with a button on that panel. So here's how I did:

In this example I've started with the most basic app created using the Sencha SDK Tool by entering the following command in my Command Prompt.
sencha generate app <appname> <path\to\app>
 The use of this tool is described in the 'Getting Started' video at www.sencha.com.
When that's up and running I stripped it down to the bare minimum leaving only the start view in a Home.js file and saw that that was good. I then added a button to the home screen like this:

1:  {  
2:     xtype: 'button',  
3:     text: 'View Pop up',  
4:     action: 'showPopup',  
5:  }  

Note the use of the action config that we will be using later. That is all that it takes in the view. No more is needed in that file at all.

Next I made the panel that will be appear when clicking/tapping that button. The code looks like this:


1:  Ext.define('GS.view.Popup',{  
2:    extend: 'Ext.form.Panel',  
3:      
4:    xtype: 'popupbox',  
5:      
6:    config:{  
7:      itemId: 'popbox',  
8:      floating: true,  
9:      centered: true,  
10:     modal: true,  
11:     height: 200,  
12:     width: 300,  
13:     showAnimation: { type: 'slide', direction: 'left'},  
14:     styleHtmlContent: true,  
15:     html: 'Hi, I\'m a popup',  
16:     items:[  
17:       {  
18:         xtype: 'button',  
19:         action: 'hide',  
20:         text: 'Close',  
21:         ui: 'confirm',  
22:         docked: 'bottom',  
23:       }  
24:     ]  
25:    }  
26:  });  

Worth noting here is modal that greys out the area around the popup making it inaccessible and showAnimation, that tells how the popup will appear on the screen. I've decided it to slide in from the right going left. Again the button has an action. Also note the itemId that will be used to reference the panel, when we need it. After adding this panel to the list of views in app.js we can turn our attention to the interesting part: adding a controller to the party and make it do stuff.

First we add a file to the controller folder. I named mine Main.js, Then add the line:

1:  controllers: ['Main'],  

to the app.js file just above the views. Now the application knows about your controller and you can begin adding code to the controller file. Let's take it one bite at a time. The first part of the controller file looks like this:

1:  Ext.define('GS.controller.Main',{  
2:      extend: 'Ext.app.Controller',  
3:      config:{  
4:          refs:  
5:              {  
6:                  popup: {  
7:                      selector: 'formpanel #popbox',  
8:                      xtype: 'popupbox',  
9:                      autoCreate: true,  
10:                  }  
11:              }  
12:      },  

The refs uses ComponentQuery with the selector to search for a reference to given component - here its our popup. With the autoCreate it checks if it's been created before it's used, if not it will be created.
In the next part we make use of the action configs from before:

1:      init: function() {  
2:          this.control({  
3:              'button[action=showPopup]': {  
4:                  tap: 'showPopup'  
5:              },  
Feel free to comment
6:              'button[action=hide]':{  
7:                  tap: 'hide'  
8:              }  
9:          });  
10:      },  

Here we initiates the controller by setting up listeners to the two buttons with the specific actions to listen for the tap event on those buttons. When tapped it will execute the functions shown below.

1:      showPopup: function(){  
2:          var popup = this.getPopup();  
3:          Ext.Viewport.add(popup);  
4:          popup.show();  
5:      },  
6:        
7:      hide: function(){  
8:          var popup = this.getPopup();  
9:          popup.hide({type: 'slideOut', direction: 'right'});  
10:      }  
11:  });  

Both functions uses the autogenerated getter method to retrieve a reference to the popup panel. In the show function the panel gets added to the Viewport and then show()'ed. In the hide function it is hidden  with the selected animation. For some reason the show animation needs to be a config in the panel, but the hide animation is an argument to the hide method. If you have a reason for this feel free to comment on it :)

That's all there is too it and should give the following result:
Screenshot of app without popup

Screenshot of app showing the popup