接下來是要串 隔壁棚的 API XD
從前幾天的 APP 組成
我們所需要的資料大概會是以下幾種:
GET todo list GET http://192.168.1.158:3000/user/kerkerj/todos return: [ { "_id": "54441f64d84f1ea412db855c", "updated_at": "2014-10-19T20:30:28.797Z", "created_at": "2014-10-19T20:30:28.797Z", "content": "task11syy", "user_id": "kerkerj", "__v": 0 }, { "_id": "54441f6fd84f1ea412db855e", "updated_at": "2014-10-19T20:30:39.957Z", "created_at": "2014-10-19T20:30:39.957Z", "content": "task13", "user_id": "kerkerj", "__v": 0 } ] Get a todo task GET http://192.168.1.158:3000/user/kerkerj/todos/54441f64d84f1ea412db855c return: { "_id": "54441f64d84f1ea412db855c", "updated_at": "2014-10-19T20:30:28.797Z", "created_at": "2014-10-19T20:30:28.797Z", "content": "task11syy", "user_id": "kerkerj", "__v": 0 } Add a todo task POST http://192.
Github 參考
不知道大家在用 POSTMAN 對前幾天寫的 API 丟 request 有沒有遇過類似下面的情況:
Cannot GET /user/kerkerj/todoss 通常是丟錯網址時會出現的,或是 code 沒寫好會出現 500 error
這些情況是有辦法接到的,今天我們希望能夠接到後,將 message 轉成 json 格式吐回給 client
因此程式碼如下
app.js
// catch 404 and forward to error handler app.use(function(req, res, next) { var err = new Error('Not Found'); err.status = 404; res.status(404).jsonp({error: "Not Found"}); next(); }); // catch 500 app.use(function(err, req, res, next) { res.status(err.status || 500).json({error: err.message}); }); 基本上這兩段 code 的意思就是加入了兩個 middleware
Github link
(忘了是放在哪個 branch 了 Orz)
接下來就要進到最後一個 Update View 了!
什麼時候會進到 Update View 呢?
是在顯示單筆 TODO 的時候的右上方按鈕:
我們今天只會實作 view 的部分, fakeData 就不實作了
因為接下來就要直接接 API 啦
也不需要更新 fakeData 了 :P
要加入 Edit 這個按鈕
要到 ShowViewController, 加入 UIBarButtonItem
並且讓其吃到一個方法,可以讓 Navigation 往下一個 View 前進:
var id: String! override func viewDidLoad() { super.viewDidLoad() indexLabel.text = "\(index)" contentLabel.text = content self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Edit", style: UIBarButtonItemStyle.Bordered, target: self, action: Selector("editTodo")) } p.s. 先前忘記加了 id, 現在補回來 XD
Github 參考
還記得昨天說要偷懶一下嗎 XD
因為刪除真的很簡單!
我們前面走過了新增、修改、讀取了
刪除?哪有什麼困難的呢! XD
直接看 code 吧!
routes/users.js:
// Delete a todo task router.delete('/:user_id/todos/:todo_id', function(req, res) { var user_id = req.params.user_id; var todo_id = req.params.todo_id; TODO.remove( { _id: todo_id, user_id: user_id }, function (err) { if (err) { res.status(400).json( { error: "delete data error"} ); } else { res.status(201).json( { success: "true" } ); } } ); }); 非常的簡單!
先抓到 user_id, todo_id 後
使用 .remove 的方法,下 WHERE 條件,並在 callback 作處理
Github link
今天要來建立 “新增資料” 的頁面
不過這個頁面我們也會拿來給 “更新資料” 的頁面使用
原因其實很簡單
兩邊要建立或編輯的資料是一樣的
差別只在於,當今天是編輯資料的 view call 該頁面時,
該頁面除了顯示編輯框外,編輯框內的文字也會預先 load 好舊的資料了
除此之外兩個 view 的排版一模一樣
所以在這邊我們就只建立一個 UpdateViewController 就可以了
那我們一樣建立一組 UpdateViewController.swift + UpdateViewController.xib
也一樣為元件建立關聯
回到主頁
我們幫 Add 新增一個按鈕吧
在 viewDidLoad 中
self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Add", style: UIBarButtonItemStyle.Done, target: self, action: Selector("pushToAddTODO")) 設定 Navigation 的右邊鍵的功能
並且根據 pushToAddTODO 的方法做事情
因此繼續下去將 pushToAddTODO 方法做一下
func pushToAddTODO(){ var addViewController = UpdateViewController(nibName: "UpdateViewController", bundle: nil) addViewController.from = "add" self.navigationController?.pushViewController(addViewController, animated: true) } 這樣寫完後就可以執行看看了!
Github 參考
接上篇,我們已經可以拿到 todo list 了
也可以拿到特定的 todo task
再來我們就可以編輯特定的 todo task 了對吧?
不囉唆直接進入程式碼
routes/users.js
// Update a todo task router.put('/:user_id/todos/:todo_id', function(req, res) { var user_id = req.params.user_id; var todo_id = req.params.todo_id; var data = req.body; TODO.update( { _id: todo_id, user_id: user_id }, { $set: { content: data.content } }, function (err, num, raw, results) { if (err) { res.status(400).json( { error: "update data error" } ); } else { TODO.
Github link
延續昨天,接下來要做換頁
因此我們必須先新建立一個 ShowViewController, 以及他的 xib
接著我們在 xib 拉幾個元件: 兩個 label, 一個用來顯示目前的 index, 另一個則是顯示內容
拉好後,將這兩個元件設定連結到 ShowViewController.swift
另外多在 ShowViewController 中放兩個變數
var index: Int! var content: String! 回到 ViewController, 到 tableView didSelectRowAtIndexPath 中
因為 didSelectRowAtIndexPath 的意思就是當 cell 被選取時要做什麼事情
因此當 cell 被選取時,我們就要讓他跳到下一頁,並且是使用 ShowViewController 來顯示資料
因此修改此方法:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { var showViewController = ShowViewController(nibName: "ShowViewController", bundle: nil) showViewController.index = indexPath.row showViewController.content = fakeData[indexPath.row]["content"] // 回復非選取狀態 tableView.deselectRowAtIndexPath(indexPath, animated: true) self.
Github 參考
如果有使用 MongoDB client 的話就可以搭配使用會比較有感覺
Mac 我是使用 Robomongo,算很好上手~
今天要來實作讀取的部分
讀取有分兩種,一種是讀取 list
另一種是讀取特定某個 todo task,今天兩種都會實作
首先我們先實作 get todo list
因為若要拿到特定的 todo task,需要 todo task 的 id
而我們現在還不曉得 todo task 的 id 是多少,我們只知道 user_id
因此就先從 list 下手
routes/users.js:
// Get todo list router.get('/:user_id/todos', function(req, res) { var user_id = req.params.user_id; TODO.find( {user_id: user_id}, function (err, results) { if (err) { res.status(400).json( { error: "can not find data" } ); } else { res.
Github link
接著我們要讓主頁顯示一些假資料:
由於我們未來接的 api 的資料會是 todo_id + content
因此我們先產生一個 dictionary array 來存放我們的假資料
var fakeData = [[String:String]]() fakeData = [ ["id": "1", "content": "A"], ["id": "2", "content": "B"], ["id": "3", "content": "C"], ] 再來對主頁的 controller 新增 tableView 上去
並且對 UITableView 加入 delegate 以及 datasource
import UIKit class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate { var fakeData = [[String:String]]() var tableView: UITableView? override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib.
Github 參考
昨天我們了解了如何拿 url params 以及 request data
今天我們就來使用他,對資料庫做存取
由於使用到資料庫,因此我們要加入資料庫的 driver
我們用的是 mongoose 套件
app.js:
// 在最上方加入 var mongoose = require('mongoose'); // 在某個地方連接資料庫 var db_uri = "mongodb://192.168.33.10:27017/TODOs"; mongoose.connect(db_uri); 在這邊我是使用了虛擬機的 DB,因此是 mongodb://192.168.33.10:27017/TODOs
DB 的名稱為 TODOs
這樣在程式一跑起來時,就會連接資料庫了!
再來我們就要設定在對資料庫做 CRUD 時,所需要做的事情
首先我們先要定義 schema,
雖然 mongodb 是 schema-free,但是官方文件也有提到最好還是有固定的 schema 避免記憶體 allocate 時出現問題,而程式撰寫時邏輯也不會因此而過於複雜
這時候我們就需要 model 資料夾了,在 model 資料夾中新增一個 todos.js
裡面要放的就是 todo task 的 schema
內容如下:
models/todos.js:
'use strict'; var mongoose = require('mongoose'); // Define our todo schema var TODOschema = new mongoose.