ExtJS 4 MVC Architecture Explained

Source: Internet
Author: User
Tags autoload

Large-scale client applications are often poorly implemented and poorly maintained, and because of the increasing functionality and manpower, the scale of these applications is quickly beyond control, and ExtJS 4 brings a new application architecture that not only organizes the code, but also reduces the content of the implementation.
The new application architecture follows an MVC-like pattern in which models (Models) and controllers (Controllers) are introduced for the first time. There are many kinds of MVC architectures in the industry, basically the same, ExtJS 4 is defined as follows:

    • The model model is a collection of fields and their data, such as the User model with username and password fields, the model knows how to persist its own data, and can be associated with other models, which Record are a bit like the classes in ExtJS 3 (the difference is that Recordsimple flat structure, but Model can be nest), usually used Store to show grid and other components of data
    • View View is a component that focuses on interface display-grid, tree, panel are view
    • Controllers controller a place where all the code that makes your app work correctly should be all actions, such as how to render the view, how to initialize the model, and other logic of the app

This tutorial will create a simple example of managing user data, and you'll learn how to use the ExtJS 4 architecture to organize simple applications together.
The application architecture is about providing structure and consistency, about real class and framework code, and adherence to conventions can bring many important benefits:

    • Every app works the same way, so you just need to learn it once
    • It's easy to share your code because all of your app's work patterns are the same
    • You can create your own confusing version for publishing
File Structure Files structure

ExtJS 4 Applications follow a unified directory structure, each of which should be the same. For details, see ExtJS 4 Getting Started, MVC, where all classes are placed in app a directory, this directory can have subdirectories, which represent namespaces (a subdirectory for a namespace), a different directory to store,,, views models controllers stores When we complete the example, the directory structure should be the same as the following:

In this example all files are in the ‘account_manager‘ directory, the ExtJS SDK must be in the directory ext-4.0 , so it index.html should be as follows:

Creating the application in App.js creating an app in App.js

Each ExtJS 4 application starts with an instance of a Application class that contains the application's global configuration (for example, the name of the app), which maintains the maintenance of references to all models, views, controllers, and a launch function that is called after all add-ins have completed loading.
Let's create a simple Account Manager app to manage user accounts. First you need to select a global namespace, and all ExtJS4 applications need to have a global namespace for all classes in the application, in this case we use AM (account Manager)

Ext.application({    requires: ‘Ext.container.Viewport‘,    name: ‘AM‘,    appFolder: ‘app‘,    launch: function() {        Ext.create(‘Ext.container.Viewport‘, {            layout: ‘fit‘,            items: [                {                    xtype: ‘panel‘,                    title: ‘Users‘,                    html : ‘List of users will go here‘                }            ]        });    }});

First we call Ext.application to create an application instance and set the app name "AM", which will automatically create a global variable "AM", and automatically register the namespace "AM" to Ext.Loader , in a similar way also set app as appFolder . In addition launch , in the function, one is created Viewport , containing only one full browser window Panel .

Defining a controller defines a control

The controller is the adhesive for the application, and what they do is listen to the event and perform the action, continue our Account Manager application, and create a controller. Create app/controller/Users.js the file and add the following code:

Ext.define(‘AM.controller.Users‘, {    extend: ‘Ext.app.Controller‘,    init: function() {        console.log(‘Initialized Users! This happens before the Application launch function is called‘);    }});

Next, app.js Add a reference to the Users controller in:

Ext.application({    ...    controllers: [        ‘Users‘    ],    ...});

When we look at the index.html application, the Users controller is automatically loaded (because a app.js reference is added to the application), and Users the method is init launch called before the
initThe method is an excellent place to set up how to interact with the view, usually using Controller a method control that control makes it easier to listen to the events of the view, update the controller, and let it tell us when the panel renders:

Ext.define(‘AM.controller.Users‘, {    extend: ‘Ext.app.Controller‘,    init: function() {        this.control({            ‘viewport > panel‘: {                render: this.onPanelRendered            }        });    },    onPanelRendered: function() {        console.log(‘The panel was rendered‘);    }});

We have updated the init method to use the this.controll listener to set the view. This controll method, using the latest component query engine (componentquery), can quickly and easily find the components on the page. If you are unfamiliar with componentquery, you can review the Componentquery documentation for more information. Briefly, Componentquery allows us to find components in a way similar to CSS selectors.
In the example init method we have applied ‘viewport > panel‘ , which can be interpreted as "finding all panel components in viewport direct descendants", then we provide an object matching event name (only used in this example render ) to provide a response function. The whole effect is that no matter which component conforms to our selector, render our onPanelRendered function is called when its event is triggered.
When we run the application, we can see the following:

It's not the most exciting app, but it shows us how easy it is to start a piece of organized code. Let's add a little bit of content and add a grid. Defining a view defines a viewing

Until now, our application only has very little code, only two files app.js and app/controller/Users.js now we want to add a grid to display all the users in the system, it is time to better organize the logic and start using the view.
The view is also a component, usually a subclass of an existing component of ExtJS, and is now ready to create the user table, create app/view/user/List.js it, add the code:

Ext.define(‘AM.view.user.List‘ ,{    extend: ‘Ext.grid.Panel‘,    alias : ‘widget.userlist‘,    title : ‘All Users‘,    initComponent: function() {        this.store = {            fields: [‘name‘, ‘email‘],            data  : [                {name: ‘Ed‘,    email: ‘[email protected]‘},                {name: ‘Tommy‘, email: ‘[email protected]‘}            ]        };        this.columns = [            {header: ‘Name‘,  dataIndex: ‘name‘,  flex: 1},            {header: ‘Email‘, dataIndex: ‘email‘, flex: 1}        ];        this.callParent(arguments);    }});

Our view class is an ordinary class, in this case we extend the component and Grid set the alias so that we can invoke the component in xtype a way that we have added store and columns the configuration.

Next we need to add this view to the Users controller. Because we use ‘widget.‘ aliases, we can use userlist them as xtype, just as we used before ‘panel‘ .

Ext.define(‘AM.controller.Users‘, {    extend: ‘Ext.app.Controller‘,    views: [        ‘user.List‘    ],    init: ...    onPanelRendered: ...});

Next modify to app.js make the view render in viewport, need to modify the launch method

Ext.application({    ...    launch: function() {        Ext.create(‘Ext.container.Viewport‘, {            layout: ‘fit‘,            items: {                xtype: ‘userlist‘            }        });    }});

The only thing to note is that we specify in the views array ‘user.List‘ , which tells the application to automatically load the corresponding file, and the ExtJS4 dynamic loading system will automatically pull files from the server according to the rules, such as user. List is the rule, replace the./is the file storage path. Refresh the page:

Controlling the Grid control of the list

Note that the onPanelRendered method is still called because our grid still satisfies the ‘viewport > panel‘ selector because our view inherits from the GridPanel

Now we need to tighten the selector, we use xtype as the selector to replace the previous ‘viewport > panel‘ , listen to the double-click event, in order to continue to do the editing user information:

Ext.define(‘AM.controller.Users‘, {    extend: ‘Ext.app.Controller‘,    views: [        ‘user.List‘    ],    init: function() {        this.control({            ‘userlist‘: {                itemdblclick: this.editUser            }        });    },    editUser: function(grid, record) {        console.log(‘Double clicked on ‘ + record.get(‘name‘));    }});

Note that we replaced the component query selector for ‘userlist‘ , listen for the event to change to, the ‘itemdblclick‘ response function is set to ‘editUser‘ , now just simple log out double-click the row's Name property:

You can see that the log is correct, but what we actually want to do is edit the user information, let's do it now, create a new viewapp/view/user/Edit.js

  ext.define (' AM.view.user.Edit ', {extend: ' Ext.window.Window ', alias: ' Widget.useredit ', title: ' Edi                T User ', layout: ' Fit ', Autoshow:true, Initcomponent:function () {this.items = [{                        Xtype: ' Form ', items: [{xtype: ' TextField ',                        Name: ' Name ', Fieldlabel: ' name '}, {                    Xtype: ' TextField ', Name: ' Email ', Fieldlabel: ' Email '        }                ]            }        ];                This.buttons = [{text: ' Save ', Action: ' Save '}, {        Text: ' Cancel ', Scope:this, handler:this.close}];    This.callparent (arguments); }});

This time we still inherit from an existing class Ext.window.Window , or use the initComponent method to specify complex items and buttons objects, we used a ‘fit‘ layout and a form, the form includes the user information to edit the field, finally we created two buttons, one to close the window, The other is used to save changes.
Now all we have to do is load this view in the controller, render and load the user information:

Ext.define(‘AM.controller.Users‘, {    extend: ‘Ext.app.Controller‘,    views: [        ‘user.List‘,        ‘user.Edit‘    ],    init: ...    editUser: function(grid, record) {        var view = Ext.widget(‘useredit‘);        view.down(‘form‘).loadRecord(record);    }});

First we created the view using a method, which is Ext.widget equivalent to Ext.create(‘widget.useredit‘) , and then we find the form in the window with the help of the component query, and each component in the ExtJS4 has a down method that can quickly find any underlying component by querying the supported selectors with the component.
Double-click a row in the table to see:

Creating a Model and a Store

Now that we have the form, we can start editing and saving the user information, but this requires a little refactoring.
AM.view.user.ListCreated an inline so that it Store works but we need to Store separate it so that we can reference and update the information in other places in the application, and we put it in the file it should be in app/store/Users.js :

Ext.define(‘AM.store.Users‘, {    extend: ‘Ext.data.Store‘,    fields: [‘name‘, ‘email‘],    data: [        {name: ‘Ed‘,    email: ‘[email protected]‘},        {name: ‘Tommy‘, email: ‘[email protected]‘}    ]});

Now we need to make two changes, first we need to let the Users initialization load this Store :

Ext.define(‘AM.controller.Users‘, {    extend: ‘Ext.app.Controller‘,    stores: [        ‘Users‘    ],    ...});

Then we're going to change the store that we used to inline in the view, and we'll app/view/user/List.js use the ID to reference the store.

Ext.define(‘AM.view.user.List‘ ,{    extend: ‘Ext.grid.Panel‘,    alias : ‘widget.userlist‘,    //we no longer define the Users store in the `initComponent` method    store: ‘Users‘,    ...});

The introduction of Store,store in the controller's code is automatically loaded into the page and given a StoreID, which makes it easy to use the store in the view (in this case, as long as the configuration store: ‘Users‘ is available)
Now we are just inline in the store defined two fields (' Name ' and ' email '), so it works, but there is a powerful class in ExtJS4, Ext.data.Model we can use it when editing the user, using the model to reconstruct the store, app/model/User.js Create a model in:

Ext.define(‘AM.model.User‘, {    extend: ‘Ext.data.Model‘,    fields: [‘name‘, ‘email‘]});

This is what we need to do to define our model, and now we need to let the store reference model replace the way in which inline fields are used, and let the controller refer to model:

//the Users controller will make sure that the User model is included on the page and available to our appExt.define(‘AM.controller.Users‘, {    extend: ‘Ext.app.Controller‘,    stores: [‘Users‘],    models: [‘User‘],    ...});// we now reference the Model instead of defining fields inlineExt.define(‘AM.store.Users‘, {    extend: ‘Ext.data.Store‘,    model: ‘AM.model.User‘,    data: [        {name: ‘Ed‘,    email: ‘[email protected]‘},        {name: ‘Tommy‘, email: ‘[email protected]‘}    ]});

Our refactoring can make the next work a little bit simpler, but without affecting the existing functionality, we refresh the page and check to see if it works:

Saving data with the model uses models to save

Now we have a user data table, double-click each row can open an edit window, now to do is to save the editing changes, the editing window has an edit form, and the Save button, now we update the controller so that the Save button responds:

Ext.define(‘AM.controller.Users‘, {    init: function() {        this.control({            ‘viewport > userlist‘: {                itemdblclick: this.editUser            },            ‘useredit button[action=save]‘: {                click: this.updateUser            }        });    },    updateUser: function(button) {        console.log(‘clicked the Save button‘);    }});

We this.control added a component query selector to the method, which ‘useredit button[action=save]‘ shows that this selector is the same as the first one, and note that we added a configuration when we defined the Save button. {action: ‘save‘} This selector means that selecting XYTPE is the button for all action properties under the Useredit component that are save
Check to see updateUser if it is called:

The instructions work fine, then populate updateUser the real logic. We need to take the data out of the form and set it back to the store:

updateUser: function(button) {    var win    = button.up(‘window‘),        form   = win.down(‘form‘),        record = form.getRecord(),        values = form.getValues();    record.set(values);    win.close();}

Let's break down what we've done here. Our response function receives a reference to the button, but what we care about is the form and the window, through the buttons and the component query, can find something to care about, here first used to button.up(‘window‘) find the window, and then used to win.down(‘form‘) find the form.
After that we removed the record associated with the form and updated the record with the input values in the form, and finally closed the window focus back to the table, and we changed the user name to ‘Ed Spencer‘ Click Save should be able to see:

Saving to the server

It's simple. Let's increase the interaction with the server side to complete this example. Now we should encode the data for two rows of tables, and now let's load it through Ajax:

Ext.define(‘AM.store.Users‘, {    extend: ‘Ext.data.Store‘,    model: ‘AM.model.User‘,    autoLoad: true,    proxy: {        type: ‘ajax‘,        url: ‘data/users.json‘,        reader: {            type: ‘json‘,            root: ‘users‘,            successProperty: ‘success‘        }    }});

Here we go apart from ‘data‘ attributes, replaced by proxy , proxies are a way to get the store or model to load and save data, with AJAX,JSONP,HTML5 Localstorage local storage, and so on. Here we use a simple Ajax proxy that allows it to load data through a URL ‘data/users.json‘ .
We also attach a reader,reader to the agent to decode the data returned by the server into a format that the store can understand, this time using JSON reader, and specifying the root and successProperty configuration (the detailed configuration of JSON reader to look at the document), Finally we create a data file data/users.json , enter the content:

{    success: true,    users: [        {id: 1, name: ‘Ed‘,    email: ‘[email protected]‘},        {id: 2, name: ‘Tommy‘, email: ‘[email protected]‘}    ]}

The other change is that we set the property for the store autoLoad and set true it to, which means that the store will automatically have the proxy load data, refresh the page should see the same results as before, the difference is now not in the program should be encoded data
The final thing is to return the changes to the server side, this example we use a static JSON file, not using the database, but enough to illustrate our example, first make a little change to tell the proxy for the updated URL:

proxy: {    type: ‘ajax‘,    api: {        read: ‘data/users.json‘,        update: ‘data/updateUsers.json‘    },    reader: {        type: ‘json‘,        root: ‘users‘,        successProperty: ‘success‘    }}

Still reading from the users.json data, but the changes will be sent to updateUsers.json , here we do a mock reply back to the package so that we know that the program can work correctly, updateUsers.json only need to include {"success": true} , the other thing is to let the store after editing to synchronize, need updateUser to Add a line of code to the function:

updateUser: function(button) {    var win    = button.up(‘window‘),        form   = win.down(‘form‘),        record = form.getRecord(),        values = form.getValues();    record.set(values);    win.close();    this.getUsersStore().sync();}

Now we can run through the entire example, check whether each function is normal, edit a row in the table, and see if we can correctly send the request toupdateUser.json

Deployment Release

The new Sencha SDK Tools point This download makes it easy to publish ExtJS4 apps. This tool allows you to generate a dependency manifest and generate a minimized version of the
Details can be viewed ExtJS getting started next Steps next

Here we create a very simple example, but the basic features are included, you can start extrapolate development of other functions, remember to follow the development model, code organization, the above code example in the EXT JS 4 SDK, the examples/app/simple directory

ExtJS 4 MVC Architecture Explained

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.