sencha touch 2 quick start
TRANSCRIPT
Based on: ‘Sencha Touch -‐ Open-‐Source HTML5 Mobile Web Development Made Easy’ by Stan Bershadskiy
Contents of document: Ø The Class System Ø The Component System Ø The Event System Ø Selectors Ø Data Package Ø And more…
Sencha Touch 2 Quick Start
The Sencha Touch class system allows creation of new JavaScript classes, providing inheritance, dependency loading, mixins, configuration options, and more.
Ext.define('Motercycle', { config: { buildYear: null, topSpeed: null, price: null }, constructor: function (config) { this.initConfig(config); }, isExpensive: function () { return this.getPrice() > 2000; } }); Ext.define('SuperBike', { extend: 'Motercycle', config: { model: null, brand: null }, isSuzuki: function () { return this.getBrand() === 'Suzuki'; }, isExpensive: function () { return this.getPrice() > 10000; } }); We defined a Motorcycle class with a Superbike subclass. The Motorcycle class has some basic properties defined in the config object. Besides class properties we defined some basic class methods as well. The Superbike class extends the Motorcycle class and thereby inherits its properties and methods. In addition we are able to define a unique implementation of each method. We can instantiate a class by using Ext.create instead of the new keyword. Using the former leverages Sencha Touch’s dynamic dependency loader and allows for using aliases, as well as easily applying the config object.
var hondaMotercycle = Ext.create('Motercycle', { buildYear: 2002, topSpeed: 180, price: 2000 });
The Class System
hondaMotercycle.isExpensive(); //returns false hondaMotercycle.getPrice(); //returns 2000 var suzukiGSXR = Ext.create('SuperBike', { buildYear: 2015, topSpeed: 300, price: 12000, model: 'gsxr1000', brand: 'Suzuki' }); suzukiGSXR.isExpensive(); //returns true suzukiGSXR.getModel(); //returns "gsxr1000"
You may notice the use of some functions that we have not explicitly defined, for example getModel(). The Sencha Touch class system does us a favor and generates 4 types of convenience functions:
• Getter – return current value; getName() • Setter – set new value; setName() • Applier – called by setter, execute logic when
property changes; applyName() • Updater – called by setter, execute logic when the
value for a property changes; updateName()
TIP
Please note that the applier and updater functions require implementation. The applier function requires a return of the value that will be set to the property. The updater gets fired after the applier and does not handle a return, rather, it just informs of a value change
Let’s assume we want to round the price of the Motercycle to the nearest 1000. To do so we would implement the applyPrice function in the Motercycle class:
applyPrice : function (newPrice, oldPrice) { return Math.round(newPrice / 1000) * 1000; }
Usage:
hondaMotercycle.setPrice(1995); hondaMotercycle.getPrice(); //returns 2000
Based on: ‘Sencha Touch -‐ Open-‐Source HTML5 Mobile Web Development Made Easy’ by Stan Bershadskiy
A crucial requirement for many mobile applications is to consume data from external sources as well as maintain internal application specific data. For these situations Sencha Touch provides the Data Package, a set of classes responsible for loading, storing, manipulating and saving data. Three types of classes generally leverage the data package:
• Model – an entity that represents a single record, defining its fields, validation, associations and conversion parameters.
• Store – collection of model instances with support for sorting, filtering, and grouping
• Proxy – medium that interacts with the remote or local data source and performs the necessary reading and writing operations.
Models Models are data objects that are managed in your application. Models are defined by a set of data fields. Each field is defined by its name, type, and optional defaultValue. Supported field types are:
• string • int • float • boolean • date
A convert function can also be implemented on the field to perform processing on the field’s data. Here is a sample model:
Ext.define('MyApp.model.Car', { extend: 'Ext.data.Model', config : { fields : [ { name: 'make', type: 'string' }, { name: 'model', type: 'string' }, { name: 'topSpeed', type: 'int' }, { name: 'price', type: 'float' }, { name: 'options', type: 'auto' } ] } }); Data Proxies There are four proxies provided by Sencha Touch that can be used in a Store or Model.
• LocalStorage – saves data to localStorage • Memory – saves data in memory, extremely volatile • Ajax – communicates with a RESTful resource on the
same domain • JsonP – communicates with a service on an external
domain using JSON-‐P Each proxy type implements four basic operations create, read, update, and destroy. When interacting with Server Proxies, there is a need for serializing the data sent and retrieved from the server. For this
Data Package Sencha Touch provides the JsonReader, JsonWriter, XmlReader and XmlWriter classes. These reader and writer types are specified on the proxy definition. Example Store with Proxy
Ext.define('MyApp.store.Cars', { extend: 'Ext.data.Store', requires : [ 'Ext.data.reader.Json', 'Ext.data.writer.Json' ], config: { model: 'MyApp.model.Car', proxy: { type: 'ajax', url: '/cars', reader: { type : 'json', rootProperty: 'cars' } } } });
TIP
Proxies can be attached to both Models and Stores. The result is the same, the Store will be looking for a Proxy config on itself and if none is present it will look for it on the Model. However, if the Proxy is defined inside the Model, multiple Stores using the same Model don’t have to define the config. Furthermore, defining a Proxy inside a Model allows you to save and load an instance of that Model without needing a Store
To access a store from anywhere in the application you can use the Ext. getStore() function and pass in either a defined storeId or the store’s classname, excluding namespace. Example of loading data into a store:
Ext.getStore("Cars").load();
Based on: ‘Sencha Touch -‐ Open-‐Source HTML5 Mobile Web Development Made Easy’ by Stan Bershadskiy
The Component System
Common Components The Sencha Touch Component system is the foundation of all the visual elements in the framework. The Component system makes full use of the Class system’s dependency injection and hierarchical support. Every Sencha Touch view class is a subclass of Ext.Component, and thus follows its lifecycle. Components are generally defined by an xtype. An xtype is a shortcut for the full component Class name allowing for lazy instantiation. Using xtypes to instantiate components allows the creation of the object to be deferred to when it’s actually needed, thus saving resources. There may be times when you want to display multiple components, either all at once or individually. The Ext.Container class exists for these situations. Containers provide functionality for adding child Components, removing Components and specifying a Layout that determines how these components are displayed.
Component Purpose Useful Properties & Functions
Component Ext.Component xtype: component
Basic Visual Class xtype cls html tpl data show() / hide() /destroy()
Container Ext.Container xtype: container
Manages Component rendering and arrangement
layout items scrollable add(component) / remove(component)
Panel Ext.Panel xtype: panel
Container designed to float as overlays
showBy(component)
Toolbar Ext.Toolbar xtype: panel
Docked containers that generally hold Buttons and a Title
title left / right ui
Button Ext.Button xtype: button
Basic tappable component
text ui iconCls iconAlign
Based on: ‘Sencha Touch -‐ Open-‐Source HTML5 Mobile Web Development Made Easy’ by Stan Bershadskiy
Tab Panel Ext.tab.Panel xtype: tabpanel
Container that allows user to easily switch between components using a Toolbar
tabBarPosition
MessageBox Ext.Msg Ext.MessageBox
Modal Container for displaying alerts and notifications. Ext.Msg is a singleton that allows for creation of predefined MessageBox instances.
Ext.Msg.alert(title, msg, callback) Ext.Msg.confirm(title, msg, callback) Ext.Msg.prompt(title, msg, callback)
Carousel Ext.Carousel xtype: carousel
Container that allows user to switch active components by swiping
ui direction indicator next() / previous()
List Ext.dataview.List xtype: list
Container of dynamically rendered components from a Data Store
store itemTpl itemCls onItemDisclosure grouped indexBar
Form Panel Ext.form.Panel xtype: formpanel
Panel that contains a set of form fields to be displayed
getValues() / setValues(data) submit(options, params, headers)
Form Fields Ext.field.Field xtype: field
Base class for all data input form fields
name label / labelCls / labelAlign inputCls required
Layouts Layouts describe the sizing and positioning on Components inside your app. For example, an email client might have a list of messages pinned to the left, taking up one third of the available width, and a message viewing panel in the rest of the screen. We can achieve this using an hbox layout and its ability to ‘flex’ items within it. Flexing means that we divide the available area based on the flexof each child component, so to achieve our example above we can set up flexes like shown in the following image:
In the code for this layout we need to specify the ‘hbox’ layout on any Container, then supply a flex parameter for each of the child components (Panels in this case) as follows: Docking
Ext.create('Ext.Container', { fullscreen: true, layout: 'hbox', items: [ { xtype: 'panel', html: 'message list', flex: 1 }, { xtype: 'panel', html: 'message preview', flex: 2 } ] });
Vbox layout
Card layout Sometimes you want to show several information screens information on a small device screen. TabPanels and Carousels both enable you to see one screen of many at a time, and underneath they both use a Card Layout. Card Layout takes the size of the Container it is applied to and sizes the currently active item so as to completely fill the Container. It then hides the rest of the items, allowing you to change which one is currently visible, but only showing one at once:
Fit layout The Fit Layout is probably the simplest layout available. All it does is make a child component fit the full size of its parent Container.
Based on: ‘Sencha Touch -‐ Open-‐Source HTML5 Mobile Web Development Made Easy’ by Stan Bershadskiy
Every layout is capable of docking items inside it. Docking enables you to place additional Components at the top, right, bottom, or left edges of the parent Container, resizing the other items as necessary.
XTemplate Template based components have been the norm in many web applications thanks to frameworks like Mustache, Handlebars, Closure, and more. Sencha Touch provides first class functionality for templating through the Ext.XTemplate class. The Ext.XTemplate class supports not only simple data identifiers but also:
• Array traversal • Conditional processing • Basic math functionality • Execute arbitrary code • Execute custom template functions
When defining an XTemplate, the tpl tag is reserved for template commands. Array Traversal Looping through an array is done with the tpl for keyword with the value being either "." or a property path.
TIP While iterating the array, there are two special variables {#} and {.}. {#} represents the current index of the array + 1. {.} represents the value of the element at the current index
Example assuming the data is an array of Car objects:
<tpl for="."> <div>{make} {model}</div> </tpl>
Example assuming the data is an object with a cars property that holds arrays grouped by make:
<tpl for="cars.toyota"> <div>{#} {.}</div> </tpl>
Conditional Processing XTemplate supports 4 basic comparison operations: if, else-‐if, else, and switch. Examples:
<tpl for="cars"> <div>{make} {model} is <tpl if="topSpeed > 150"> <span>ridiculously fast</span> <tpl elseif="topSpeed > 80"> <span>somewhat fast</span> <tpl else> <span>ridiculously slow</span> </tpl> </div> </tpl> <div> {make} is <tpl switch="{make}"> <tpl case="BMW" case="Mercedes-‐Benz" case="Audi"> <span>luxurious</span> <tpl default> <span>economical</span> </tpl> Math Support The following math operators are supported: + -‐ * / Example:
<tpl for="cars"> <div>Top Speed in km/h is {topSpeed * 1.6}</div> </tpl>
Executing Arbitrary Code It is possible to execute JavaScript code while in the scope of the template by using [] inside an expression. While executing code inside a template expression there are several special values available:
• out – output array of the template • values – values in the current scope • parent – values of parent data object • xindex – if in looping template, then the 1-‐based
index • xcount – if in looping template, then the total
length of array Example:
<tpl for="cars"> <div>{[values.make.toUpperCase() + " -‐ " + values.model.toLowerCase()]}</div> </tpl> Custom Template Function When defining our Ext.XTemplate instance, we can implement functions that will be executed by the template. Example: (See next page)
Based on: ‘Sencha Touch -‐ Open-‐Source HTML5 Mobile Web Development Made Easy’ by Stan Bershadskiy
var tpl = new Ext.XTemplate ( '<tpl for="cars">', '<div> {make} is', '<tpl if="this.isFast(make)">', '<span>fast!</span>', '<tpl else>', '<span>slow</span>', '</tpl>', '</tpl>', { isFast : function (make) { return (make === "Ferrari"); } } );
Theming An important aspect of any application is styling and theming. Sencha Touch applications are styled using SASS and compiled with Compass.
TIP Compass requires Ruby to be installed on your computer and can be installed using rubygems. More information can be found here: http://compass-‐style.org/ More information on SASS can be found at: http://sass-‐lang.com/
Common Global SASS Variables Variable Description $base-‐color Primary color that most elements
reference $base-‐gradient Primary gradient color most elements
reference $font-‐family Font family used throughout the theme $page-‐bg-‐color Background color of fullscreen
components Common Global SASS Mixins Mixin Description pictos-‐iconmask($name)
Include a base64-‐encoded icon to be used with Tab Buttons. Name must match icon‘s file name in resources/themes/images/ default/pictos without extension @include pictos-‐iconmask(‘wifi2‘);
bevel-‐text($type) Add text shadow or highlight. $type is either shadow or highlight.
stretch() Stretch an element to parent‘s bounds
ellipsis() Apply element text-‐overflow to use ellipsis
A crucial part of the Component and Application life cycle in general are the events that are fired at different stages. These events can be triggered from some interaction with a component or be fired after some arbitrary business logic is executed. Most importantly, for each event we can configure simple listeners to handle these events. We react to events by attaching event listeners on a given component through the listeners property or the on() function where we pass in an object where the event name maps to a callback. When we define the listeners, we can also attach the context that the callback gets executed in via the scope property.
myButton.on({ tap : function () { console.log("button tap"); }, scope : this }); Common Events Fired by Components
• painted – fires when element becomes rendered on the screen
• show / hide – fires when view component, generally a modal, is shown or hidden using show() and hide()
• updatedata – fires when data of component is updated
Common Events Fired by Containers • activate / deactivate – fires when an item in the
container is activated or deactivated • activeitemchange – (card layout only) fires when
the actively visible item is changed by setActiveItem()
• add / remove – fires when components are added or removed from container
Sencha Touch allows us to also manage events that are fired by the DOM elements that these components render. These DOM elements are of type Ext.dom.Element. The elements fire events for native browser gesture interactions. Here is an example of attaching event listeners for both component and element events. You can also see some simple event handler implementation as well as firing of custom events.
Ext.define("MyApp.view.tooltip.Tooltip", { extend: "Ext.Panel", xtype: "tooltip", config: { /* ... */ }, initialize : function () { var me = this; me.element.on({ tap : me.onTap, touchstart : me.onTouchStart, /* Continued on the next page */
The Event System
Based on: ‘Sencha Touch -‐ Open-‐Source HTML5 Mobile Web Development Made Easy’ by Stan Bershadskiy
touchend : me.onTouchEnd, scope : me }); me.on({ show : me.onShow, hide : me.onHide, scope : me }); me.callParent(); }, onTap : function (evtObj) { this.fireEvent('close'); }, onTouchStart : function (evtObj) { var closeButton = evtObj.getTarget(".close-‐button"); if (closeButton) { Ext.fly(closeButton).addCls('pressed'); } }, onTouchEnd : function (evtObj) { var closeButton = evtObj.getTarget(".close-‐button"); closeButton && Ext.fly(closeButton).removeCls('pressed'); }, onShow : function () { /* ... */ }, onHide : function () { this.destroy(); } }); Common Events Fired by Elements
• tap -‐ fires for every tap • doubletap -‐ fires for a double tap • taphold / longpress -‐ fires for when you hold a tap
for > 1 second • touchstart / touchend -‐ fires for when the touch
starts and finishes • drag -‐ continuously fires for dragging • dragstart / dragend -‐ fires when dragging begins and
finishes • pinch / rotate -‐ continuously fires for pinch and
rotate gestures swipe -‐ fires when there is a swipe; the event property holds the swipe direction
Selectors One of the most useful functionalities of Sencha Touch and ExtJS as well is the support for finding the instance of a component or DOM element. Similar to jQuery’s $ selector, Sencha Touch provides the child(), up(), down() and query() functions to each Container class. These functions take in a ComponentQuery Selector and return either the first component (child(), up(), down()) or an array of all matching components (query()). You can also query for components on a global scope by using the Ext. ComponentQuery singleton, which has a query() method.
Selector Type Purpose Example
xtype Select component based on its xtype
Ext.ComponentQuery.query(‘. formpanel‘); myContainer.down(‘.button‘);
itemId / id Select component based on its itemId or id property
Ext.ComponentQuery. query(‘#myFirstPanel‘); myContainer.down(‘#submit‘);
Attribute Select a component based on its xtype and some property value that is set on it
myFormPanel.down("field[name= userName]);
Nested Selector
Select a child of a matched selector
Ext.ComponentQuery.query(‘panel > toolbar‘);
Multiple Selector
Select children that match multiple selectors
Ext.ComponentQuery. query(‘formpanel, carousel‘);
TIP We can also query on DOM Elements. The Ext.dom.Element class provides query() and down() functions. Here however we use CSS selectors. More information on CSS Selectors can be found here: http://www.w3.org/TR/selectors/
Based on: ‘Sencha Touch -‐ Open-‐Source HTML5 Mobile Web Development Made Easy’ by Stan Bershadskiy
Cheat Sheet List of Sencha defined xtypes xtype Class -‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐ -‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐ actionsheet Ext.ActionSheet audio Ext.Audio button Ext.Button component Ext.Component container Ext.Container image Ext.Img label Ext.Label loadmask Ext.LoadMask map Ext.Map mask Ext.Mask media Ext.Media panel Ext.Panel segmentedbutton Ext.SegmentedButton sheet Ext.Sheet spacer Ext.Spacer title Ext.Title titlebar Ext.TitleBar toolbar Ext.Toolbar video Ext.Video carousel Ext.carousel.Carousel carouselindicator Ext.carousel.Indicator navigationview Ext.navigation.View datepicker Ext.picker.Date picker Ext.picker.Picker pickerslot Ext.picker.Slot slider Ext.slider.Slider thumb Ext.slider.Thumb tabbar Ext.tab.Bar tabpanel Ext.tab.Panel tab Ext.tab.Tab viewport Ext.viewport.Default DataView Components -‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐ dataview Ext.dataview.DataView list Ext.dataview.List listitemheader Ext.dataview.ListItemHeader nestedlist Ext.dataview.NestedList dataitem Ext.dataview.component.DataItem Form Components -‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐ checkboxfield Ext.field.Checkbox datepickerfield Ext.field.DatePicker emailfield Ext.field.Email field Ext.field.Field hiddenfield Ext.field.Hidden input Ext.field.Input numberfield Ext.field.Number passwordfield Ext.field.Password radiofield Ext.field.Radio searchfield Ext.field.Search selectfield Ext.field.Select sliderfield Ext.field.Slider spinnerfield Ext.field.Spinner textfield Ext.field.Text textareafield Ext.field.TextArea textareainput Ext.field.TextAreaInput togglefield Ext.field.Toggle urlfield Ext.field.Url fieldset Ext.form.FieldSet formpanel Ext.form.Panel
List of pictos icon set available in Sencha
TIP
By default Sencha Touch 2 does not include the full icon list to keep the Stylesheet lightweight. If you wanted to include an icon that is not available in the default list below, you would have to add the following to your .SCSS file:
@include icon('network');
Default included pictos iconCls list (see icons above) action add arrow_down arrow_left arrow_right arrow_up bookmarks compose delete download favorites home info locate
maps more organize refresh reply search settings star team time trash user
Based on: ‘Sencha Touch -‐ Open-‐Source HTML5 Mobile Web Development Made Easy’ by Stan Bershadskiy
MVC Previously we introduced Views and Models. Now, it’s time to connect them together to form a full-‐fledged application by adding in a Controller concept. Controller Sencha Touch implements the Controller through the Ext.app.Controller class. The Controller is responsible for responding to events that your components may fire. There are two core configuration properties of the Controller: ref and control.
• refs – execute ComponentQuery to locate first component instance to match selector and generate getter function
• control – listen to events from ComponentQuery selectors or refs and attach listeners
Controller Example:
Ext.define('MyApp.controller.Main', { extend: 'Ext.app.Controller', config: { refs: { loginPanel: 'loginpanel', loginButton: 'loginpanel button[text="login"]' }, control: { loginpanel: { validate: 'onLoginPanelValidate' }, loginButton: { tap: 'onLoginButtonTap' } } }, onLoginPanelValidate : function () { this.getLoginPanel().validate(); }, onLoginButtonTap : function () { this.getLoginPanel().submit(); } }); Application Now that we have Models, Views, and Controllers defined we need a way to connect them together so that they can coexist and work with each other. For this we have the Ext.app.Application class that connects Models, Controllers, Profiles, Stores and Views together by instantiating them through the dependency loader. All Sencha Touch applications begin with a call to the Ext.application function that creates an Application instance. Example Application instance:
Ext.application({ name: 'MyApp',
models : [ 'Car', 'User' ], /* Continued on the right */
stores : [ 'Cars', 'Users' ], views : [ 'LoginPanel', 'CarDetailView' ], controllers : [ 'Main' ], launch : function () { Ext.fly('appLoadingIndicator').destroy(); } });
Packaging / Deploying Since Sencha Touch is a full-‐fledged application framework it is only fitting that there exists a tool supporting the application’s entire life cycle. Sencha Cmd is a command line utility that provides automated tasks from generating a new application to generating components of an existing application to preparing an application for production deployment. Sencha Cmd contains the following major features:
• Code generation • Optimized Sencha specific JavaScript minifier
and obfuscator • Native Packager to wrap mobile web
application as a native hybrid application using Phonegap/Cordova
• Workspace management allows sharing code between applications
TIP
You may notice that when we specify the models, stores, views, and controllers we do not include the necessary namespaces. You can also specify models, stores and views in Controllers. In the Ext. app.Application and Ext.app.Controller class, Sencha Touch’s loader looks up the dependency based on the context provided in the configuration.
Example Usage Generate New Application
Sencha generate app MyApp /path/to/MyApp
Generate Models, Controller and Views
cd /path/to/MyApp sencha generate model Car make:string,model:string,price:float sencha generate controller Main sencha generate view CarDetailView
Generate New Application
sencha app build [-‐d ‘testing’|’production’|’package’|’native’]
Based on: ‘Sencha Touch -‐ Open-‐Source HTML5 Mobile Web Development Made Easy’ by Stan Bershadskiy
Sencha Best Practices Avoid hardcoded ids and Ext.getCmp Sencha Touch generates a unique random id and registers it with the ComponentManager. It is possible to force a static id for your component and retrieve it using the Ext.getCmp(id) function. However, as your project and number of developers grow, the chance that the static ID that you thought would stay unique diminishes. Thus, it is recommended to use either itemId, which assigns a pseudo-‐id and is scoped locally to the Container, or to use ComponentQuery. Useful References:
• http://extjs.eu/writing-‐a-‐big-‐application-‐in-‐ext/ Avoid Controller refs with multiple instances Generally, it is a good practice to make your components generic enough to be reusable or extensible throughout your application. Often, when defining a Controller ref, it is forgotten that it only returns the first instance that matches the ComponentQuery selector. Thus, it is recommended to use a ComponentQuery inside your event listener to determine the proper instance of the desired Component you need. Avoid over-‐nesting Containers Sencha Touch Containers do an excellent job in maintaining their child components and making sure they are displayed properly. To accomplish this task, there is a lot of calculation and manipulation of the DOM involved in the layout managers of these containers. It is easy to begin carelessly nesting these containers inside of each other. When the containers are nested it becomes much more processor intensive to calculate how to display the components and their underlying DOM elements properly. Reduce reliance on built-‐in Components Many of Sencha Touch’s components are designed to be widgets that are meant to be items of a Container and arranged by the layout manager. While this is acceptable in certain simple situations, it often results in unnecessary utilization of the DOM. Sencha Touch allows us to create custom views by leveraging XTemplate and controlling the markup of our component to be as minimal as necessary. Do not edit the Framework code Yes, delve into it, read it, test it, learn from it – but don’t edit it! If you start making changes to the core library, whether it is the JS or CSS, you are planting a ticking time-‐bomb into your application. When you come to upgrade to a newer version all those changes will be lost and you will have to traipse through trying to figure out where things are broken! If you want to alter the behavior/look of the framework then go for it but do it by overriding the class (be it a JS class or a CSS class) or method in a separate script file. By doing this you can remove it if necessary and keep track of it when it comes to reviewing those changes when new versions are released.
Be careful of spaghetti Code/Scope Don’t define all your components in one big file or all inline – it will be a nightmare to debug and your scope will be all over the place. Make things easy and split each component definition into its own file and extend the base class to add your configuration and extra methods and behavior. This way you can simply instantiate these components where you need them keeping things nice and tidy and loosely coupled. Make sure you use Namespaces Again, it’s all about organization. Utilize the built-‐in namespace capabilities of Sencha Touch to organize your components and classes so it’s easy to navigate later. Typically you would want to do this by functional module, for example, MyApp.Users for all the User management code. I like to mirror this namespace structure with the folder structure so everything is dead easy to find. Use Get/Set methods or Static references Don’t be tempted to delve into a component’s items or toolbar collections to get a reference to a particular button or panel using ‘comp.get(0)’ or comp.getTopToolbar().get(1)’ syntax. If you ever add items to these collections the references will be broken and you will have to track them down. In a big application this becomes a mammoth task, which will introduce bugs. Save yourself some hassle and, in the extended class, create a get method for the necessary components, which delves into the collection, so when you do add more items you know there is only one method to be updated. Or, if you aren’t concerned about lazy instantiation, define your buttons and items as class variables and reference them that way so you won’t need to make any updates when new items are added. Name your xtypes carefully Name your xtypes the same as your class, including namespaces, so you can track down the actual class definition very easily. Additionally, it is recommended to write your xtypes with lowercase letters only. Always have the Docs open The API documentation is your best friend – it should be your first port of call when running into problems or when trying something new. Intellisense for Ext JS isn’t quite up to the standards of Visual Studio for .NET so we can’t get away with being so lazy – the docs are the answer to this. They are well laid out and easy to navigate, so make use of them! Use Plugins and User Extensions If you want a component to do something that is fairly generic and a common functional requirement it is likely that someone has already coded it and released it as a Plugin or an Extension. Take some time before coding it from scratch (unless you have the time – it’s a great way to learn!) to search the forums and the web for a pre-‐made solution (Sencha marketplace).
References • http://www.swarmonline.com/technology/articles-‐and-‐videos/20-‐things-‐to-‐avoiddo-‐when-‐getting-‐started-‐with-‐ext-‐js-‐and-‐sencha-‐touch/ • Sencha Touch -‐ Open-‐Source HTML5 Mobile Web Development Made Easy’ by Stan Bershadskiy
Based on: ‘Sencha Touch -‐ Open-‐Source HTML5 Mobile Web Development Made Easy’ by Stan Bershadskiy
Always have a Utility file It is recommended to always maintain a Utility file in your application. Here we can manage all general information like API url details, function to handle errors, showing alert messages etc. You can make a class with a statics object and put it in a separate “util” folder under the “app” folder. Utility.js
Ext.define('MyApp.utils.Utility', { statics: { BASE_URL: 'http://example.com/API/' } }); Some where in the application
// Use properties and methods as follows var url = MyApp.utils.Utility.BASE_URL console.log(url) // returns "http://example.com/API/"
Maintain all templates inside index.html In almost all the examples and tutorials you will see people add tpl or itemTpl with lots of html tags as strings. It becomes very irritating to debug, change and format because most of us use IDEs and html inside Javascript files. One way to solve this is by adding the templates inside the index.html file like this: Templates inside index.html
<!-‐-‐ Sales Rep TPL Info -‐-‐> <script type="text/template" id="tpl_sales_rep_info"> <div class="black-‐box sales-‐rep-‐details" id="sales_rep_info_block"> <div class="name">{name}</div> <div><a href="tel:{phone}">{phone}</a></div> <div><a href="mailto:{email}">{email}</a></div> </div> </script> <!-‐-‐ Sales Rep TPL Input -‐-‐> <script type="text/template" id="tpl_sales_rep_input"> <div class="contact-‐us"> <div class="black-‐box"> <div class="value"> Enter your zip code </div> </div> <div class="black-‐box"> <div class="label">Zip Code</div> <div class="value"> <input type="text" name="sales_rep_zip" id="sales_rep_zip"/> </div> </div> </div> </script>
We keep all the html fragments inside SCRIPT tag, so these html elements are not added in the DOM and you can access the data simply by accessing innerHTML of the Script tags. This works perfectly fine while creating builds and template codes in Views become easy to maintain. Sample tpl
var touchTeam = Ext.create('Ext.DataView', { store: 'MyStore', itemTpl: document.getElementById('tpl_sales_rep_input').innerHTML }); Recommended debugging chain How you should go about fixing a problem…
1. Check your Code (it’s easy to misspell config options, miss commas etc)
2. Refer to the Documentation (you might be missing a related config option)
3. Step into the Framework’s Source Code (break into the code around the error and try to see what’s going wrong, you’ll likely discover a config option you’ve missed, or realize something you expected to be there isn’t instantiated yet)
4. Search the Forum (it’s almost a guarantee that someone will have had the same problem and posted a question about it)
5. Search the wider WWW (if the forum can’t help the wider web might be able to)
6. Post on the Forum (if you still can’t find the resolution, create a new thread with as much detail about the problem as you can – make it easy for people to help you)
Build and load Widgets on Demand When possible, build and load widgets on demand. Don’t create and load all the widgets upon application launch. Follow a load strategy based on the user’s role in the app so you only load the UI elements that the user will need. For example, you don’t have to load the administration UI of an app if the user is not in the administrators role. Your UI performs better and is more stable when you don’t load the DOM with elements that you will not use. Limit the amount of data rendered in the UI Do not transfer large amounts of data from the server or local storage to the UI, in particular to data-‐bound components such as grids, lists and combo boxes. Large numbers of records take memory. They also slow down data-‐bound widgets’ rendering and performance. Use server-‐side and client-‐side paging and filtering to limit what you render in the app.
References • http://www.innofied.com/sencha-‐touch-‐coding-‐guidelines-‐you-‐should-‐follow-‐part-‐1/ • http://miamicoder.com/2015/sencha-‐touch-‐best-‐practices-‐for-‐user-‐interface-‐development/
Based on: ‘Sencha Touch -‐ Open-‐Source HTML5 Mobile Web Development Made Easy’ by Stan Bershadskiy
Design for Offline Mode and Optimize Access to Local Data Your application should function without having to talk to the server all the time, unless there are very specific requirements to connect frequently. This approach has implications for your UI design. Your data-‐bound widgets should read data cached in local storage, local files or local databases that you refresh as needed when there is a connection with the server. Get only the data needed, cache it locally, and perform fast reads and writes. Avoid Tight Coupling of UI Elements Don’t make a widget be aware or depend on the existence of another widget. For those widgets that react to events triggered by other widgets, use controllers to handle the events. If two widgets are governed by different controllers, don’t let controller A be aware of widget B that’s under controller B. Use controller to controller links via events. With this approach it’s easier to modify parts of the UI without impacting other UI elements or application modules. Don’t Block the UI Don’t make your users wait. Prevent the UI from becoming unresponsive when the app is executing long-‐running operations, such as server calls and local data loading and filtering. Trigger long running operations and use callbacks to be notified upon completion. Use timeouts to limit wait periods. Be mindful of timers and functions that execute on intervals and might block the UI. Avoid complex drawing and animations, they affect UI performance. Well formed code Use tools like JSLint, JSHint, Esprima, etc. to help you detect errors and potential problems in your JavaScript code. These tools also help you structure your JavaScript code to increase readability and maintainability.
References • https://speakerdeck.com/arthurakay/best-‐practices-‐for-‐enterprise-‐javascript-‐applications