반응형
지난 시간에는 New 버튼을 달고 더미 데이터를 넣어서 List 를 출력해 봤습니다.
잘 되셨나요?
지난주까지 진행한 소스코드 아래에 있습니다.
필요하신 분은 받아서 보세요.
오늘은 Note Editor 부분을 하겠습니다.
Notes List 에서 Note Editor 화면으로 전환하고 새 데이터를 넣고 저장하고 이것을 List 로 새로 출력하는 기능을 할 겁니다.
이 과정에서 validation도 체크하는 기능도 다룰거구요.
아래 오늘의 내용을 보시죠.
Writing a Sencha Touch Application, Part 3
Part 1,2 에서는 Notes 앱 중에 Notes List view 부분을 다뤘습니다. 오늘은 Note Editor view를 다루겠습니다.
타이틀은 Edit Note 가 될 텐데요. Note의 생성, update, 삭제 기능이 있을 겁니다.
아래 Mock up 이미지와 완성 화면이 있습니다.
***** Creating a Sencha Touch Form Panel
Note Editor mockup을 보면 우리는 툴바와 필드들을 만들어야 합니다.
우선 form field들 부터 만들겠습니다.
NotesApp.views.noteEditor = new Ext.form.FormPanel({
id: 'noteEditor',
items: [
{
xtype: 'textfield',
name: 'title',
label: 'Title',
required: true
},
{
xtype: 'textareafield',
name: 'narrative',
label: 'Narrative'
}
]
});
이 필드들을 만들기 위해 Ext.form.FormPanel 클래스를 사용했습니다. 센차터치에서 form 필드들을 만들 때 가장 손쉽게 만들 수 있는 방법입니다.
제목은 textfield를 사용하고 내용을 넣는 공간은 Text field를 사용합니다.
title 부분에 required 를 true로 했습니다. 반드시 이곳에 값을 넣어야 한다는 겁니다. 디비의 not null 이죠. 나중에 save 하는 단계에서 이곳에 값을 넣지 않으면 어떻게 되는지 보실 수 있습니다.
툴바를 넣기 전에 이 form들의 모습이 어떤지 미리 보면 좋겠죠? viewport 부분을 약간 수정해서 이 form이 보이도록 해 보죠.
viewport의 items 부분을 수정해 아래처럼 수정해 보세요. 그러면 지난번에 만들었던 list가 아니라 edit form이 나올겁니다.
NotesApp.views.viewport = new Ext.Panel({
fullscreen: true,
layout: 'card',
cardAnimation: 'slide',
items: [NotesApp.views.noteEditor] // TODO: revert to [NotesApp.views.notesListContainer]
});
제대로 됐다면 아래처럼 보일겁니다.
***** Adding top and bottom toolbars to a Sencha Touch Panel
이제 툴바를 만들 차례입니다.
첫번째 툴바는 Home 과 Save 버튼이 있는 위쪽 툴바입니다.
NotesApp.views.noteEditorTopToolbar = new Ext.Toolbar({
title: 'Edit Note',
items: [
{
text: 'Home',
ui: 'back',
handler: function () {
// TODO: Transition to the notes list view.
}
},
{ xtype: 'spacer' },
{
text: 'Save',
ui: 'action',
handler: function () {
// TODO: Save current note.
}
}
]
});
위 소스 콛를 보시면 툴바를 만들면서 ui config 옵션을 사용하신 걸 보실 수 있을 겁니다. (back, action 으로 정의했죠?) home 버튼에는 back 이라고 정의했습니다. 왜냐하면 이 버튼을 누르면 back 해서 main view 로 갈 것이기 때문입니다. 그리고 save 버튼에는 action이라고 정의했는데요. 이것은 유저가 이 버튼을 누르면 note를 save 할 거라는 겁니다. 이 기능이 가장 중요한 기능 중 하나죠?
화면 아래에 있는 툴바에는 휴지통 버튼이 들어갈 겁니다. 이 버튼을 누르면 해당 note 가 delete 되겠죠?
NotesApp.views.noteEditorBottomToolbar = new Ext.Toolbar({
dock: 'bottom',
items: [
{ xtype: 'spacer' },
{
iconCls: 'trash',
iconMask: true,
handler: function () {
// TODO: Delete current note.
}
}
]
});
여기에 몇가지 주의하실 부분이 있습니다. 첫번째로 dock config를 어떻게 사용했는지 보세요. 화면 아래에 배치하기 위해 bottom을 사용했습니다. 그리고 iconCls와 iconMask config 옵션을 보세요. 이 기능들은 버튼 안에 trash icon을 render 하기 위한 옵션들입니다.
이제 툴바를 add 하실 수 있습니다.
NotesApp.views.noteEditor = new Ext.form.FormPanel({
id: 'noteEditor',
items: [
{
xtype: 'textfield',
name: 'title',
label: 'Title',
required: true
},
{
xtype: 'textareafield',
name: 'narrative',
label: 'Narrative'
}
],
dockedItems: [
NotesApp.views.noteEditorTopToolbar,
NotesApp.views.noteEditorBottomToolbar
]
});
약간 코드를 수정해서 지금까지 한 작업을 화면으로 볼 수 있도록 해 보죠.
NotesApp.views.viewport = new Ext.Panel({
fullscreen: true,
layout: 'card',
cardAnimation: 'slide',
items: [NotesApp.views.noteEditor] // TODO: revert to [NotesApp.views.notesListContainer]
});
성공했으면 아래와 같은 화면을 보실 수 있을 겁니다.
아주 훌륭하죠?
지금까지 우리는 Notes List와 Note Editor 뷰를 만들었습니다. 이제 필요한 것은 이 앱의 workflow 입니다. 뷰 이외에 다른 비지니스 로직을 어떻게 구현하느냐를 말하는 것이죠. 우선 첫번째 기억할 비지니스 로직(Navigate screen) 은 Notes List 에서 New 버튼을 누르면 Notes Edit View 로 간다는 겁니다.
****** How to change views in a Sencha Touch application
이제 Notes List view 로 가 볼까요? 이제 New 버튼의 handler 부분을 다룰 차례입니다. 이 버튼이 눌려지면 새로운 note를 만들 수 있어야 합니다. 그러니까 이 버튼을 누르면 Note Editor를 화면에 보이도록 하면 되곘죠.
NotesApp.views.notesListToolbar = new Ext.Toolbar({
id: 'notesListToolbar',
title: 'My Notes',
layout: 'hbox',
items: [
{ xtype: 'spacer' },
{
id: 'newNoteButton',
text: 'New',
ui: 'action',
handler: function () {
var now = new Date();
var noteId = now.getTime();
var note = Ext.ModelMgr.create(
{ id: noteId, date: now, title: '', narrative: '' },
'Note'
);
NotesApp.views.noteEditor.load(note);
NotesApp.views.viewport.setActiveItem('noteEditor', {type: 'slide', direction: 'left'});
}
}
]
});
순서대로 한번 볼까요?
첫번째로 ModelMgr 클래스의 create()메소드를 사용해서 새로운 note를 생성합니다.
var now = new Date();
var noteId = now.getTime();
var note = Ext.ModelMgr.create(
{ id: noteId, date: now, title: '', narrative: '' },
'Note'
);
그리고 나서 이 새 note를 Note Editor에 전해줍니다. FormPanel에서 이 부분이 보이도록 하기 위해 load 메소드를 사용했습니다. 이 load 메소드는 필드들을 보여줄겁니다. 이때 value 값들이 있으면 그 value 값들도 보여 줄 거구요.
NotesApp.views.noteEditor.load(note);
다음으로는 우리가 viewport에서 card layout을 사용했듯이 viewport이 setActiveItem()메소드를 사용해서 Note Editor를 보이도록 할 겁니다.
이 setActiveItem()을 call 하면 우리는 우리가 active 시키려고 하는 card의 id를 전달해 주고 그 객체가 transition 하는 animation 기능을 사용할 수 있습니다.
NotesApp.views.viewport.setActiveItem('noteEditor', {type: 'slide', direction: 'left'});
이 New 버튼이 어떻게 작동하는지 확인하기 전에 viewport의 items array를 약간 수정해야 합니다.
NotesApp.views.viewport = new Ext.Panel({
fullscreen: true,
layout: 'card',
cardAnimation: 'slide',
items: [
NotesApp.views.notesListContainer,
NotesApp.views.noteEditor
]
});
여기까지 완성 됐나요? 그러면 이제 user가 작성한 note를 save 할 수 있도록 하시면 됩니다.
이 기능은 당연히 Note Editor의 Save 버튼에 달아야 겠죠.
***** Validating a data model in Sencha Touch
save 버튼을 누르게 되면 우선 체크해야 할 것들이 몇가지 있습니다.
1. form field의 title과 narrative 정보는 Note Model 인스턴스에서 capture 됩니다.
2. note의 title의 value 가 없으면 유저에게 alert 화면을 띄울 겁니다.
3. note 가 new일 경우 이 note를 cache에 add 할 겁니다. 이 note 가 이전에 저장 됐던 것이면 cache에 있는 해당 note를 update 할 겁니다.
4. 그리고 나서 Notes List 를 refresh 해서 보여줄 겁니다.
자 이 기능들을 구현해 볼까요?
save 버튼의 tap 핸들러를 구현하기 전에 Note data model을 수정해서 validation 부분을 구현하는데 좀 더 편하도록 해 봅시다. 우리가 할 것은 model의 title 필드의 validation 함수를 사용해서 message 프로퍼티를 override 할 겁니다. 이 기능은 이 필드가 invalid 할 경우 메세지를 띄우는 기능입니다.
Ext.regModel('Note', {
idProperty: 'id',
fields: [
{ name: 'id', type: 'int' },
{ name: 'date', type: 'date', dateFormat: 'c' },
{ name: 'title', type: 'string' },
{ name: 'narrative', type: 'string' }
],
validations: [
{ type: 'presence', field: 'id' },
{ type: 'presence', field: 'title', message: 'Please enter a title for this note.' }
]
});
이 메세지는 우리가 Note Editor view 에서 note의 validation을 할 때 사용할 겁니다.
이제 save 버튼의 tap 핸들러를 구현해서 이 validation 이 어떻게 이뤄지는지 확인해 보겠습니다.
NotesApp.views.noteEditorTopToolbar = new Ext.Toolbar({
title: 'Edit Note',
items: [
{
text: 'Home',
ui: 'back',
handler: function () {
NotesApp.views.viewport.setActiveItem('notesListContainer', { type: 'slide', direction: 'right' });
}
},
{ xtype: 'spacer' },
{
text: 'Save',
ui: 'action',
handler: function () {
var noteEditor = NotesApp.views.noteEditor;
var currentNote = noteEditor.getRecord();
// Update the note with the values in the form fields.
noteEditor.updateRecord(currentNote);
var errors = currentNote.validate();
if (!errors.isValid()) {
currentNote.reject();
Ext.Msg.alert('Wait!', errors.getByField('title')[0].message, Ext.emptyFn);
return;
}
var notesList = NotesApp.views.notesList;
var notesStore = notesList.getStore();
if (notesStore.findRecord('id', currentNote.data.id) === null) {
notesStore.add(currentNote);
} else {
currentNote.setDirty();
}
notesStore.sync();
notesStore.sort([{ property: 'date', direction: 'DESC'}]);
notesList.refresh();
NotesApp.views.viewport.setActiveItem('notesListContainer', { type: 'slide', direction: 'right' });
}
}
]
});
이 handler 함수에서 첫번째로 form panel의 getRecord() 메소드를 사용했습니다. 이 메소드는 form에 Note model이 로드되는 reference를 가질 수 있도록 해 줍니다. 그 다음에는 updateRecord() 메소드를 사용합니다. 이 메소드는 이 model reference로 폼 필드로부터 value들을 가져와서 전달해 줍니다.
validation dms Note data model에서 validate()를 call 함으로서 Errors 객체를 return 하도록 합니다. isValid()는 이 과정에서 에러가 있는지 없는지 알 수 있게 해 줍니다. 지난 시간에 했듯이 Note Editor 에서는 title 만이 not null입니다. 그래서 이 앱에서는 그 부분만 체크할 겁니다. 에러를 확인하기 위해서는 model의 validations config 옵션에서 정의했듯이 errors.getByField('title')[0] 메세지를 통해서 확인할 수 있습니다.
이 validation을 통화 하면 이 note를 cache에 add 해야 합니다. 대신 이 데이터가 이전에 있는지 확인하는 기능이 있어야 합니다.
아래 findRecord()메소드를 통해서 이 작업을 간단하게 해 주시구요.
var notesStore = notesList.getStore();
if (notesStore.findRecord('id', currentNote.data.id) === null) {
notesStore.add(currentNote);
}
update 시키신 후에는 sync() 메소드를 이용해서 완전히 이 데이터를 저장하시면 됩니다. 오라클에서 commit; 기능하고 비슷합니다.
그 다음에 sort() 메소드를 사용해서 note를 날짜 순서로 정렬합니다. 그러면 notes list에 render 할 준비가 끝나는 겁니다.
notesList.refresh();
NotesApp.views.viewport.setActiveItem('notesListContainer', { type: 'slide', direction: 'right' });
type을 보시면 slide와 right가 있을 겁니다. 이것은 화면 전환 할 때 된쪽에서 오른쪽으로 slide하게 화면이 바뀌도록 합니다.
이제 남은 것은 Home button에 handler를 구현하는 겁니다.
이 홈 버튼을 누르면 단순히 Notes List로 돌아가기만 하면 됩니다.
{
text: 'Home',
ui: 'back',
handler: function () {
NotesApp.views.viewport.setActiveItem('notesListContainer', { type: 'slide', direction: 'right' });'s next
}
}
한번 화면으로 테스트 해 보고 싶으신가요? 이제 실행 해 보시면 save하고 새 note를 create하는 것들이 다 가능할 겁니다.
***** What’s next
다음에 우리가 구현 할 것은 기존에 존재하는 notes를 수정하고 지우는 기능입니다.
이 기능은 다음 시간에 구현해 보겠습니다.
오늘까지 한 js 소스는 아래와 같습니다.
var App = new Ext.Application({
name: 'NotesApp',
useLoadMask: true,
launch: function () {
Ext.regModel('Note', {
idProperty: 'id',
fields: [
{ name: 'id', type: 'int' },
{ name: 'date', type: 'date', dateFormat: 'c' },
{ name: 'title', type: 'string' },
{ name: 'narrative', type: 'string' }
],
validations: [
{ type: 'presence', field: 'id' },
{ type: 'presence', field: 'title', message: 'Please enter a title for this note.' }
]
});
Ext.regStore('NotesStore', {
model: 'Note',
sorters: [{
property: 'date',
direction: 'DESC'
}],
proxy: {
type: 'localstorage',
id: 'notes-app-store'
}
});
NotesApp.views.noteEditorTopToolbar = new Ext.Toolbar({
title: 'Edit Note',
items: [
{
text: 'Home',
ui: 'back',
handler: function () {
NotesApp.views.viewport.setActiveItem('notesListContainer', { type: 'slide', direction: 'right' });
}
},
{ xtype: 'spacer' },
{
text: 'Save',
ui: 'action',
handler: function () {
var noteEditor = NotesApp.views.noteEditor;
var currentNote = noteEditor.getRecord();
// Update the note with the values in the form fields.
noteEditor.updateRecord(currentNote);
var errors = currentNote.validate();
if (!errors.isValid()) {
currentNote.reject();
Ext.Msg.alert('Wait!', errors.getByField('title')[0].message, Ext.emptyFn);
return;
}
var notesList = NotesApp.views.notesList;
var notesStore = notesList.getStore();
if (notesStore.findRecord('id', currentNote.data.id) === null) {
notesStore.add(currentNote);
} else {
currentNote.setDirty();
}
notesStore.sync();
notesStore.sort([{ property: 'date', direction: 'DESC'}]);
notesList.refresh();
NotesApp.views.viewport.setActiveItem('notesListContainer', { type: 'slide', direction: 'right' });
}
}
]
});
NotesApp.views.noteEditorBottomToolbar = new Ext.Toolbar({
dock: 'bottom',
items: [
{ xtype: 'spacer' },
{
iconCls: 'trash',
iconMask: true,
handler: function () {
// TODO: Delete current note.
}
}
]
});
NotesApp.views.noteEditor = new Ext.form.FormPanel({
id: 'noteEditor',
items: [
{
xtype: 'textfield',
name: 'title',
label: 'Title',
required: true
},
{
xtype: 'textareafield',
name: 'narrative',
label: 'Narrative'
}
],
dockedItems: [
NotesApp.views.noteEditorTopToolbar,
NotesApp.views.noteEditorBottomToolbar
]
});
NotesApp.views.notesList = new Ext.List({
id: 'notesList',
store: 'NotesStore',
itemTpl: '
<div class="list-item-title">{title}</div>
' +
'
<div class="list-item-narrative">{narrative}</div>
',
onItemDisclosure: function (record) {
// TODO: Render the selected note in the note editor.
},
listeners: {
'render': function (thisComponent) {
thisComponent.getStore().load();
}
}
});
NotesApp.views.notesListToolbar = new Ext.Toolbar({
id: 'notesListToolbar',
title: 'My Notes',
layout: 'hbox',
items: [
{ xtype: 'spacer' },
{
id: 'newNoteButton',
text: 'New',
ui: 'action',
handler: function () {
var now = new Date();
var noteId = now.getTime();
var note = Ext.ModelMgr.create(
{ id: noteId, date: now, title: '', narrative: '' },
'Note'
);
NotesApp.views.noteEditor.load(note);
NotesApp.views.viewport.setActiveItem('noteEditor', { type: 'slide', direction: 'left' });
}
}
]
});
NotesApp.views.notesListContainer = new Ext.Panel({
id: 'notesListContainer',
layout: 'fit',
html: 'This is the notes list container',
dockedItems: [NotesApp.views.notesListToolbar],
items: [NotesApp.views.notesList]
});
NotesApp.views.viewport = new Ext.Panel({
fullscreen: true,
layout: 'card',
cardAnimation: 'slide',
items: [
NotesApp.views.notesListContainer,
NotesApp.views.noteEditor
]
});
}
});
이제 저도 Sencha Touch 에 대해 대충 감이 잡히네요.
다음시간에 첫번째 센차터치 앱 Notes 를 완료하겠습니다.
그리고 계속 하이브리드 모바일 앱을 위해 Corona SDK, HTML5, Sencha Touch, Phone Gap 등 관련 기술을 익히고 싶네요.
꾹~~ 꾹~~ 응원 부탁드려요... ~~~~~~~
잘 되셨나요?
지난주까지 진행한 소스코드 아래에 있습니다.
필요하신 분은 받아서 보세요.
오늘은 Note Editor 부분을 하겠습니다.
Notes List 에서 Note Editor 화면으로 전환하고 새 데이터를 넣고 저장하고 이것을 List 로 새로 출력하는 기능을 할 겁니다.
이 과정에서 validation도 체크하는 기능도 다룰거구요.
아래 오늘의 내용을 보시죠.
Writing a Sencha Touch Application, Part 3
Part 1,2 에서는 Notes 앱 중에 Notes List view 부분을 다뤘습니다. 오늘은 Note Editor view를 다루겠습니다.
타이틀은 Edit Note 가 될 텐데요. Note의 생성, update, 삭제 기능이 있을 겁니다.
아래 Mock up 이미지와 완성 화면이 있습니다.
***** Creating a Sencha Touch Form Panel
Note Editor mockup을 보면 우리는 툴바와 필드들을 만들어야 합니다.
우선 form field들 부터 만들겠습니다.
NotesApp.views.noteEditor = new Ext.form.FormPanel({
id: 'noteEditor',
items: [
{
xtype: 'textfield',
name: 'title',
label: 'Title',
required: true
},
{
xtype: 'textareafield',
name: 'narrative',
label: 'Narrative'
}
]
});
이 필드들을 만들기 위해 Ext.form.FormPanel 클래스를 사용했습니다. 센차터치에서 form 필드들을 만들 때 가장 손쉽게 만들 수 있는 방법입니다.
제목은 textfield를 사용하고 내용을 넣는 공간은 Text field를 사용합니다.
title 부분에 required 를 true로 했습니다. 반드시 이곳에 값을 넣어야 한다는 겁니다. 디비의 not null 이죠. 나중에 save 하는 단계에서 이곳에 값을 넣지 않으면 어떻게 되는지 보실 수 있습니다.
툴바를 넣기 전에 이 form들의 모습이 어떤지 미리 보면 좋겠죠? viewport 부분을 약간 수정해서 이 form이 보이도록 해 보죠.
viewport의 items 부분을 수정해 아래처럼 수정해 보세요. 그러면 지난번에 만들었던 list가 아니라 edit form이 나올겁니다.
NotesApp.views.viewport = new Ext.Panel({
fullscreen: true,
layout: 'card',
cardAnimation: 'slide',
items: [NotesApp.views.noteEditor] // TODO: revert to [NotesApp.views.notesListContainer]
});
제대로 됐다면 아래처럼 보일겁니다.
***** Adding top and bottom toolbars to a Sencha Touch Panel
이제 툴바를 만들 차례입니다.
첫번째 툴바는 Home 과 Save 버튼이 있는 위쪽 툴바입니다.
NotesApp.views.noteEditorTopToolbar = new Ext.Toolbar({
title: 'Edit Note',
items: [
{
text: 'Home',
ui: 'back',
handler: function () {
// TODO: Transition to the notes list view.
}
},
{ xtype: 'spacer' },
{
text: 'Save',
ui: 'action',
handler: function () {
// TODO: Save current note.
}
}
]
});
위 소스 콛를 보시면 툴바를 만들면서 ui config 옵션을 사용하신 걸 보실 수 있을 겁니다. (back, action 으로 정의했죠?) home 버튼에는 back 이라고 정의했습니다. 왜냐하면 이 버튼을 누르면 back 해서 main view 로 갈 것이기 때문입니다. 그리고 save 버튼에는 action이라고 정의했는데요. 이것은 유저가 이 버튼을 누르면 note를 save 할 거라는 겁니다. 이 기능이 가장 중요한 기능 중 하나죠?
화면 아래에 있는 툴바에는 휴지통 버튼이 들어갈 겁니다. 이 버튼을 누르면 해당 note 가 delete 되겠죠?
NotesApp.views.noteEditorBottomToolbar = new Ext.Toolbar({
dock: 'bottom',
items: [
{ xtype: 'spacer' },
{
iconCls: 'trash',
iconMask: true,
handler: function () {
// TODO: Delete current note.
}
}
]
});
여기에 몇가지 주의하실 부분이 있습니다. 첫번째로 dock config를 어떻게 사용했는지 보세요. 화면 아래에 배치하기 위해 bottom을 사용했습니다. 그리고 iconCls와 iconMask config 옵션을 보세요. 이 기능들은 버튼 안에 trash icon을 render 하기 위한 옵션들입니다.
이제 툴바를 add 하실 수 있습니다.
NotesApp.views.noteEditor = new Ext.form.FormPanel({
id: 'noteEditor',
items: [
{
xtype: 'textfield',
name: 'title',
label: 'Title',
required: true
},
{
xtype: 'textareafield',
name: 'narrative',
label: 'Narrative'
}
],
dockedItems: [
NotesApp.views.noteEditorTopToolbar,
NotesApp.views.noteEditorBottomToolbar
]
});
약간 코드를 수정해서 지금까지 한 작업을 화면으로 볼 수 있도록 해 보죠.
NotesApp.views.viewport = new Ext.Panel({
fullscreen: true,
layout: 'card',
cardAnimation: 'slide',
items: [NotesApp.views.noteEditor] // TODO: revert to [NotesApp.views.notesListContainer]
});
성공했으면 아래와 같은 화면을 보실 수 있을 겁니다.
아주 훌륭하죠?
지금까지 우리는 Notes List와 Note Editor 뷰를 만들었습니다. 이제 필요한 것은 이 앱의 workflow 입니다. 뷰 이외에 다른 비지니스 로직을 어떻게 구현하느냐를 말하는 것이죠. 우선 첫번째 기억할 비지니스 로직(Navigate screen) 은 Notes List 에서 New 버튼을 누르면 Notes Edit View 로 간다는 겁니다.
****** How to change views in a Sencha Touch application
이제 Notes List view 로 가 볼까요? 이제 New 버튼의 handler 부분을 다룰 차례입니다. 이 버튼이 눌려지면 새로운 note를 만들 수 있어야 합니다. 그러니까 이 버튼을 누르면 Note Editor를 화면에 보이도록 하면 되곘죠.
NotesApp.views.notesListToolbar = new Ext.Toolbar({
id: 'notesListToolbar',
title: 'My Notes',
layout: 'hbox',
items: [
{ xtype: 'spacer' },
{
id: 'newNoteButton',
text: 'New',
ui: 'action',
handler: function () {
var now = new Date();
var noteId = now.getTime();
var note = Ext.ModelMgr.create(
{ id: noteId, date: now, title: '', narrative: '' },
'Note'
);
NotesApp.views.noteEditor.load(note);
NotesApp.views.viewport.setActiveItem('noteEditor', {type: 'slide', direction: 'left'});
}
}
]
});
순서대로 한번 볼까요?
첫번째로 ModelMgr 클래스의 create()메소드를 사용해서 새로운 note를 생성합니다.
var now = new Date();
var noteId = now.getTime();
var note = Ext.ModelMgr.create(
{ id: noteId, date: now, title: '', narrative: '' },
'Note'
);
그리고 나서 이 새 note를 Note Editor에 전해줍니다. FormPanel에서 이 부분이 보이도록 하기 위해 load 메소드를 사용했습니다. 이 load 메소드는 필드들을 보여줄겁니다. 이때 value 값들이 있으면 그 value 값들도 보여 줄 거구요.
NotesApp.views.noteEditor.load(note);
다음으로는 우리가 viewport에서 card layout을 사용했듯이 viewport이 setActiveItem()메소드를 사용해서 Note Editor를 보이도록 할 겁니다.
이 setActiveItem()을 call 하면 우리는 우리가 active 시키려고 하는 card의 id를 전달해 주고 그 객체가 transition 하는 animation 기능을 사용할 수 있습니다.
NotesApp.views.viewport.setActiveItem('noteEditor', {type: 'slide', direction: 'left'});
이 New 버튼이 어떻게 작동하는지 확인하기 전에 viewport의 items array를 약간 수정해야 합니다.
NotesApp.views.viewport = new Ext.Panel({
fullscreen: true,
layout: 'card',
cardAnimation: 'slide',
items: [
NotesApp.views.notesListContainer,
NotesApp.views.noteEditor
]
});
여기까지 완성 됐나요? 그러면 이제 user가 작성한 note를 save 할 수 있도록 하시면 됩니다.
이 기능은 당연히 Note Editor의 Save 버튼에 달아야 겠죠.
***** Validating a data model in Sencha Touch
save 버튼을 누르게 되면 우선 체크해야 할 것들이 몇가지 있습니다.
1. form field의 title과 narrative 정보는 Note Model 인스턴스에서 capture 됩니다.
2. note의 title의 value 가 없으면 유저에게 alert 화면을 띄울 겁니다.
3. note 가 new일 경우 이 note를 cache에 add 할 겁니다. 이 note 가 이전에 저장 됐던 것이면 cache에 있는 해당 note를 update 할 겁니다.
4. 그리고 나서 Notes List 를 refresh 해서 보여줄 겁니다.
자 이 기능들을 구현해 볼까요?
save 버튼의 tap 핸들러를 구현하기 전에 Note data model을 수정해서 validation 부분을 구현하는데 좀 더 편하도록 해 봅시다. 우리가 할 것은 model의 title 필드의 validation 함수를 사용해서 message 프로퍼티를 override 할 겁니다. 이 기능은 이 필드가 invalid 할 경우 메세지를 띄우는 기능입니다.
Ext.regModel('Note', {
idProperty: 'id',
fields: [
{ name: 'id', type: 'int' },
{ name: 'date', type: 'date', dateFormat: 'c' },
{ name: 'title', type: 'string' },
{ name: 'narrative', type: 'string' }
],
validations: [
{ type: 'presence', field: 'id' },
{ type: 'presence', field: 'title', message: 'Please enter a title for this note.' }
]
});
이 메세지는 우리가 Note Editor view 에서 note의 validation을 할 때 사용할 겁니다.
이제 save 버튼의 tap 핸들러를 구현해서 이 validation 이 어떻게 이뤄지는지 확인해 보겠습니다.
NotesApp.views.noteEditorTopToolbar = new Ext.Toolbar({
title: 'Edit Note',
items: [
{
text: 'Home',
ui: 'back',
handler: function () {
NotesApp.views.viewport.setActiveItem('notesListContainer', { type: 'slide', direction: 'right' });
}
},
{ xtype: 'spacer' },
{
text: 'Save',
ui: 'action',
handler: function () {
var noteEditor = NotesApp.views.noteEditor;
var currentNote = noteEditor.getRecord();
// Update the note with the values in the form fields.
noteEditor.updateRecord(currentNote);
var errors = currentNote.validate();
if (!errors.isValid()) {
currentNote.reject();
Ext.Msg.alert('Wait!', errors.getByField('title')[0].message, Ext.emptyFn);
return;
}
var notesList = NotesApp.views.notesList;
var notesStore = notesList.getStore();
if (notesStore.findRecord('id', currentNote.data.id) === null) {
notesStore.add(currentNote);
} else {
currentNote.setDirty();
}
notesStore.sync();
notesStore.sort([{ property: 'date', direction: 'DESC'}]);
notesList.refresh();
NotesApp.views.viewport.setActiveItem('notesListContainer', { type: 'slide', direction: 'right' });
}
}
]
});
이 handler 함수에서 첫번째로 form panel의 getRecord() 메소드를 사용했습니다. 이 메소드는 form에 Note model이 로드되는 reference를 가질 수 있도록 해 줍니다. 그 다음에는 updateRecord() 메소드를 사용합니다. 이 메소드는 이 model reference로 폼 필드로부터 value들을 가져와서 전달해 줍니다.
validation dms Note data model에서 validate()를 call 함으로서 Errors 객체를 return 하도록 합니다. isValid()는 이 과정에서 에러가 있는지 없는지 알 수 있게 해 줍니다. 지난 시간에 했듯이 Note Editor 에서는 title 만이 not null입니다. 그래서 이 앱에서는 그 부분만 체크할 겁니다. 에러를 확인하기 위해서는 model의 validations config 옵션에서 정의했듯이 errors.getByField('title')[0] 메세지를 통해서 확인할 수 있습니다.
이 validation을 통화 하면 이 note를 cache에 add 해야 합니다. 대신 이 데이터가 이전에 있는지 확인하는 기능이 있어야 합니다.
아래 findRecord()메소드를 통해서 이 작업을 간단하게 해 주시구요.
var notesStore = notesList.getStore();
if (notesStore.findRecord('id', currentNote.data.id) === null) {
notesStore.add(currentNote);
}
update 시키신 후에는 sync() 메소드를 이용해서 완전히 이 데이터를 저장하시면 됩니다. 오라클에서 commit; 기능하고 비슷합니다.
그 다음에 sort() 메소드를 사용해서 note를 날짜 순서로 정렬합니다. 그러면 notes list에 render 할 준비가 끝나는 겁니다.
notesList.refresh();
NotesApp.views.viewport.setActiveItem('notesListContainer', { type: 'slide', direction: 'right' });
type을 보시면 slide와 right가 있을 겁니다. 이것은 화면 전환 할 때 된쪽에서 오른쪽으로 slide하게 화면이 바뀌도록 합니다.
이제 남은 것은 Home button에 handler를 구현하는 겁니다.
이 홈 버튼을 누르면 단순히 Notes List로 돌아가기만 하면 됩니다.
{
text: 'Home',
ui: 'back',
handler: function () {
NotesApp.views.viewport.setActiveItem('notesListContainer', { type: 'slide', direction: 'right' });'s next
}
}
한번 화면으로 테스트 해 보고 싶으신가요? 이제 실행 해 보시면 save하고 새 note를 create하는 것들이 다 가능할 겁니다.
***** What’s next
다음에 우리가 구현 할 것은 기존에 존재하는 notes를 수정하고 지우는 기능입니다.
이 기능은 다음 시간에 구현해 보겠습니다.
오늘까지 한 js 소스는 아래와 같습니다.
var App = new Ext.Application({
name: 'NotesApp',
useLoadMask: true,
launch: function () {
Ext.regModel('Note', {
idProperty: 'id',
fields: [
{ name: 'id', type: 'int' },
{ name: 'date', type: 'date', dateFormat: 'c' },
{ name: 'title', type: 'string' },
{ name: 'narrative', type: 'string' }
],
validations: [
{ type: 'presence', field: 'id' },
{ type: 'presence', field: 'title', message: 'Please enter a title for this note.' }
]
});
Ext.regStore('NotesStore', {
model: 'Note',
sorters: [{
property: 'date',
direction: 'DESC'
}],
proxy: {
type: 'localstorage',
id: 'notes-app-store'
}
});
NotesApp.views.noteEditorTopToolbar = new Ext.Toolbar({
title: 'Edit Note',
items: [
{
text: 'Home',
ui: 'back',
handler: function () {
NotesApp.views.viewport.setActiveItem('notesListContainer', { type: 'slide', direction: 'right' });
}
},
{ xtype: 'spacer' },
{
text: 'Save',
ui: 'action',
handler: function () {
var noteEditor = NotesApp.views.noteEditor;
var currentNote = noteEditor.getRecord();
// Update the note with the values in the form fields.
noteEditor.updateRecord(currentNote);
var errors = currentNote.validate();
if (!errors.isValid()) {
currentNote.reject();
Ext.Msg.alert('Wait!', errors.getByField('title')[0].message, Ext.emptyFn);
return;
}
var notesList = NotesApp.views.notesList;
var notesStore = notesList.getStore();
if (notesStore.findRecord('id', currentNote.data.id) === null) {
notesStore.add(currentNote);
} else {
currentNote.setDirty();
}
notesStore.sync();
notesStore.sort([{ property: 'date', direction: 'DESC'}]);
notesList.refresh();
NotesApp.views.viewport.setActiveItem('notesListContainer', { type: 'slide', direction: 'right' });
}
}
]
});
NotesApp.views.noteEditorBottomToolbar = new Ext.Toolbar({
dock: 'bottom',
items: [
{ xtype: 'spacer' },
{
iconCls: 'trash',
iconMask: true,
handler: function () {
// TODO: Delete current note.
}
}
]
});
NotesApp.views.noteEditor = new Ext.form.FormPanel({
id: 'noteEditor',
items: [
{
xtype: 'textfield',
name: 'title',
label: 'Title',
required: true
},
{
xtype: 'textareafield',
name: 'narrative',
label: 'Narrative'
}
],
dockedItems: [
NotesApp.views.noteEditorTopToolbar,
NotesApp.views.noteEditorBottomToolbar
]
});
NotesApp.views.notesList = new Ext.List({
id: 'notesList',
store: 'NotesStore',
itemTpl: '
<div class="list-item-title">{title}</div>
' +
'
<div class="list-item-narrative">{narrative}</div>
',
onItemDisclosure: function (record) {
// TODO: Render the selected note in the note editor.
},
listeners: {
'render': function (thisComponent) {
thisComponent.getStore().load();
}
}
});
NotesApp.views.notesListToolbar = new Ext.Toolbar({
id: 'notesListToolbar',
title: 'My Notes',
layout: 'hbox',
items: [
{ xtype: 'spacer' },
{
id: 'newNoteButton',
text: 'New',
ui: 'action',
handler: function () {
var now = new Date();
var noteId = now.getTime();
var note = Ext.ModelMgr.create(
{ id: noteId, date: now, title: '', narrative: '' },
'Note'
);
NotesApp.views.noteEditor.load(note);
NotesApp.views.viewport.setActiveItem('noteEditor', { type: 'slide', direction: 'left' });
}
}
]
});
NotesApp.views.notesListContainer = new Ext.Panel({
id: 'notesListContainer',
layout: 'fit',
html: 'This is the notes list container',
dockedItems: [NotesApp.views.notesListToolbar],
items: [NotesApp.views.notesList]
});
NotesApp.views.viewport = new Ext.Panel({
fullscreen: true,
layout: 'card',
cardAnimation: 'slide',
items: [
NotesApp.views.notesListContainer,
NotesApp.views.noteEditor
]
});
}
});
이제 저도 Sencha Touch 에 대해 대충 감이 잡히네요.
다음시간에 첫번째 센차터치 앱 Notes 를 완료하겠습니다.
그리고 계속 하이브리드 모바일 앱을 위해 Corona SDK, HTML5, Sencha Touch, Phone Gap 등 관련 기술을 익히고 싶네요.
꾹~~ 꾹~~ 응원 부탁드려요... ~~~~~~~
반응형
'WEB_APP > Sencha_Touch' 카테고리의 다른 글
Sencha Touch 2 Tutorial - Controllers - (2) | 2012.03.06 |
---|---|
Sencha Touch 2 Application에 대한 전반적인 이해 (0) | 2012.03.04 |
Sencha Touch 2.0 Beta Tutorial 첫번째 앱 -2- (4) | 2012.02.26 |
Sencha Touch 2.0 Beta Tutorial 첫번째 앱 -1- (6) | 2012.02.25 |
Sencha Touch Tutorial 1 Getting Started (0) | 2012.02.22 |
Sencha Touch 로 첫번째 앱 만들기 -4- (1) | 2012.02.21 |
Sencha Touch 로 첫번째 앱 만들기 -2- (6) | 2012.02.17 |
Sencha Touch 로 첫번째 앱 만들기 -1- (6) | 2012.02.14 |
Sencha Touch getting started - 설치 및 예제 실행 - (2) | 2011.12.16 |
Sencha Touch Road Show 를 다녀와서.... (4) | 2011.12.14 |