iT邦幫忙

3

[Javascript] Backbone.js (二) Model

  • 分享至 

  • xImage
  •  

延續上一篇 [Javascript] Backbone.js (一) Hello backbone
http://design2u.me/blog/956/javascript-backbone-js-a-hello-backbone

本篇來談談 Backbone 當中的 Model

在 MVC 的架構當中,Model 通常被當成資料的容器,在 backbone 當中也不例外,Model 可以承載所有頁面當中常取用的資料,或是 server 回傳的資料等

特別的是,Backbone 當中的 View 採用了 Observer Pattern 的設計,當使用者改變 Model 的值時,對應的事件會被 Trigger,而達成 UI 自動更新或是 Ajax 自動啟動等
宣告 Model

Model 是用來存放資料的類別,可供 Backbone 的其他類別進行資料的取用,以下程式碼可以宣告一個簡單的 Model :

//Backbone Model
var user = new Backbone.Model({
firstName: "Jack",
lastName: "divaka"
});

或是你也可以宣告一個 JSON 物件在 Model 當中:

//Backbone Model
model = new Backbone.Model({
data:[
{ text: "Google", href: "http://google.com" },
{ text: "Facebook", href: "http://facebook.com" },
{ text: "Youtube", href: "http://youtube.com" }
]
});

取得 Model 資料

如果只是很單純的 Model,只要用逗點即可取得 Model 內容

//較單純的 Model
var user = new Backbone.Model({
firstName: "Jack",
lastName: "divaka"
});

//取得 Model 項目
document.write(user.get("firstName"));
document.write("<hr>");
document.write(user.get("lastName"));

如果是裡面有一個 Array,則需要靠遞迴將資料取出

//裡面有 json obj 的 Model
jsonModel = new Backbone.Model({
data:[
{ item: "item1", href: "1.jsp" },
{ item: "item2", href: "2.jsp" }
]
});

//取得 Model 項目 (JSON 物件版) - 需要用到遞迴
for(i=0;i<jsonModel.get("data").length;i++){
document.write("<hr>");
document.write(jsonModel.get("data")[i].item);
document.write("│");
document.write(jsonModel.get("data")[i].href);
}

以上可到 jsfiddle 玩玩看
http://jsfiddle.net/divaka/Xnhhn/1/light/

新增 Model 資料

如果要新增一筆值,可以用 set 的指令,直接塞進一筆值:

//initial var
var user = new Backbone.Model({
firstName: "Jack",
lastName: "divaka"
});

// add data
user.set({birthday: "oct. 1, 1985"});

較複雜的也可以直接把整個 array 物件新增進 Model 當中:

//Backbone Model
APPListModel = new Backbone.Model({
data:[
{ item: "item1", href: "1.jsp" },
{ item: "item2", href: "2.jsp" }
]
});

// data
var x = [
{ item: "item3", href: "3.jsp" }
];

//insert data
APPListModel.set({data:x});

刪除 Model 資料

基本的 attribute 可用 unset 方法來移除:

//initial var
var user = new Backbone.Model({
firstName: "Jack",
lastName: "divaka"
});

// add data
user.set({birthday: "oct. 1, 1985"});
user.unset("firstName");
user.unset("lastName");

// print model result
alert(JSON.stringify(user));

如果是裡面有複雜的 JSON 物件,則可利用遞迴條件清除某筆資料,或是用 unset 直接拿掉某個子元素

此範例有 JSfiddle demo:http://jsfiddle.net/divaka/5Kacs/6/

//initial model 1
var user = new Backbone.Model({
firstName: "Jack",
lastName: "divaka"
});

// reset data
user.set({birthday: "oct. 1, 1985"});
user.unset("firstName");
user.unset("lastName");

// print model result
document.write("基本:"+JSON.stringify(user));
document.write("<hr>");

////////////////////////////////////////////////////////////

//Backbone Model
m = new Backbone.Model({
data:[
{ text: "Google", href: "http://google.com" },
{ text: "Facebook", href: "http://facebook.com" },
{ text: "Youtube", href: "http://youtube.com" }
]
});

//拿掉其中一筆值
var a = m.get("data");
for(i=0;i<a.length;i++){
var b = a[i].text;
if(b=="Facebook"){
a.splice(i,1);
}
}
document.write("拿掉陣列:"+JSON.stringify(m));
document.write("<hr>");

// 清空整個 model
m.unset("data");
document.write("拿掉整個model"+JSON.stringify(m));
document.write("<hr>");​

設定 Model 更新事件監聽

Model 可以綁定 change event ,當 model 的資料改變時,自動執行某些程式碼

例如:

// binding event
APPListModel.bind('change:data',function(){
alert("event fired");
});

或是你也可以設定 model 更新時,自動呼叫 (callback) 某個函式:

// binding event
APPListModel.bind('change:data',function(){
updateContainer(APPListModel );
});

動態設定 Model 的值

官方的範例有一個是可以動態設定 Model 內容的,以下的 code 可以詢問使用者一個顏色,並動態將 color 設定進 Model 裡面,更新成背景的顏色。

var BodyColor= Backbone.Model.extend({
promptColor: function() {
var cssColor = prompt("Please enter a CSS color:");
this.set({color: cssColor});
}
});

window.bg= new BodyColor;

bg.on('change:color', function(model, color) {
$('body').css({background: color});
});

bg.set({color: 'white'});

bg.promptColor();​

也可以玩看看 jsFiddle 的範例
http://jsfiddle.net/divaka/7Atjf/light/

Model Extend (繼承)

backbone 的 Model 也可以讓你自訂 class,但是一定要從原本的 backbone model 繼承
如果要 override 一些 class 屬性,則需要利用以下語法,將自訂的 property 傳進去

var MyModelClass=Backbone.Model.extend(properties)

以下範例宣告了一個 Model instance,並繼承自訂的 Model 類別

//自訂 Backbone Model 類別
window.Item = Backbone.Model.extend({

//起始化
initialize:function(){
document.write("instance is initialized");
document.write("<hr>");
},

//自訂類別成員
intro:"This is a backbone model instance"

});

//用自訂類別宣告一個實體
var item = new Item();

//呼叫類別成員
document.write(item.intro);
document.write("<hr>");

//設定 Model 的屬性
item.set("anotherAttr","新增的屬性");
document.write(item.get("anotherAttr"));
document.write("<hr>");

jsFiddle 如下:
http://jsfiddle.net/divaka/Kbkvs/1/light/

Model 與 UI 互動完整範例

以下程式碼建立一個簡單的 Model 與 View 互動範例,目標達成:

(1) Model 初始就有資料
(2) 註冊一個 Button,設定當 Button 點擊時,新增某個 Model data
(3) 註冊另一個 Button,設定當 Button 點擊時,刪除 Model data
(4) 當 Model data 改變時,View 就會自動 ajax 更新

以下介紹其程式碼

HTML 部份

html 這邊只設定了三個 Button ,然後在最後面安排一個 container 來放內容

<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.3.1/underscore-min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/backbone.js/0.9.2/backbone-min.js"></script>

<button id="triggerAddEvent">新增 item3</button>
<button id="triggerDeleteEvent">刪除 item3</button>
<button id="triggerDeletelastItemEvent">刪除最後一個 item</button>

<div id="container"></div>

JS 部份

JS 部份在一開始先建立了一個 itemModel,做為整體內容容器
設定了一個 updateContainer 的 function,負責重繪 UI
畫面當中則安排了三個按鈕

(1) 第一個是新增一個 item3
(2) 第二個是移除一個 item3
(3) 第三個是移除 model 裡面的最後一個 element

由於以下程式碼已經替 itemModel binding 一個「change」的事件,所以當 model 內容改變,就會呼叫 updateContainer function

itemModel.bind(‘change:data’,function(){
updateContainer(this);
});

至於 Model 元素的新增與刪除,似忽沒有既有方法可以使用 (如果讀者知道麻煩告訴我一下 ! 謝謝)所以我設定了一個 temp 的物件,然後用 temp.push(x); 加入一筆

資料,或是設定條件,用來裝每次 loop 過濾所要留下來的元素,以完成 remove element 的實做

最後,則呼叫 itemModel.set({ data:temp }); ,用 temp 取代原本的 Model 內容
並自動呼叫 updateContainer 以完成 UI 的重繪

這邊有 jsfiddle 的 demo:http://jsfiddle.net/divaka/qcG5J/4/

以下為 JS 的程式碼:

// Model
itemModel = new Backbone.Model({
data:[
{ item: "item1"},
{ item: "item2"}
]
});

// 先 update 一次
updateContainer(itemModel);

// binding event
itemModel.bind('change:data',function(){
updateContainer(this);
});

// trigger add event
$("#triggerAddEvent").click(function(){

// new data
var x = { item: "item3"};

var temp = [];
var data = itemModel.get("data");
for(i=0;i<data.length;i++){
temp.push(data[i]);
}

// import the new data
temp.push(x);

// set the new data
itemModel.set({ data:temp });

});

// trigger delete event
$("#triggerDeleteEvent").click(function(){

//delete a data
var temp=[];
var data = itemModel.get("data");
for(i=0;i<data.length;i++){
var b = data[i].item;

//刪除條件
if(b!="item3"){
temp.push(data[i]);
}
}

// set the new data
itemModel.set({ data:temp });

});

// trigger delete the last item event
$("#triggerDeletelastItemEvent").click(function(){

//delete a data
var temp=[];
var data = itemModel.get("data");
for(i=0;i<data.length;i++){

//刪除條件
if(i!=data.length-1){
temp.push(data[i]);
}
}

// set the new data
itemModel.set({ data:temp });

});

//更新顯示
function updateContainer(model){

//empty container
$("#container").html("");

//re-render UI
var data = model.get('data');
for (var i=0, l=data.length; i<l; i++) {
$("#container").append(data[i].item+" , ");
}

}

備註

ps. 因為上稿系統似乎有點問題,我的程式碼如果用 code tag 包起來的話,送出之後會亂掉,所以本篇文章就不用 code tag 包起來,如果要看更完整的排版的文章,歡迎到我的 blog 觀看。
Blog 連結:http://design2u.me/blog


圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

2 則留言

0
ted99tw
iT邦高手 1 級 ‧ 2012-07-27 13:25:58

衝刺趕快拿有kitty圖樣的筆記簿記下來先~~衝刺

0
timloo
iT邦研究生 2 級 ‧ 2012-07-30 08:04:54

看了幾遍,請問篇名tse是指什麼意思呢?

divaka iT邦新手 5 級 ‧ 2012-07-30 09:26:29 檢舉

Dear timloo :

sorry, 因為一直上稿失敗,結果後來都在測試到底怎樣的內容才能上稿成功,索興先把文章標題隨便打,感謝您的提醒,已修正標題。

我要留言

立即登入留言