Many of the readers of this tutorial on how to build a Sencha Touch Application have requested a version of the Notes Application that shows how to create components using the config object, instead of the initialize function. In this chapter of the tutorial, we are going to do just that.
很多此系列教程的读者都在要求一个使用config创建视图控件的版本,而不是我们在前几节使用的在initailize()函数中添加控件。所以在这一章我们只是修改我们的应用,使用config来创建控件,仅此而已。
Using Sencha Touch’s Config Object to Create the Notes List(使用ST的config对象创建list)
The first step we are going to take is consolidate the Notes List Container View and Notes List View into a single View, which we will call Notes List View. This View has the same components that used to exist in the former Views:
第一步我们把NoteListContainer类和NotesList类合并为一个类:NotesList。这个视图包含的控件和前面的版本一样:
In the application’s view directory, we are going to delete the old NotesListContainer.js file, and leave only the NotesList.js and NoteEditor.js files:
修改之后的view目录是这样的:
Next, we are going to remove the existing code from the NotesList.js file, and define the NotesList class like so:
接下来我们这样定义NotesList类:
Ext.define("NotesApp.view.NotesList", { extend: "Ext.Container", requires:"Ext.dataview.List", alias: "widget.noteslistview", config: { layout: { type: 'fit' }, items: [{ xtype: "toolbar", title: "My Notes", docked: "top", items: [ { xtype: 'spacer' }, { xtype: "button", text: 'New', ui: 'action', itemId: "newButton" } ] }, { xtype: "list", store: "Notes", itemId:"notesList", loadingText: "Loading Notes...", emptyText: '<div class="notes-list-empty-text">No notes found.</div>', onItemDisclosure: true, grouped: true, itemTpl: '<div class="list-item-title">{title}</div><div class="list-item-narrative">{narrative}</div>' }], listeners: [{ delegate: "#newButton", event: "tap", fn: "onNewButtonTap" }, { delegate: "#notesList", event: "disclose", fn: "onNotesListDisclose" }] }, onNewButtonTap: function () { console.log("newNoteCommand"); this.fireEvent("newNoteCommand", this); }, onNotesListDisclose: function (list, record, target, index, evt, options) { console.log("editNoteCommand"); this.fireEvent('editNoteCommand', this, record); } });
If you are already familiar with the previous version of this View, you will notice that although the onNewButtonTap and onNotesListDisclose functions remain unchanged, we are now taking advantage of the config object to define the View’s items, and the event listeners needed for the New button and the disclose buttons of the notes List.
如果你已经对前面的版本很熟悉的话,你会看到虽然onNewButtonTap()和onNoteListDisclose()函数没做改变,但是我们却是用了config对象来配置视图的控件和事件。
Defining Event Listeners with Sencha Touch Config Objects(使用ST的config对象定义事件监听器)
The New button’s tap listener is pretty straightforward(坦率,直接,简单). Its delegate(代表) config is the value of the itemId config of the button. The fn config is a pointer to the onNewButtonTap function:
newButton的监听器很简单。他的delegate配置是按钮的id,然后fn配置指定事件处理函数。
{ delegate: "#newButton", event: "tap", fn: "onNewButtonTap" }
We defined the List’s disclose handler in a similar fashion. The delegate points to the List’s itemId, and fn is the onNotesListDisclose function:
我们使用相同的风格来定义list的disclose监听器。
{ delegate: "#notesList", event: "disclose", fn: "onNotesListDisclose" }
Configuring the Note Editor(配置noteEditor)
Now we are going to move on to the NoteEditor View, where we will replace the initialize function with the config’s items and listeners properties:
我们到NoteEditor视图中我们将会用config对象来替换初始化函数中的代码:
Ext.define("NotesApp.view.NoteEditor", { extend: "Ext.form.Panel", requires: "Ext.form.FieldSet", alias: "widget.noteeditorview", config: { scrollable: 'vertical', items: [ { xtype: "toolbar", docked: "top", title: "Edit Note", items: [ { xtype: "button", ui: "back", text: "Home", itemId: "backButton" }, { xtype: "spacer" }, { xtype: "button", ui: "action", text: "Save", itemId: "saveButton" } ] }, { xtype: "toolbar", docked: "bottom", items: [ { xtype: "button", iconCls: "trash", iconMask: true, itemId: "deleteButton" } ] }, { xtype: "fieldset", items: [ { xtype: 'textfield', name: 'title', label: 'Title', required: true }, { xtype: 'textareafield', name: 'narrative', label: 'Narrative' } ] } ], listeners: [ { delegate: "#backButton", event: "tap", fn: "onBackButtonTap" }, { delegate: "#saveButton", event: "tap", fn: "onSaveButtonTap" }, { delegate: "#deleteButton", event: "tap", fn: "onDeleteButtonTap" } ] }, onSaveButtonTap: function () { console.log("saveNoteCommand"); this.fireEvent("saveNoteCommand", this); }, onDeleteButtonTap: function () { console.log("deleteNoteCommand"); this.fireEvent("deleteNoteCommand", this); }, onBackButtonTap: function () { console.log("backToHomeCommand"); this.fireEvent("backToHomeCommand", this); } });
We are following the same approach we used to configure the NotesList View. This time, we need listeners for the Back, Save and Delete buttons:
遵循在NoteList视图中的配置方法,为back,save,delete按钮配置监听器:
listeners: [ { delegate: "#backButton", event: "tap", fn: "onBackButtonTap" }, { delegate: "#saveButton", event: "tap", fn: "onSaveButtonTap" }, { delegate: "#deleteButton", event: "tap", fn: "onDeleteButtonTap" } ]
The onBackButtonTap, onSaveButtonTap, and onDeleteButtonTap function remain unchanged.
The onBackButtonTap, onSaveButtonTap, and onDeleteButtonTap函数都没有变化。
Adding View Instances to the Application(给应用添加视图引用)
In the app.js file, we are going to instantiate both Views as follows:
在app.js文件中,我们这样实例化两个视图:
Ext.application({ name: "NotesApp", models: ["Note"], stores: ["Notes"], controllers: ["Notes"], views: ["NotesList", "NoteEditor"], launch: function () { var notesListView = { xtype: "noteslistview" }; var noteEditorView = { xtype: "noteeditorview" }; Ext.Viewport.add([notesListView, noteEditorView]); } });
Modifying the Controller(修改控制器)
The Controller remains unchanged, with the exception of the Views aliases, which we have changed in the chapter of the tutorial:
由于视图类没有
Ext.define("NotesApp.controller.Notes", { extend: "Ext.app.Controller", config: { refs: { // We're going to lookup our views by alias. notesListView: "noteslistview", noteEditorView: "noteeditorview", notesList: "#notesList" }, control: { notesListView: { // The commands fired by the notes list container. newNoteCommand: "onNewNoteCommand", editNoteCommand: "onEditNoteCommand" }, noteEditorView: { // The commands fired by the note editor. saveNoteCommand: "onSaveNoteCommand", deleteNoteCommand: "onDeleteNoteCommand", backToHomeCommand: "onBackToHomeCommand" } } }, // Transitions slideLeftTransition: { type: 'slide', direction: 'left' }, slideRightTransition: { type: 'slide', direction: 'right' }, // Helper functions getRandomInt: function (min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; }, activateNoteEditor: function (record) { var noteEditorView = this.getNoteEditorView(); noteEditorView.setRecord(record); // load() is deprecated. Ext.Viewport.animateActiveItem(noteEditorView, this.slideLeftTransition); }, activateNotesList: function () { Ext.Viewport.animateActiveItem(this.getNotesListView(), this.slideRightTransition); }, // Commands. onNewNoteCommand: function () { console.log("onNewNoteCommand"); var now = new Date(); var noteId = (now.getTime()).toString() + (this.getRandomInt(0, 100)).toString(); var newNote = Ext.create("NotesApp.model.Note", { id: noteId, dateCreated: now, title: "", narrative: "" }); this.activateNoteEditor(newNote); }, onEditNoteCommand: function (list, record) { console.log("onEditNoteCommand"); this.activateNoteEditor(record); }, onSaveNoteCommand: function () { console.log("onSaveNoteCommand"); var noteEditorView = this.getNoteEditorView(); var currentNote = noteEditorView.getRecord(); var newValues = noteEditorView.getValues(); // Update the current note's fields with form values. currentNote.set("title", newValues.title); currentNote.set("narrative", newValues.narrative); var errors = currentNote.validate(); if (!errors.isValid()) { Ext.Msg.alert('Wait!', errors.getByField("title")[0].getMessage(), Ext.emptyFn); currentNote.reject(); return; } var notesStore = Ext.getStore("Notes"); if (null == notesStore.findRecord('id', currentNote.data.id)) { notesStore.add(currentNote); } notesStore.sync(); notesStore.sort([{ property: 'dateCreated', direction: 'DESC'}]); this.activateNotesList(); }, onDeleteNoteCommand: function () { console.log("onDeleteNoteCommand"); var noteEditorView = this.getNoteEditorView(); var currentNote = noteEditorView.getRecord(); var notesStore = Ext.getStore("Notes"); notesStore.remove(currentNote); notesStore.sync(); this.activateNotesList(); }, onBackToHomeCommand: function () { console.log("onBackToHomeCommand"); this.activateNotesList(); }, // Base Class functions. launch: function () { this.callParent(arguments); var notesStore = Ext.getStore("Notes"); notesStore.load(); console.log("launch"); }, init: function () { this.callParent(arguments); console.log("init"); } });
Summary
We just created a version of the Notes Application where, instead of the initialize function, we exclusively(仅仅) used config objects to configure each of the application’s Views. In the process(在此过程中), we learned how to create event listeners for components defined using config objects.
At this point, we have accomplished our goals for this application. I hope the insights(见解) you gained in this Sencha Touch tutorial will help you create great mobile applications.
这里我们只是创建了一个使用config对象配置视图的版本。我们仅仅使用config配置应用的视图,在这个过程中我们学习了怎么使用config对象为控件创建事件监听。
到此为止我们已经能实现了我们的目标,希望这个教程能给你一些灵感,让你创造出更加好的移动应用!
Downloads
Download the source code for this article: NotesApp-ST2-Part5.zip
The Entire Series
§ How to Create a Sencha Touch 2 App, Part 1
§ How to Create a Sencha Touch 2 App, Part 2
§ How to Create a Sencha Touch 2 App, Part 3
§ How to Create a Sencha Touch 2 App, Part 4
§ How to Create a Sencha Touch 2 App, Part 5
§
Want To Learn More?
My Sencha Touch books will teach you how to create an application from scratch.
§ Sencha Touch 2 Book
§ Sencha Touch 1 Book
What Sencha Touch Topics Would You Like Me To Write About?
I’d like to help you learn Sencha Touch better and faster, but I need you to let me know what subjects you are curious about, or what topics you are struggling with.
Please send me your questions or suggestions for future posts at miamicoder[AT]gmail.com.
TAGGED WITH: SENCHA TOUCH TUTORIAL 58 COMMENTS
About Jorge
Jorge is the author of Building a Sencha Touch Application, How to Build a jQuery Mobile Application, and the Ext JS 3.0 Cookbook. He runs a software development and developer education shop that focuses on mobile, web and desktop technologies.
If you'd like to work with Jorge, contact him at ramonj[AT]miamicoder.com.