2013년 10월 17일 목요일

Creating a real-life application with the MVC pattern



1. Our first step is to create our app.js file, which will provide our application's
launch point. We create this file in the root of our application alongside our
index.html. At this stage we will give our application the name BugTracker
and an empty launch function:
Ext.application({
name: 'BugTracker',
launch: function(){
console.log('App Launch');
}
});

2. Next we will define our bug model and store. These will be placed in two files named
Bug.js in the model folder and BugStore.js in the store folder respectively. The
contents of each can be seen as follows:
// model/Bug.js
Ext.define('BugTracker.model.Bug', {
extend: 'Ext.data.Model',
fields: [
'title',
'status',
'description',
'severity'
]
});
// store/BugStore.js
Ext.define('BugTracker.store.BugStore', {
extend: 'Ext.data.Store',
model: 'BugTracker.model.Bug',
data: [ ... ]
});

3. We have created our main model and store, now we want to make the application
aware of them so the framework loads them when required. We do this by adding
stores and models configs to the Ext.application call of app.js. These
configs accept an array of strings that are then fully qualified with the relevant
namespace (for example, MyModel becomes BugTracker.model.MyModel).
Ext.application({
name: 'BugTracker',
models: [
'Bug'
],
stores: [
'BugStore'
],
launch: function(){
console.log('App Launch');
}
});

4. Our next step is to create our views. In our application we have a DataView that
displays our set of bugs, a panel to wrap the DataView, a Form panel to allow us to
edit a bug, a window to house the Form panel when it is displayed, and a Viewport
container. We are going to create each of these views as their own class, extending
the relevant framework class, starting with our BugDataView:
// view/BugDataView.js
Ext.define('BugTracker.view.BugDataView', {
extend: 'Ext.view.View',
alias: 'widget.BugDataView',
config: {
store: Ext.create('BugTracker.store.BugStore'),
tpl: '' +
'
' +

'{title}' +
'{severity}</
span>' +
'{description}' +
'{status}' +
'
' +'
',itemSelector: 'div.bug-wrapper',
emptyText: 'Woo hoo! No Bugs Found!',
deferEmptyText: false
}
});

5. Next we create the BugPanel that will have an instance of the BugDataView within
it. Notice the new action config we have given to each of the toolbar buttons; we will
use these later on to hook up their click events:
// view/BugPanel.js
Ext.define('BugTracker.view.BugPanel', {
extend: 'Ext.panel.Panel',
alias: 'widget.BugPanel',
config: {
title: 'Current Bugs,
height: 500,
width: 580,
layout: 'fit',
style: 'margin: 50;',
tbar: [{
xtype: 'combo',
name: 'status',
width: 200,
labelWidth: 100,
fieldLabel: 'Severity Filter',
store: ['1', '2', '3', '4', '5'],
queryMode: 'local'
}, '-', {
text: 'Sort by Severity',
action: 'sortBySeverity'
}, {
text: 'Open all Bugs',
action: 'openAllBugs'
}, '->', {
text: 'Clear Filter',
action: 'clearFilter'
}],
items: [{
xtype: 'BugDataView'
}]
}
});

6. The Bug form panel is next and we follow the same pattern as the other views and
create it in its own file whose name matches the class name that it contains:
// view/BugForm.js
Ext.define('BugTracker.view.BugForm', {
extend: 'Ext.form.Panel',
alias: 'widget.BugForm',
config: {
border: 0,
items: [{
xtype: 'textfield',
name: 'title',
width: 300,
fieldLabel: 'Title'
}, {
xtype: 'textarea',
name: 'description',
width: 300,
height: 100,
fieldLabel: 'Description'
}, {
xtype: 'numberfield',
name: 'severity',
width: 300,
fieldLabel: 'Severity',
value: 1,
maxValue: 5,
minValue: 1
}, {
xtype: 'combo',
name: 'status',
width: 300,
fieldLabel: 'Status',
store: ['Open', 'In Progress', 'Complete'],
queryMode: 'local'
}]
}
});

7. Now we create a window that contains an instance of the BugForm as well as a
single Save button:
Ext.define('BugTracker.view.BugFormWindow', {
extend: 'Ext.window.Window',
alias: 'widget.BugFormWindow',
config: {
height: 250,
width: 500,
title: 'Edit Bug',
modal: true,
items: [{
xtype: 'BugForm'
}],
closeAction: 'hide',
buttons: [{
text: 'Save',
action: 'saveBug'
}]
}
});

8. Our Viewport container is our final view and is a simple component that extends the
Ext.container.Viewport class and creates an instance of the BugPanel class
within its items collection. To have this class instantiated automatically we also add
the autoCreateViewport: true configuration to our application definition in
app.js:
// view/Viewport.js
Ext.define('BugTracker.view.Viewport', {
extend: 'Ext.container.Viewport',
initComponent: function(){
Ext.apply(this, {
layout: 'fit',
items: [{
xtype: 'BugPanel'
}]
});
this.callParent(arguments);
}
});

9. At this point if we open our index.html page we will see the application displaying
our bugs, but clicking on the buttons or bugs doesn't do anything! To bring it all to
life we need to create a controller, which will tie everything together. Start by creating
a new file called Bugs.js in the controller folder and give it the following skeleton
code. At this point we must also add a controllers config to the application
definition of app.js with a value of ['Bugs'] so the controller is automatically
loaded and initialized:
// controller/Bugs.js
Ext.define('BugTracker.controller.Bugs', {
extend: 'Ext.app.Controller',
views: [
'BugDataView',
'BugPanel',
'BugForm',
'BugFormWindow'
],
init: function(){
console.log('Bugs Controller Init');
}
});

10. Next we use the refs config option to adds some accessor methods for each of the
main components so we can access references to them in our action methods:
refs: [{
ref: 'bugDataView',
selector: 'BugPanel BugDataView'
}, {
ref: 'bugFormPanel',
selector: 'BugFormWindow BugForm'
}, {
ref: 'bugFormWindow',
selector: 'BugFormWindow'
}]

11. We now use the control method (which we introduced in the previous recipe) to
wire up our button clicks to a controller action. We use a simple component query to
target the correct button using the action property that we gave each button and
then hook its click event to a method within the controller:
init: function(){
console.log('Bugs Controller Init');
this.control({
'BugPanel button[action="sortBySeverity"]': {
click: this.onSortBySeverityButtonClick,
scope: this
}
});
},
onSortBySeverityButtonClick: function(btn){
this.getBugDataView().getStore().sort('severity', 'DESC');
}
onSortBySeverityButtonClick: function(btn){
this.getBugDataView().getStore().sort('severity', 'DESC');
}

12. We do this for the remaining buttons, the DataView's itemclick event and the
comboboxes' change event:
init: function(){
console.log('Bugs Controller Init');
this.control({
'BugPanel BugDataView': {
itemclick: this.onBugDataViewItemClick,
scope: this
},
'BugPanel button[action="sortBySeverity"]': {
click: this.onSortBySeverityButtonClick,
scope: this
},
'BugPanel button[action="openAllBugs"]': {
click: this.onOpenAllBugsButtonClick,
scope: this
},
'BugPanel button[action="clearFilter"]': {
click: this.onClearFilterButtonClick,
scope: this
},
'BugPanel combo[name="status"]': {
change: this.onBugStatusComboboxChange,

scope: this
},
'BugFormWindow button[action="saveBug"]': {
click: this.onSaveBugButtonClick,
scope: this
}
});
},
onSaveBugButtonClick: function(btn){
var form = this.getBugFormPanel();
// get the record loaded into the form
var selectedRecord = form.getRecord();
selectedRecord.set(form.getValues());
// refilter
this.getBugDataView().getStore().filter();
this.getBugFormWindow().close();
},

onBugDataViewItemClick: function(view, record, item, index,e){
var win = this.getBugFormWindow();
if(!win){
win = Ext.create('BugTracker.view.BugFormWindow');
}
win.show();
// populate the form with the clicked record
this.getBugFormPanel().loadRecord(record);
},
onSortBySeverityButtonClick: function(btn){
this.getBugDataView().getStore().sort('severity', 'DESC');
},
onOpenAllBugsButtonClick: function(btn){
this.getBugDataView().getStore().each(function(model){
model.set('status', 'Open');
model.commit();
}, this);
},
onClearFilterButtonClick: function(btn){
this.getBugDataView().getStore().clearFilter();
},
onBugStatusComboboxChange: function(combo, value, options){
this.getBugDataView().getStore().clearFilter();
this.getBugDataView().getStore().filter('severity', combo.
getValue());
}


댓글 없음:

댓글 쓰기