Contentsjavascript
Large client side applications have always been hard to write, hard to organize and hard to maintain. They tend to quickly grow out of control as you add more functionality and developers to a project. Ext JS 4 comes with a new application architecture that not only organizes your code but reduces the amount you have to write.css
富客戶端應用程序一直很難編寫,維護整理也很難進行。隨着功能的增長和開發者的增多,程序很快變得難以控制。Ext JS 4 擁有一套新的應用結構,可以幫助你有效組織程序,並減小編寫代碼數量。html
Our application architecture follows an MVC-like pattern with Models and Controllers being introduced for the first time. There are many MVC architectures, most of which are slightly different from one another. Here's how we define ours:java
咱們的應用結構首次引用了 MVC 模式。如今市面上存在許多 MVC 構架,彼此或多或少都有一些差異。如今介紹咱們是如何定義 MVC 的:ajax
Model is a collection of fields and their data (e.g. a User model with username and password fields). Models know how to persist themselves through the data package, and can be linked to other models through associations. Models work a lot like the Ext JS 3 Record class, and are normally used with Stores to present data into grids and other components 模型 (Model) 是一個包含了一些字段和字段下數據的集合(例如用戶模型包含了用戶名和密碼字段)。模型瞭解怎樣處理數據包,能和其餘模型創建鏈接。模型的工做模式和 Ext JS 3 下的 Record 類很類似,一般配合 Stores 向網格 (grid) 和其餘組件提供數據。數據庫
View is any type of component - grids, trees and panels are all views.視圖 (View) 任何組件都屬於視圖——網格、樹和麪板都屬於視圖的範疇。json
Controllers are special places to put all of the code that makes your app work - whether that's rendering views, instantiating Models, or any other app logic. 控制器 (Controllers) 控制器是放置全部保持應用正常運行的代碼的地方——渲染視圖、初始化模型或者其餘的邏輯成分。api
In this guide we'll be creating a very simple application that manages User data. By the end you will know how to put simple applications together using the new Ext JS 4 application architecture.數組
在本教程中咱們會建立一個簡單的用戶數據管理系統。教程結束後你會學習到怎樣使用新的 Ext JS 4 應用構架建立應用程序。服務器
The application architecture is as much about providing structure and consistency as it is about actual classes and framework code. Following the conventions unlocks a number of important benefits:
應用程序架構既提供了實際的類和框架代碼,也提供了程序結構和一致性。按照約定編寫代碼有如下幾點好處:
Ext JS 4 applications follow a unified directory structure that is the same for every app. Please check out the Getting Started guide for a detailed explanation on the basic file structure of an application. In MVC layout, all classes are placed into the app/
folder, which in turn contains sub-folders to namespace your models, views, controllers and stores. Here is how the folder structure for the simple example app will look when we're done:
Ext JS 4 應用遵照統一的文件結構。請閱讀 Ext JS 4 手冊中文版 - 開始使用 Ext JS 4 中相關的章節學習有關文件結構的內容。用 MVC 模式開發程序時,全部的類文件應該被放置在 app 文件夾內,app 文件夾內還應包含 models、views、controllers 和 stores 等文件夾。下面是一個文件結構的例子:
In this example, we are encapsulating the whole application inside one folder called 'account_manager
'. Essential files from the Ext JS 4 SDK are wrapped inside ext-4/
folder. Hence the content of our index.html
looks like this:
在這個示例中咱們把整個程序封裝進一個叫 'account_manage' 的文件夾內。Ext JS 4 SDK 自己的文件被放在 ext-4.0 文件夾內。所以 index.html 文件的內容應該相似這樣:
<html> <head> <title>Account Manager</title> <link rel="stylesheet" type="text/css" href="ext-4/resources/css/ext-all.css"> <script type="text/javascript" src="ext-4/ext-debug.js"></script> <script type="text/javascript" src="app.js"></script> </head> <body></body> </html>
Every Ext JS 4 application starts with an instance of Application class. The Application contains global settings for your application (such as the app's name), as well as maintains references to all of the models, views and controllers used by the app. An Application also contains a launch function, which is run automatically when everything is loaded.
每一個 Ext JS 4 應用都從一個Application 類的示例開始。Application 包含了應用的全局設置(好比應用的名字)以及對應用中使用的模型、視圖和控制器的引用。Application 還應包含一個 launch 函數,launch 函數會在全部資源都載入成功後運行。
Let's create a simple Account Manager app that will help us manage User accounts. First we need to pick a global namespace for this application. All Ext JS 4 applications should only use a single global variable, with all of the application's classes nested inside it. Usually we want a short global variable so in this case we're going to use "AM":
如今一塊兒建立一個簡單的帳號管理器用來幫助咱們管理帳號。首先咱們須要爲應用挑選一個全局命名空間。全部的 Ext JS 4 應用程序都應該只使用一個全局變量用來嵌入應用中全部須要的類。一般咱們使用一個簡短的名字,這裏咱們使用「AM」:
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' } ] }); } });
There are a few things going on here. First we invoked Ext.application
to create a new instance of Application class, to which we passed the name'AM'
. This automatically sets up a global variable AM
for us, and registers the namespace to Ext.Loader
, with the corresponding path of 'app
' set via the appFolder
config option. We also provided a simple launch function that just creates a Viewport which contains a single Panel that will fill the screen.
以上代碼,作了以下幾件事。首先,調用Ext.application建立一個應用程序類的實例,設置了一個「AM」的命名空間,他將做爲整個應用的全局變量,也將做爲 Ext.Loader的命名空間,而後經過appFolder來指定配置選項設置相應的路徑。最後,建立了一個簡單的launch函數,這裏僅僅建立了一個Viewport ,其中包含一個Panel,使其充滿整個窗口。
Controllers are the glue that binds an application together. All they really do is listen for events (usually from views) and take some actions. Continuing our Account Manager application, lets create a controller. Create a file called app/controller/Users.js
and add the following code:
控制器是整個應用程序的關鍵,他負責監聽事件,並對某些事件作出相應的動做。如今咱們建立一個控制器,將其命名爲Users.js,其路徑是app/controller/Users.js。而後,咱們爲Users.js添加以下代碼:
1 Ext.define('AM.controller.Users', { 2 extend: 'Ext.app.Controller', 3 4 init: function() { 5 console.log('Initialized Users! This happens before the Application launch function is called'); 6 } 7 });
Now lets add our newly created Users controller to the application config in app.js:
完成以後,咱們將建立好的控制器添加到程序配置文件app.js中
Ext.application({ ... controllers: [ 'Users' ], ... });
When we load our application by visiting index.html
inside a browser, the Users
controller is automatically loaded (because we specified it in the Application definition above), and its init
function is called just before the Application's launch
function.
當咱們訪問index.html時,用戶控制器(Users.js)自動加載(由於咱們在上面的app.js中的定義中指定了)。它的init函數會在Application的launch函數以前調用。
The init
function is a great place to set up how your controller interacts with the view, and is usually used in conjunction with another Controller function -control. The control
function makes it easy to listen to events on your view classes and take some action with a handler function. Let's update ourUsers
controller to tell us when the panel is rendered:
Init函數裏很是適合設置控制器與視圖的交互,它一般和另外一個控制器函數的配合使用 -control。control函數使得監聽視圖類的事件處理函數並執行一些處理函數的動做變得很容易。讓咱們更新咱們的用戶控制器,在呈現面板時通知咱們:
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've updated the init
function to use this.control
to set up listeners on views in our application. The control
function uses the new ComponentQuery engine to quickly and easily get references to components on the page. If you are not familiar with ComponentQuery yet, be sure to check out the ComponentQuery documentation for a full explanation. In brief though, it allows us to pass a CSS-like selector that will find every matching component on the page.
咱們已經更新了init函數使用this.control設置咱們應用程序的視圖上的監聽器。Control函數使用新的ComponentQuery引擎,快速、方便地獲取頁面上的組件引用。若是您還不熟悉ComponentQuery,必定要看 ComponentQuery documentation文檔,那篇解釋的更加全面。簡而言之,它使咱們可以經過一個相似CSS的選擇器找到頁面上的每個匹配組件。
In our init function above we supplied 'viewport > panel'
, which translates to "find me every Panel that is a direct child of a Viewport". We then supplied an object that maps event names (just render
in this case) to handler functions. The overall effect is that whenever any component that matches our selector fires a render
event, our onPanelRendered
function is called.
在咱們上面的init函數中的「viewport > panel」,至關於「找到每個是Viewport直接子節點的Panel」。而後,咱們提供了一個對象,映射事件的名稱(這個例子中是render )處處理函數。總體效果是,每當咱們的選擇匹配到任何組件時,就觸發render事件,並調用onPanelRendered函數。
When we run our application now we see the following:
運行應用程序,效果以下:
Not exactly the most exciting application ever, but it shows how easy it is to get started with organized code. Let's flesh the app out a little now by adding a grid.
雖然不徹底是有史以來最使人興奮的應用程序,但它開始顯示出它組織代碼是多麼的容易。讓咱們再爲程序加入Grid。
Until now our application has only been a few lines long and only inhabits two files - app.js
and app/controller/Users.js
. Now that we want to add a grid showing all of the users in our system, it's time to organize our logic a little better and start using views.
到如今爲止,咱們的應用程序只有幾行,只有兩個文件- app.js 和app/controller/Users.js。如今咱們要添加一個Grid,顯示在咱們的系統中的全部用戶,如今是把咱們的邏輯組織的好一點並開始使用View(視圖)的時間了。
A View is nothing more than a Component, usually defined as a subclass of an Ext JS component. We're going to create our Users grid now by creating a new file called app/view/user/List.js
and putting the following into it:
視圖就是一個組件(Component),一般會定義爲Ext JS組件的一個子類。咱們將經過建立一個新文件app/view/user/List.js建立用戶grid ,下面是代碼:
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: 'ed@sencha.com'}, {name: 'Tommy', email: 'tommy@sencha.com'} ] }; this.columns = [ {header: 'Name', dataIndex: 'name', flex: 1}, {header: 'Email', dataIndex: 'email', flex: 1} ]; this.callParent(arguments); } });
Our View class is nothing more than a normal class. In this case we happen to extend the Grid Component and set up an alias so that we can use it as an xtype (more on that in a moment). We also passed in the store configuration and the columns that the grid should render.
咱們的View類是隻是一個普通的類。在這種狀況下,咱們擴展了Grid組件,並設置一個別名,使咱們可使用它做爲一個的xtype(在某一時刻)。咱們還配置了store和grid應該添加的columns。
Next we need to add this view to our Users
controller. Because we set an alias using the special 'widget.'
format, we can use 'userlist' as an xtype now, just like we had used 'panel'
previously.
下一步,咱們須要添加這個view到咱們的Users controller上。由於咱們設置的別名使用了特殊的「widget」格式,咱們如今可使用「userlist」做爲xtype,就像咱們之前曾使用「panel」做爲xtype同樣。
Ext.define('AM.controller.Users', { extend: 'Ext.app.Controller', views: [ 'user.List' ], init: ... onPanelRendered: ... });
And then render it inside the main viewport by modifying the launch method in app.js
to:
而且把它附加到主Viewport上,須要修改app.js的launch方法:
Ext.application({ ... launch: function() { Ext.create('Ext.container.Viewport', { layout: 'fit', items: { xtype: 'userlist' } }); } });
The only other thing to note here is that we specified 'user.List'
inside the views array. This tells the application to load that file automatically so that we can use it when we launch. The application uses Ext JS 4's new dynamic loading system to automatically pull this file from the server. Here's what we see when we refresh the page now:
其餘惟一要注意的是,咱們在View數組內指定「user.List」。這告訴應用程序自動加載該文件,因此當咱們啓動程序的時候就能夠用它。該應用程序使用Ext JS4的新動態加載系統自動從服務器獲取這個文件。下面是咱們所看到的,當咱們如今刷新頁面的:
Note that our onPanelRendered
function is still being called. This is because our grid class still matches the 'viewport > panel'
selector. The reason for this is that our class extends Grid, which in turn extends Panel.
請注意,咱們onPanelRendered函數仍然是被調用。這是由於咱們的grid類仍然匹配「viewport > panel」選擇器。這是由於咱們的類繼承自Grid,Grid又繼承自Panel。
At the moment, the listeners we add to this selector will actually be called for every Panel or Panel subclass that is a direct child of the viewport, so let's tighten that up a bit using our new xtype. While we're at it, let's instead listen for double clicks on rows in the grid so that we can later edit that User:
目前,咱們添加到這個選擇器上的listeners,實際上被每個是viewport 直接孩子的Panel或Panel的子類調用,所以,讓咱們用新的xtype給它收緊(不要匹配的這麼寬泛)。雖然咱們在它的時候,讓咱們把監聽事件換成雙擊grid中行的事件,使咱們能夠在之後編輯該用戶:
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 changed the ComponentQuery selector (to simply 'userlist'
), the event name (to 'itemdblclick'
) and the handler function name (to'editUser'
). For now we're just logging out the name of the User we double clicked:
請注意,咱們改變了ComponentQuery選擇器(「userlist」),事件的名稱(「itemdblclick」)和處理函數名稱(「editUser」)。如今咱們只是記錄了咱們雙擊的用戶名稱:
Logging to the console is all well and good but we really want to edit our Users. Let's do that now, starting with a new view in app/view/user/Edit.js
:
記錄到控制檯,一切都很好,但咱們真的要編輯咱們的用戶。讓咱們作,就如今,建一個新的視圖app/view/user/Edit.js:
Ext.define('AM.view.user.Edit', { extend: 'Ext.window.Window', alias: 'widget.useredit', title: 'Edit 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); } });
Again we're just defining a subclass of an existing component - this time Ext.window.Window
. Once more we used initComponent
to specify the complex objects items
and buttons
. We used a 'fit'
layout and a form as the single item, which contains fields to edit the name and the email address. Finally we created two buttons, one which just closes the window, and the other that will be used to save our changes.
一樣,咱們只是定義一個現有組件的子類 - 這一次繼承Ext.window.Window。咱們再次用initComponent指定複雜的對象項和按鈕。咱們使用「fit」佈局,並添加一個form做爲單項,其中包含的字段編輯的名稱和電子郵件地址。最後,咱們建立了兩個按鈕,一個是關閉窗口,另外一個是保存修改。 如今咱們要作的是添加視圖控制器,使其裝入用戶:
All we have to do now is add the view to the controller, render it and load the User into it:
如今咱們要作的是添加視圖到控制器中,附加到界面並使其加載用戶:
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 the convenient method Ext.widget
, which is equivalent to Ext.create('widget.useredit')
. Then we leveraged ComponentQuery once more to quickly get a reference to the edit window's form. Every component in Ext JS 4 has a down
function, which accepts a ComponentQuery selector to quickly find any child component.
首先,咱們建立的視圖使用了一個很方便的方法Ext.widget,這至關於Ext.create('widget.useredit’)。而後咱們利用ComponentQuery再次快速獲取到編輯窗口Form的引用。在Ext JS4的每一個組件有一個down()函數,它接受一個ComponentQuery選擇器,能夠快速找到任何子組件。
Double clicking a row in our grid now yields something like this:
在咱們的Grid上雙擊行,結果看起來像這樣:
Now that we have our edit form it's almost time to start editing our users and saving those changes. Before we do that though, we should refactor our code a little.
如今,咱們有了咱們的edit Form,差很少能夠開始編輯咱們的用戶並保存這些改變了。雖然在這樣作以前,咱們應該重構咱們的代碼一點點。
At the moment the AM.view.user.List
component creates a Store inline. This works well but we'd like to be able to reference that Store elsewhere in the application so that we can update the data in it. We'll start by breaking the Store out into its own file - app/store/Users.js
:
如今AM.view.user.List用內聯方式建立了一個Store,它工做的很好,可是咱們但願可以更新數據。首先,咱們將Store放到單獨的文件中- app/store/Users.js
:
Ext.define('AM.store.Users', { extend: 'Ext.data.Store', fields: ['name', 'email'], data: [ {name: 'Ed', email: 'ed@sencha.com'}, {name: 'Tommy', email: 'tommy@sencha.com'} ] });
Now we'll just make 2 small changes - first we'll ask our Users
controller to include this Store when it loads:
如今,咱們只是作兩個小變化 - 首先,咱們將要求用戶控制器加載時包括此Store:
Ext.define('AM.controller.Users', { extend: 'Ext.app.Controller', stores: [ 'Users' ], ... });
then we'll update app/view/user/List.js
to simply reference the Store by id:
而後咱們更新 app/view/user/List.js簡單的用id來引用這個Store
Ext.define('AM.view.user.List' ,{ extend: 'Ext.grid.Panel', alias: 'widget.userlist', title: 'All Users', // we no longer define the Users store in the `initComponent` method store: 'Users', initComponent: function() { this.columns = [ ... });
By including the stores that our Users
controller cares about in its definition they are automatically loaded onto the page and given a storeId, which makes them really easy to reference in our views (by simply configuring store: 'Users'
in this case).
包括Store在內,咱們的用戶控制器關心在其定義中他們會自動加載到頁面上,並給予的StoreID,這使得它們很容易引用咱們的View(經過簡單的配置store:這裏是「user」)。
At the moment we've just defined our fields ('name'
and 'email'
) inline on the store. This works well enough but in Ext JS 4 we have a powerfulExt.data.Model
class that we'd like to take advantage of when it comes to editing our Users. We'll finish this section by refactoring our Store to use a Model, which we'll put in app/model/User.js
:
目前,咱們剛剛在Store裏定義了咱們的字段(「name」和「email」)。這已經足夠了,但在Ext JS4咱們有一個強大的Ext.data.Model的類,咱們想利用它的優點來編輯咱們的Users。在本節裏咱們將重構咱們的Store來使用Model,使用文件app/model/User.js:
Ext.define('AM.model.User', { extend: 'Ext.data.Model', fields: ['name', 'email'] });
That's all we need to do to define our Model. Now we'll just update our Store to reference the Model name instead of providing fields inline...
這就是定義咱們的模型所須要作的所有工做,如今咱們只須要更新Store來引用模型名稱來代替內聯,並讓 Users controller也獲取一個模型:
Ext.define('AM.store.Users', { extend: 'Ext.data.Store', model: 'AM.model.User', data: [ {name: 'Ed', email: 'ed@sencha.com'}, {name: 'Tommy', email: 'tommy@sencha.com'} ] });
And we'll ask the Users
controller to get a reference to the User
model too:
Ext.define('AM.controller.Users', { extend: 'Ext.app.Controller', stores: ['Users'], models: ['User'], ... });
Our refactoring will make the next section easier but should not have affected the application's current behavior. If we reload the page now and double click on a row we see that the edit User window still appears as expected. Now it's time to finish the editing functionality:
咱們的重構會讓下一節變得很容易,但卻不會影響應用程序的當前行爲。若是咱們如今刷新頁面,雙擊一個行,咱們會看到「edit User」窗口仍然和預期顯示同樣。如今來完成編輯功能:
Now that we have our users grid loading data and opening an edit window when we double click each row, we'd like to save the changes that the user makes. The Edit User window that the defined above contains a form (with fields for name and email), and a save button. First let's update our controller's init function to listen for clicks to that save button:
如今,咱們讓咱們的users grid加載數據並當咱們雙擊每一行打開一個編輯窗口。如今咱們想要保存修改。Edit User窗口定義了一個表單(包含name和email字段)和保存按鈕。首先,讓咱們更新控制器的init函數來監聽保存按鈕的點擊:
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 added a second ComponentQuery selector to our this.control
call - this time 'useredit button[action=save]'
. This works the same way as the first selector - it uses the 'useredit'
xtype that we defined above to focus in on our edit user window, and then looks for any buttons with the'save'
action inside that window. When we defined our edit user window we passed {action: 'save'}
to the save button, which gives us an easy way to target that button.
咱們在this.control調用裏增長了第二個ComponentQuery選擇器- 這一次是「useredit button[action=save]」。它第一個選擇器以一樣的方式工做 - 它使用咱們上面定義的「useredit」xtype來查找到編輯用戶窗口,而後查找該窗口內的「保存」行爲按鈕。當咱們定義咱們的編輯用戶窗口的時候,咱們把 {action: 'save'} 定義到保存按鈕,這給了咱們一個簡單的方法鎖定目標按鈕。
We can satisfy ourselves that the updateUser
function is called when we click the Save button:
當咱們點擊「保存」按鈕時,updateUser函數被調用,:
Now that we've seen our handler is correctly attached to the Save button's click event, let's fill in the real logic for the updateUser
function. In this function we need to get the data out of the form, update our User with it and then save that back to the Users store we created above. Let's see how we might do that:
如今,咱們已經看到應用正確地處理了鏈接到保存按鈕的Click事件。讓咱們填寫updateUser函數的真正的邏輯。在這個函數中,咱們須要獲取Form的數據,更新咱們的用戶,而後保存,存儲回給咱們上面建立的Users 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's going on here. Our click event gave us a reference to the button that the user clicked on, but what we really want is access to the form that contains the data and the window itself. To get things working quickly we'll just use ComponentQuery again here, first usingbutton.up('window')
to get a reference to the Edit User window, then win.down('form')
to get the form.
讓咱們說說這裏發生了什麼事情。咱們的點擊事件給了咱們一個用戶點擊的按鈕的引用,但咱們真正想要訪問的是包含數據的form和窗口自己,。咱們再次使用ComponentQuery,第一次使用button.up('window') ,以得到編輯用戶窗口的引用,而後win.down('form')獲得form。
After that we simply fetch the record that's currently loaded into the form and update it with whatever the user has typed into the form. Finally we close the window to bring attention back to the grid. Here's what we see when we run our app again, change the name field to 'Ed Spencer'
and click save:
以後,咱們只需獲取當前form加載的記錄而且更新它。最後,咱們關閉該窗口,把注意力轉移到grid。在這裏咱們看到,咱們運行了咱們的應用程序,更改name字段爲「Ed Spencer」,並點擊保存:
Easy enough. Let's finish this up now by making it interact with our server side. At the moment we are hard coding the two User records into the Users Store, so let's start by reading those over AJAX instead:
這很容易作到。咱們如今要得它與咱們的服務器端進行交互。目前,咱們是把兩個用戶記錄硬編碼到Users Store中,讓咱們開始看些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 removed the 'data'
property and replaced it with a Proxy. Proxies are the way to load and save data from a Store or a Model in Ext JS 4. There are proxies for AJAX, JSON-P and HTML5 localStorage among others. Here we've used a simple AJAX proxy, which we've told to load data from the url'data/users.json'
.
在這裏,咱們刪除'data '屬性,並用一個 Proxy取代它。Proxies(代理)是Ext JS4用來從Store或Model加載和保存數據的方式。有AJAX、JSON- P、HTML5本機存儲和其餘方式的代理。這裏咱們使用一個簡單的AJAX代理,從URL「data/users.json」加載數據。
We also attached a Reader to the Proxy. The reader is responsible for decoding the server response into a format the Store can understand. This time we used a JSON Reader, and specified the root and successProperty
configurations. Finally we'll create our data/users.json
file and paste our previous data into it:
咱們還把reader附加到代理上。reader負責把服務器響應的數據解碼成Store能夠理解的格式。此次咱們使用了JSONreader,並指定根和successProperty配置(參看 Json Reader文檔)。最後,咱們將創建data/users.json 文件,把以前的數據粘貼進去:
{ "success": true, "users": [ {"id": 1, "name": 'Ed', "email": "ed@sencha.com"}, {"id": 2, "name": 'Tommy', "email": "tommy@sencha.com"} ] }
The only other change we made to the Store was to set autoLoad
to true
, which means the Store will ask its Proxy to load that data immediately. If we refresh the page now we'll see the same outcome as before, except that we're now no longer hard coding the data into our application.
惟一的變化是Store的autoLoad 被設置爲true,這意味着商店將要求其Proxy當即加載數據。若是咱們如今刷新頁面,咱們會看到像之前相同的結果,除了咱們如今再也不是硬編碼應用程序的數據了。
The last thing we want to do here is send our changes back to the server. For this example we're just using static JSON files on the server side so we won't see any database changes but we can at least verify that everything is plugged together correctly. First we'll make a small change to our new proxy to tell it to send updates back to a different url:
咱們要在這裏作的最後一件事是把咱們的修改發送回服務器。對於這個例子,咱們只是在服務器端使用靜態的JSON文件,因此咱們不會看到任何數據庫更改,但咱們至少能夠確認一切是正確的放到了一塊兒。首先,咱們將作一個小變化,告訴咱們新的proxy更新要發送到一個不一樣的URL:
proxy: { type: 'ajax', api: { read: 'data/users.json', update: 'data/updateUsers.json' }, reader: { type: 'json', root: 'users', successProperty: 'success' } }
We're still reading the data from users.json
but any updates will be sent to updateUsers.json
. This is just so we know things are working without overwriting our test data. After updating a record, the updateUsers.json
file just contains {"success": true}
. Since it is updated through a HTTP POST command, you may have to create an empty file to avoid receiving a 404 error.
The only other change we need to make is to tell our Store to synchronize itself after editing, which we do by adding one more line inside the updateUser function, which now looks like this:
咱們仍是從users.json讀取數據,任何更新都會發送到updateUsers.json。這樣咱們就能夠返回一個虛擬的迴應,讓咱們知道程序工做正常。updateUsers.json文件只包含{"success": true}。咱們須要作的惟一改變是要告訴Store編輯後同步本身,因而在updateUser函數裏再加一行,如今看起來像這樣:
updateUser: function(button) { var win = button.up('window'), form = win.down('form'), record = form.getRecord(), values = form.getValues(); record.set(values); win.close(); // synchronize the store after editing the record this.getUsersStore().sync(); }
Now we can run through our full example and make sure that everything works. We'll edit a row, hit the Save button and see that the request is correctly sent to updateUser.json
如今,咱們就能夠運行咱們完整的例子,並確保一切正常。咱們將編輯一行,點擊「保存」按鈕,看到請求正確發送到updateUser.json
The newly introduced Sencha SDK Tools (download here) makes deployment of any Ext JS 4 application easier than ever. The tools allows you to generate a manifest of all dependencies in the form of a JSB3 (JSBuilder file format) file, and create a minimal custom build of just what your application needs within minutes.
新推出的Sencha SDK工具(下載)使得任何Ext JS4應用程序的部署比以往任什麼時候候都更容易。這些工具容許您生成一個JSB3(JSBuilder文件格式)文件格式的全部依賴關係的清單,並只須要在幾分鐘以內就建立一個最小自定義的應用程序構建。
Please refer to the Getting Started guide for detailed instructions.
請參閱入門指南詳細說明(Getting Started guide)。
We've created a very simple application that manages User data and sends any updates back to the server. We started out simple and gradually refactored our code to make it cleaner and more organized. At this point it's easy to add more functionality to our application without creating spaghetti code. The full source code for this application can be found in the Ext JS 4 SDK download, inside the examples/app/simple folder.
咱們已經建立了一個很是簡單的應用程序,管理用戶數據和並把任何更新發送回服務器。咱們從簡單的代碼開始,逐步重構,使其更清潔,更優雅。在這之上上,很容易添加更多的功能,而無需爲咱們的應用程序建立意大利麪條式的代碼。該應用程序的完整的源代碼能夠到Ext JS4 SDK下載,在examples/app/simple文件夾中。