国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 網站 > WEB開發 > 正文

Ember Model

2024-04-27 15:07:43
字體:
來源:轉載
供稿:網友

model是指數據層,也就是一個用于向用戶展示的數據對象。考慮到前后端分離,其實可以認為展現內容與后端的DTO對象或者DVO對象是一一對應的。同時,model會通過json的形式以http請求的方式與服務器進行交互。但是,model的形式不一定是json的,其他的形式都是可以的。也就是說,model是持久化的。

這種方式下,ember本身提供了許多api,這也就是Ember data做的事情。Ember Data為你提供了更加簡便的方式操作數據,統一管理數據的加載,降低程序復雜度。

Ember Data有幾個重要的概念,分別為:modelsrecordsadaptersstoreserializer.

models

個人認為,model這個類,應該和后端的DO或者是DTO對象是一一對應的。 model的定義,可以通過命令行方式: ember g model <your-model-name> 則會創建一個app/models/<your-model-name>.js的文件。其中就是model的主體,由若干個屬性構成,如:

export default DS.Model.extend({ title: DS.attr('string'), // 字符串類型 flag: DS.attr('boolean'), // 布爾類型 timestamp: DS.attr('number'), // 數字類型 birth: DS.attr('date'), //日期類型 addr: DS.attr(), //json類型,其實就是string});

這里需要注意,沒有id字段,Ember 會默認生成id屬性。 如果有對應關系的話,比如一對多或者多對一的情況,那么可以使用Ember Data中的hasMany 以及 belongsTo方法。belongsTo為一對一關系,hasMany為一對多關系。使用方式如下

import DS from 'ember-data';//app/models/blog-post.jsexport default DS.Model.extend({ comments: DS.hasMany('comment')});//app/models/commont.jsexport default DS.Model.extend({ blogPost: DS.belongsTo('blog-post')});

如果是多對多的關系,則如下就好:

import DS from 'ember-data';//app/models/blog-post.jsexport default DS.Model.extend({ comments: DS.hasMany('comment')});//app/models/commont.jsexport default DS.Model.extend({ blogPost: DS.hasMany('blog-post')});

這個對應關系,可以看做為,實際的邏輯表之間的對應關系。

此外,還可以添加計算屬性,因為,model也是一個Ember Object

export default DS.Model.extend({ title: DS.attr('string'), // 字符串類型 flag: DS.attr('boolean'), // 布爾類型 tf: Ember.computed('title', 'flag', function() { return `${this.get('title')} ${this.get('flag')}`; })});

store & record

store這個概念,在Ember Data中十分重要。 store是指所有的從服務端活動的record的數據以及新創建的record數據。即,store為所有數據的緩存,所有關于record的增刪改查動作,都需要經過store。

一般情況下,一個應用,只有一個DS.store,它是由Ember.application初始化的。

record是指一個model的實例,他可能是一個從服務端返回的數據,當然,你自己也可以新建一個record。

假設我們有一個route:

// app/routes/store-route.jsimport Ember from 'ember';export default Ember.Route.extend({ model: function() { }});

store 這個概念,可以在route以及controller中使用。形如this.get('store') 或者 this.store

查詢record

(1)store.findRecord() 通過model的type以及id,發起一個請求,去獲取數據,他返回一個PRomise對象,結果為record。

model(){ return this.store.findRecord('model-example',1).then((data) => { return data; }); //get請求為 域名/model-examples/1, 例如 http://localhost:4200/model-examples/1}

(2)store.peekRecord(), 通過model的type以及id,不發起一個請求,從store中去獲取現有以加載的數據。

model(){ return this.store.peekRecord('model-example',1); //無請求}

(3)store.findAll(), 通過model的type獲取所有的數據,發起請求,返回的為,DS.PromiseArray對象,結果為DS.RecordArray

model(){ return this.store.findAll('model-example').then((data)=>{return data}); //get請求為 域名/model-examples, 例如 http://localhost:4200/model-examples}

(4)store.peekAll(), 通過model的type獲取所有的數據,不發起請求,從store中去獲取現有以加載的數據,返回的為DS.RecordArray

model(){ this.store.findAll('model-example'); //無請求}

這里需要注意,DS.RecordArray,并不是一個[]它使一個可遍歷的對象。這意味著,如果你在模板中,使用了這些reocrd,那么就可以享受到雙向綁定的好處,同時,也提供了一些API,能夠幫助你更方便的使用。具體可參考:Ember.js DS.Store

(5)store.query()條件查詢,查詢條件為type以及自定義條件,同樣也是一個get請求,返回結果通store.findAll()

model(){ this.store.query('model-example',{firstName:'James'}); //get 請求,請求為 域名/model-examples?firstName=James,例如,http://localhost:4200/model-examples?firstName=James}

(6)store.queryRecord()條件查詢,查詢條件為type以及自定義條件,同樣也是一個get請求,返回結果同store.findRecord()

model(){ this.store.queryRecord('model-example',{firstName:'James'}); //get 請求,請求為 域名/model-examples?firstName=James,例如,http://localhost:4200/model-examples?firstName=James,返回結果為promise,其中為一個record}

創建record

使用store.createRecord()來增加一個record。

model(){ let a = this.store.createRecord('model-example',{ firstName:'firstName', secondName: 'secondName' }); return a;}

則返回一個record。

在運用場景上,我們可以設想這樣一個場景,比如一個表單:

//route route-example.hbs<form class="" action="index.html" method="post"> firstName:{{input value=model.firstName}} secondName:{{input value=model.secondName}} <button type="submit" name="button" {{action 'submitForm'}}>提交</button></form>//route route-example.jsimport Ember from 'ember';export default Ember.Route.extend({ model(){ return this.store.createRecord('model-example',{ firstName:'', secondName: '' }); }, actions:{ actionSubmit(){ let model = this.modelFor('route-example'); model.save(); //這里會發出一個post請求,即 域名/model-example, 這里是localhost:8000/model-example,參數為{"data":{"attributes":{"first-name":"<你填寫的內容>","second-name":"<你填寫的內容>"},"type":"model-examples"}} } }});

生成的頁面如下: 這里寫圖片描述

這的數據是一個雙向綁定的過程,在頁面上的變動會直接變化到model上。

更新record

更新record的操作也是一樣的

this.store.findRecord('model-example', 1).then(function(data) { data.set('firstName', "name1");});

這樣就可以對其進行修改。

持久化record

持久化,也就是說將數據存入數據庫,實際上是一個與后端進行交互的過程。 調用sava()方法就可以。 但是不同于新建的post請求,所有更新操作的請求為PATCH請求。

this.store.findRecord('model-example', 1).then(function(data) { data.set('firstName', "name1"); data.save() //patch 請求:域名/model-examples/1, 在這里為:http://localhost:4200/model-examples/1 //參數 {"data":{"id":"1","attributes":{"firstName":"asdas","secondName":"sn"},"type":"model-examples"}}});

刪除record

使用deleteRecord()可以刪除一個record

this.store.findRecord('model-example', 1).then(function(data) { data.deleteRecord(); data.get('isDeleted');//true =>表示已經刪除});

如果想要持久化到后端,調用sava()

this.store.findRecord('model-example', 1).then(function(data) { data.deleteRecord(); data.get('isDeleted');//true =>表示已經刪除 data.save();//這會發送一個DELETE請求,為 http://localhost:4200/model-examples/1});

或者直接調用

this.store.findRecord('model-example', 1).then(function(data) { data.destroyRecord();//這會發送一個DELETE請求,為 http://localhost:4200/model-examples/1});

插入record

ember還支持直接向store中插入record,但是這個過程不是與后端交互的過程。是通過push()方法實現的。

//route route-example.jsexport default Ember.Route.extend({ model() { this.get('store').push({ data: [{ id: 1, type: 'model-example', attributes: { firstName: 'fn1', secondName: 'sn1', }, }, { id: 1, type: 'model-example', attributes: { firstName: 'fn1', secondName: 'sn1', }, }] }); }});

這樣就可以手動向其中插入兩條record。例如,當時不想用他提供的方式如post、patch、delete進行增刪改數據,那么可以使用Ajax先更新或者插入數據,然后在手動push進store。

小結

總結一下增刪改查的請求形式: //TODO

adapters

適配器,決定了數據如何持久化到后端。舉例而言,請求的URL、REST API的header等。 創建適配器的命令,同樣通過命令行就可以創建:ember g adapter <your-adapter-name>。這里注意,這里的名字必須和路由的是一致的,關于路由的規則,我們后面獨立說。 以application這個路由為例,其適配器配置可能為:

//app/adapters/application.jsimport DS from 'ember-data';export default DS.JSONAPIAdapter.extend({ host: 'http://xxx.com', namespace: 'api/v1', pathForType: function(type) { return Ember.String.underscore(type); }, headers: { 'API_KEY': 'secret key', 'ANOTHER_HEADER': 'Some header value' }});

下面解釋一下這幾個常用規則的配置:

host,指域名namespace,命名空間,如上述的情況下,model名為model-example的新建請求為(忽略pathForType方法):http://xxx.com/api/v1/model-examplepathForType,修改model的適配方式,如果你希望都是下劃線的方式,可以調用Ember.String.underscore()方法,就可以把駝峰或者中劃線改為下劃線,那么上述的情況下,新建的請求為:http://xxx.com/api/v1/model_exampleheaders,http的heads,這里是支持計算屬性的,例如:export default DS.JSONAPIAdapter.extend({ session: Ember.inject.service('session'), headers: Ember.computed('session.authToken', function() { return { 'API_KEY': this.get('session.authToken'),//這里的headers取自session的authToken字段 'ANOTHER_HEADER': 'Some header value' }; })});

在適配器中,你還可以重寫函數findRecord() findAll……等等:

export default DS.JSONAPIAdapter.extend({ findRecord(store, type, id){ return Ember.$.getJson(`${this.get('host')}/${this.get('namespace')}/${type}/${id}`); }});

序列化器serializers

序列化器serializers主要負責用來格式化數據。這個在Ember Data中十分重要,因為本身model的數據格式十分蛋疼,用起來非常難受。

創建serializers,也可以是命令行工具:ember g serializer <your-serializer-name>

Ember Data提供了3種serializers的默認實現,分別為:

JSONAPISerializer,2.0以后版本的默認實現JSONSerializer 針對單個json或者json array的簡單實現RESTSerializer2.0以前版本的默認實現,較為復雜,可以支持邊緣加載,即是通過增加數據層級來分步加載(可以理解為先加載第一層次的數據集合,然后按需加載子一級的數據集合)

這意味著,根據自己的需求,繼承其中任意一個類就可以。

現在考慮標準格式的record:

//單條record{ "data": { "type": "people", "id": "123", "attributes": { "first-name": "Jeff", "last-name": "Atwood" } }}//recordArray{ "data": [{ "type": "model-example", "id": "1", "attributes": { "firstName": "Jeff", "secondName": "Atwood" } }, { "type": "model-example", "id": "2", "attributes": { "firstName": "Yehuda", "secondName": "Katz" } }]}//如果數據除了本身之外還有關系數據,那么關系數據就放在`included`中{ "data": { "type": "articles", "id": "1", "attributes": { "title": "JSON API paints my bikeshed!" }, "links": { "self": "http://example.com/articles/1" }, "relationshxml better" }, "links": { "self": "http://example.com/comments/12" } }]}

我們從簡單的情況入手,比如,正常情況下,我們的后端返回的數據格式可能為:

{ "result":[ { "id": 1, "firstName": "Jeff", "secondName": "Atwood" }, { "id": 1, "firstName": "Yehuda", "secondName": "Katz" } ]}

這種情況下,如果返回的話,前端一定會報錯,因為格式不匹配,找不到data

格式化內容數據

import DS from 'ember-data';export default DS.JSONAPISerializer.extend({ normalizeResponse(store, primaryModelClass, payload, id, requestType) { if (payload) { if (!payload.result){ let documentHash = {included:[]}; if(id) documentHash.data=null; else documentHash.data=[]; return documentHash; } return this._super(store, primaryModelClass, payload.result, id, requestType); } return this._super(...arguments); },});

這樣,就可以將返回的result轉化為data

反之,如果請求中,后端需要的內容與前端給的不一樣,只需要重寫serialize方法:

import DS from 'ember-data';export default DS.JSONSerializer.extend({ serialize: function(snapshot, options) { var json = this._super(...arguments); // ?? json.data.attributes.cost = { amount: json.data.attributes.amount, currency: json.data.attributes.currency }; delete json.data.attributes.amount; delete json.data.attributes.currency; return json; }});

通過上述的方式,可以把前端發送的內容:

{ "data": { "attributes": { "id": "1", "name": "My Product", "amount": 100, "currency": "SEK" }, "type": "product" }}

變為:

{ "data": { "attributes": { "id": "1", "name": "My Product", "cost": { "amount": 100, "currency": "SEK" } }, "type": "product" }}

最后說兩句,RESTSerializer的實現與其他兩個不同,他沒有規定返回的格式,也就是說可以是任意格式的,而其他的都是json。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 淳安县| 信丰县| 黎川县| 右玉县| 普格县| 高安市| 桦甸市| 凤冈县| 新和县| 平定县| 南平市| 上犹县| 衢州市| 滦平县| 沙湾县| 邳州市| 白沙| 石泉县| 临清市| 长子县| 汤原县| 晋州市| 三亚市| 历史| 邵阳市| 横峰县| 噶尔县| 抚远县| 西宁市| 澄迈县| 内乡县| 巴塘县| 呼玛县| 繁昌县| 清徐县| 凯里市| 若尔盖县| 高淳县| 福鼎市| 苍溪县| 略阳县|