接續上次的文章,我們這次要把要一步一步把功能給實做完成~!
第一階段
第二階段
內文:
延續上次的文章,我們已經完成Todo應用的CUD(新增、修改、刪除),接下來我們要做的便是可以讓使用者filter已經完成的Todo,哪些又是尚未完成的Todo。因此這邊我們需要把我們的Template分成數個子Template並利用框架的Route來做到讓這些事情在同一頁完成。
首先我們先把列表頁的內容抽出來變成一個新的Template
<!-- data-template-name內的值就相當於是一個路由,index是讓這個Template顯示的路由值,裡面的資料來源從哪裡來則從route去設定 --> <script type="text/x-handlebars" data-template-name="MyTodos/index"> <ul id="todo-list"> {{#each itemController="MyTodoList"}} <li {{bind-attr class="isCompleted:completed isEditing:editing" }}> {{#if isEditing}} {{input class="edit" value=title focus-out="acceptChanges" insert-newline="acceptChanges"}} {{else}} {{input type="checkbox" checked=isItemCompleted class="toggle"}} <label {{action "editTodo" on="doubleClick" }}>{{title}}</label><button {{action "removeTodo" }} class="destroy"></button> {{/if}} </li> {{/each}} </ul> </script>而原本的Template就變成如下:
<script type="text/x-handlebars" data-template-name="MyTodos"> <section id="todoapp"> <header id="header"> <h1>todos</h1> {{input type="text" id="new-todo" placeholder="What needs to be done?" value=myTitle1 action="createTodo"}} </header> <section id="main"> {{outlet}} <input type="checkbox" id="toggle-all"> </section> </script> <!--忽略很多-->Handlebars helper "{{outlet}}" 是用來幫助我們宣告一個區域,當我們改變route時可以render出指定route的畫面,而第一個child route就會是填滿這個區塊的route。
改完View之後我們要新增一個route.js檔案,在裡面撰寫route相關的邏輯。
Todos.Router.map(function () { // 當Uri為'/'時去render名稱為「MyTodos」的Template this.resource('MyTodos', { path: '/' }, function () { //額外的child routes }); }); Todos.MyTodosRoute = Ember.Route.extend({ // 表明這個route要顯示的model是那個 model: function () { return this.store.find('MyTodo'); } }); // EmberJS的controller預設的route名稱就是Index,因此若直接存取預設的controller那麼根據框架就會去render Index的內容 Todos.MyTodosIndexRoute = Ember.Route.extend({ // 這邊表示index的model就是MyTodos model: function () { return this.modelFor('MyTodos'); } });
現在重新刷一次頁面應該就可以看到我們的清單顯示於頁面中。不過我們還要這個Todo應用可以切換以做完、未做完的顯示。首先還是來調整一下頁面。
<script type="text/x-handlebars" data-template-name="MyTodos"> <!--忽略很多--> <footer id="footer"> <span id="todo-count"> <strong>{{remaining}}</strong> {{inflection}} left </span> <ul id="filters"> <li> {{#link-to "MyTodos.index" activeClass="selected"}}All{{/link-to}} </li> <li> {{#link-to "MyTodos.active" activeClass="selected"}}Active{{/link-to}}<--會打到active這個route> </li> <li> {{#link-to "MyTodos.completed" activeClass="selected"}}Completed{{/link-to}} </li> </ul> <!--忽略很多--> </script>接著調整一下route.js的內容,讓route知道這兩個route分別要呈現什麼東西。
Todos.Router.map(function () { // 當Uri為'/'時去render名稱為「MyTodos」的Template this.resource('MyTodos', { path: '/' }, function () { // 這些route會在MyTodo這個Route之下 this.route('active');// MyTodos.active this.route('completed');// MyTodos.completed }); }); <!--忽略...--> Todos.MyTodosActiveRoute = Ember.Route.extend({ model: function () { return this.store.filter('MyTodo', function (todo) { return !todo.get('isCompleted'); }); }, renderTemplate: function (controller) { //這裡重複使用了既存的Template來render this.render('MyTodos/index', { controller: controller }); } }); Todos.MyTodosCompletedRoute = Ember.Route.extend({ model: function () { return this.store.filter('MyTodo', function (todo) { return todo.get('isCompleted'); }); }, renderTemplate: function (controller) { this.render('MyTodos/index', { controller: controller }); } });現在重新刷一下畫面,應該已經可以切換完成、未完成的項目了。接下來我們新增一個可以清除所有已經完成的項目的功能。還是一樣,首先修改頁面
<footer id="footer"> <!--忽略...--> {{#if hasCompleted}} <button id="clear-completed"> {{action "clearCompleted"}} Clear completed ({{completed}}) </button> {{/if}} </footer>接下來我們要在Controller中新增以下功能
Todos.MyTodosController = Ember.ArrayController.extend({ // 忽略好大一段... // 清空已經完成的項目 clearCompleted: function () { var completed = this.filterBy('isCompleted', true); // emberjs的array api提供的方法 completed.invoke('deleteRecord'); completed.invoke('save'); }, hasCompleted: function () { return this.get('completed') > 0; }.property('completed'), completed: function () { return this.filterBy('isCompleted', true).get('length'); }.property('@each.isCompleted') )};重刷一下畫面後,功能就實做完成了~!但,既然有清除全部已經做完當然也會有全部已做完的功能才是
因此我們再來改一下畫面
<!--忽略...--> <section id="main"> {{outlet}} {{input type="checkbox" id="toggle-all" checked=allAreDone}} </section> <!--忽略...-->
//忽略很多... allAreDone: function (key, value) { if (value === undefined) { return !!this.get('length') && this.isEvery('isCompleted', true); } else { this.setEach('isCompleted', value); this.invoke('save'); return value; } }.property('@each.isCompleted')好~改好之後存好檔,重新刷一下頁面這樣我們的全選功能就算完成了~!
以上這些小功能都完成後,一個簡單的Todo應用的基本能力就實做完成了,剩下的就是資料來源的問題,這就流到下次吧 = =汗
沒有留言:
張貼留言