반응형
블로그 이미지
개발자로서 현장에서 일하면서 새로 접하는 기술들이나 알게된 정보 등을 정리하기 위한 블로그입니다. 운 좋게 미국에서 큰 회사들의 프로젝트에서 컬설턴트로 일하고 있어서 새로운 기술들을 접할 기회가 많이 있습니다. 미국의 IT 프로젝트에서 사용되는 툴들에 대해 많은 분들과 정보를 공유하고 싶습니다.
솔웅

최근에 받은 트랙백

글 보관함



Writing a Sencha Touch Application, Part 2

지난 시간에는 Sencha로 만드는 첫번째 앱인 My Notes 앱을 배웠습니다.
Notes List view를 말들고 있었습니다.
지난시간에 아래 화면까지 작업했습니다.



여기에 아래 mock-up 이미지처럼 툴바에 버튼을 달고 유저가 생성한 Notes들을 랜더링해서 보여주는 기능을 Ext.list를 이용해서 구현할 겁니다.



***** Creating a Data Model in Sencha Touch

우선 데이타 모델을 만들겠습니다. DB를 이용한다면 필드들을 만드는 겁니다.
리스트에 표시할 내용들에 대한 데이터 모델인데요 id,date,title,narrative 등이 있어야 합니다.
이 데이터 모델은 Ext.regModel() 메소드를 이용해서 만들겁니다.

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' }
    ]
});

데이타 모델과 관련한 API는 여기를 클릭해서 보시면 도움이 될 겁니다.
Sencha Touch의 이 데이터 모델관련 메소드에서는 내부적으로 validation을 지원합니다.
위에는 id와 title에 validations를 주었습니다. 데이터가 꼭 있어야 된다는 내용입니다. sql로 치면 not null 입니다.
이 validation이 어떻게 동작하는지에 대해서는 나중에 살펴보도록 하죠.
또한 associations 기능도 지원을 하는데요 우리가 만드는 앱에서는 사용하지는 않습니다.
아주 유용한 기능이니까 API를 꼭 참조하세요.

***** Configuring a Sencha Touch Data Store to use HTML5 local storage

이제 데이터를 Cacheg하는 기능이 필요합니다. Ext.regstore() 함수가 데이터 store를 생성하도록 할 겁니다.
아래 소스코드를 참조하세요.

Ext.regStore('NotesStore', {
    model: 'Note',
    sorters: [{
        property: 'date',
        direction: 'DESC'
    }],
    proxy: {
        type: 'localstorage',
        id: 'notes-app-localstore'
    }
});

Ext.regStore() 는 프레임 워크의 Store Manager 와 같이 store를 생성하고 register 합니다. 프레임워크의 다른 클래스들 처럼 여러분은 앱의 데이터 store를 lookup 하고 modify 하는데 이 Store Manager를 사용할 수 있습니다.
우리의 NotesStore의 모델 config 옵션은 Note model 입니다. 우리는 또한 sorters 옵션도 사용해서 날짜 역순으로 표시할 겁니다.
우리의 앱은 브라우저 세션을 이용해서 notes를 저장할 수 있어야 합니다. 그러기 위해서는 store의 proxy로 모델데이터를 로드하고 저장하는 일을 해야 합니다. 그래서 proxy config 옵션을 사용합니다. 이 옵션을 사용함으로서 proxy 는 Ext.data.LocalStorageProxy 클래스의 인스턴스가 됩니다. 이 클래스는 HTML5의 LocalStorage API를 사용해 사용자 브라우저에 모델 데이터를 저장하게 됩니다.

***** Creating a Sencha Touch list

데이터 모델과 store 가 준비 됐으면 이제 notes list 를 생성할 수 있습니다.

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>
'
});

복잡한 거는 없습니다. store config 옵션에 이름을 넣습니다. render 하기 위해 itemTpi config 옵션을 사용합니다. 그 안에 있는 태그(markup)은 list-item-title과 list-item-narrative 클래스가 정의 돼 있습니다. 이 클래스는 app.css 파일에서 사용할 겁니다.

.list-item-title
{
    float:left;
    width:100%;
    font-size:90%;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.list-item-narrative
{
    float:left;
    width:100%;
    color:#666666;
    font-size:80%;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.x-item-selected .list-item-title
{
    color:#ffffff;
}
.x-item-selected .list-item-narrative
{
    color:#ffffff;
}

이제 panel의 items config 옵션을 사용해서 container panel에 list를 추가해 보겠습니다.

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]
});

시뮬레이터에서 확인하기 전에 dummy note를 집어 넣겠습니다. 그래야 브라우저나 디바이스로 테스트하면 이 dummy 내용이 나올 테니까요. 아래와 같이 data config 옵션을 넣어 보세요.

Ext.regStore('NotesStore', {
    model: 'Note',
    sorters: [{
        property: 'date',
        direction: 'DESC'
    }],
    proxy: {
        type: 'localstorage',
        id: 'notes-app-store'
    },
    // TODO: remove this data after testing.
    data: [
        { id: 1, date: new Date(), title: 'Test Note', narrative: 'This is simply a test note' }
    ]
});

에뮬레이터에서 Notes List 는 아래와 같이 보일 겁니다.



이제 우리의 Notes List view는 거의 완성 됐습니다. 툴바를 만들었고 Note List도 만들었습니다. 그리고 data model,store도 구현했구요 이러한 것들은 이 notes를 cache 하게 될 겁니다. 아직 안된게 두개가 있습니다. 다른 페이지로 넘어가도록 하는 버튼들인데요. 툴바에 있는 New 버튼하고 각각의 List item에 있는 disclosure 버튼입니다.



***** Adding buttons to a Sencha Touch toolbar

아래 소스코드는 New 버튼을 툴바에 add 하는 방법을 보여줍니다.
NotesApp.views.notesListToolbar = new Ext.Toolbar({
    id: 'notesListToolbar',
    title: 'My Notes',
    layout: 'hbox',
    items: [
        { xtype: 'spacer' },
        {
            id: 'newNoteButton',
            text: 'New',
            ui: 'action',
            handler: function () {
                // TODO: Create a blank note and make the note editor visible.
            }
        }
    ]
});

보시면 툴바에 New button을 달 수 있도록 hbox 레이아웃과 spacer를 넣었습니다. 그리고 handler function 도 넣었습니다. 여기에는 나중에 Note Editor view 와 관련한 기능이 추가 될 겁니다.

***** Implementing disclosure buttons in a Sencha Touch list

각 리스트에 달릴 disclosure 버튼을 다는것도 쉽습니다. 아래 코드에서 보듯이 onItemDisclosure function을 사용하시면 됩니다.

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.
    }
});

리스트 아이템에 tap event에 대한 listener를 달기 위해 onItemDisclsure를 override 하고 있습니다. 이 리스너가 하는 일은 유저가 리스트를 탭하면 이를 감지해서 Note Editor view에 알려주는 역할을 하게 될 겁니다.
이 기능은 Note Editor를 만들고 나서 나중에 구현하겠습니다.

***** Where are we?

여기까지 무사히 마쳤다면 아래와 같은 화면을 부실 수 있을 겁니다.



이제 어플리케이션의 main view를 완성했습니다. 두개의 이벤트 핸들러를 구현하는 부분은 남았지만 비쥬얼한 부분은 다 완성됐습니다.

이제 다음시간에는 Note Editor를 만들어 보겠습니다.



아래는 지금까지 한 소스 입니다.

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' }
            ]
        });

        Ext.regStore('NotesStore', {
            model: 'Note',
            sorters: [{
                property: 'date',
                direction: 'DESC'
            }],
            proxy: {
                type: 'localstorage',
                id: 'notes-app-localstore'
            },
            // TODO: remove this data after testing.
            data: [
                { id: 1, date: new Date(), title: 'Test Note', narrative: 'This is simply a test note' }
            ]
        });

        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.
            }
        });

        NotesApp.views.notesListToolbar = new Ext.Toolbar({
            id: 'notesListToolbar',
            title: 'My Notes',
            layout: 'hbox',
            items: [
                { xtype: 'spacer' },
                {
                    id: 'newNoteButton',
                    text: 'New',
                    ui: 'action',
                    handler: function () {
                        // TODO: Create a blank note and make the note editor visible.
                    }
                }
            ]
        });

        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]
        });
    }
});

앞으로 두 번만 더 다루면 센차터치로 만드는 첫 번째 앱이 완성됩니다.
정말 기대가 되는데요.
다음 시간에 또 뵙구요... 꾹 꾹 추천 한방 눌러 주세요.... ~~~~
반응형

Comment

  1. 테일 2012.02.20 18:19

    감사히 보고 있습니다 ^^

    • 솔웅 2012.02.21 07:59 신고

      예 저도 감사합니다.
      질문이나 의견 있으시면 언제든지 말씀해 주세요.

      감사합니다.

  2. 우와 상세해 2012.03.21 15:55

    정말 감사합니다 많은 도움이 되고 있어요 ㅠ. ㅠ

    • 솔웅 2012.05.30 04:57 신고

      오래전에 댓글 올리셨네요. 이제야 확인합니다.
      저도 아주 감사드립니다.

  3. 1.x 기반소스인가요? 2.0.1에서는 정상작동을 안하네요?

    • 솔웅 2012.05.30 04:57 신고

      예 1.X 기반 소스예요. 써핑하다 보니까 1.x 대 소스만 있어서 일단 이것 가지고 개념이해하려고 정리했어요.
      2.0 대 소스는 잘 구하기 어려운것 같은데..
      어디 소스 있는데 알고 계시면 share 해 주세요. ^^
      감사합니다.