資料點

在 Web 應用程式中以 Knockout.js 進行 OData 資料繫結

Julie Lerman

下載代碼示例

Julie Lerman
作為資料 geek,我花很多時間寫後端代碼和錯過上有很多樂趣在用戶端上的東西。約翰 · 爸爸,用筆此列,現在用戶端技術為這本雜誌,寫一個專欄,他已做了很多工作的一種稱為 Knockout.js 的熱新用戶端的技術。由於爸爸和別人表達有關 Knockout.js 的激情,我跳在演示文稿的報價上挖空在我的本地使用者組,VTdotNET,通過從喬恩 · 霍 MyWebGrocer.com。會議吸引了一大群比我們通常所得到的並包括從外面.net 社區開發。隨著霍半工半讀念完演示文稿,它變成了我為什麼這麼多的 Web 開發人員引誘挖空效果明顯:通過利用該模型-視圖-ViewModel (MVVM) 模式,它簡化了 Web 應用程式中的用戶端的資料繫結。資料繫結...現在,這也是我能做的資料 !第二天我已經學習如何與資料訪問織 Knockout.js — — 和現在我可以和你分享我的發現。

我應該提供公平的警告,指出我的 JavaScript 技能非常缺乏,因此這花了我更長時間去工作,而它應該有。然而,我猜許多你們閱讀此專欄的人都在同一條船上,所以你可能欣賞我嬰兒學步。您可以獲得挖空更深入地理解爸爸的列,以及他優秀的課程從 Pluralsight.com

我的目標是要看看如何我可以使用 Knockout.js 來綁定到,然後更新從 WCF 資料服務中檢索資料。在這篇文章我要做的是顯示您的關鍵工作部件。然後,您可以看到如何他們都適合一起陪同下載示例。

我開始與現有的 WCF 的資料服務。事實上,這是我在我 2011 年 12 月的資料點的列中,"處理實體架構驗證的 WCF 資料服務"中使用相同的服務 (msdn.microsoft.com/magazine/hh580732),而我現在更新到最近公佈的 WCF 資料服務 5。

作為提醒,我的演示潔具模型組成單個類:

public class Person
{
  public int PersonId { get; set; }
  [MaxLength(10)]
  public string IdentityCardNumber { get; set; }
  public string FirstName { get; set; }
  [Required]
  public string LastName { get; set; }
}

DbCoNtext 類暴露在 DbSet 中的人類:

public class PersonModelContext : DbContext
{
  public DbSet<Person> People { get; set; }
}

資料服務然後暴露,用於讀取和寫入的 DbSet:

public class DataService : DataService<PersonModelContext>
{
  public static void InitializeService(DataServiceConfiguration config)
  {
    config.SetEntitySetAccessRule("People", EntitySetRights.All);
  }
}

Knockout.js,使用用戶端腳本可以回應的資料繫結物件的屬性值的變化。例如,如果您在您的腳本中調用挖空 applyBindings 方法,傳遞一個物件,在挖空將警告對該物件的屬性更新的任何資料繫結元素。您可以實現類似的行為,對於挖空看著他們獲取或快顯項目的集合。所有這一切都發生在用戶端無需編寫任何事件處理腳本或返回到伺服器以獲取説明。

有一些我不得不執行實現我的目標的任務:

  • 創建挖空注意查看模型。
  • 獲取 OData JSON 格式。
  • 將 OData 結果移到我的視圖模型物件。
  • 將 Knockout.js 的資料繫結。
  • 對於更新,進入查看模型值回 OData 結果物件。

創建挖空注意查看模型

這項工作的順序,挖空需要,以便能夠"遵守"該物件的屬性。您可以啟用此使用挖空,當您在您的物件中定義的屬性。但等待 !我不說你"髒了"您的域物件與特定于使用者介面的邏輯這樣的挖空效果可以觀察值的更改。這是 MVVM 模式是哪裡來。MVVM 允許您創建特定于使用者介面的版本 (或視圖) 你的模型 — — 這就是 MVVM,VM (ViewModel)。這意味著可以將您的資料拉入您的應用程式中,但是您喜歡 (查詢針對 WCF 資料服務,打一項服務或甚至通過新的 Web API),然後改變形狀對齊到視圖的結果。例如,我的資料服務返回的名字、 姓氏和 IdentityCard 人類型。但在我看來,我只是對名字和姓氏感興趣。您甚至可以應用您的物件的視圖模型版本中的特定視圖的邏輯。這為您提供了兩個領域的最佳產品:你到你的觀點,而不考慮資料來源的提供專門針對的物件。

這裡是我已經在 JavaScript 物件中定義的用戶端的 PersonViewModel:

function PersonViewModel(model) {
  model = model || {};
  var self = this;
  self.FirstName = ko.observable(model.FirstName || ' ');
  self.LastName = ko.observable(model.LastName || ' ');
}

無論什麼從服務,返回只想在我的視圖中使用的第一個和最後一個名稱,所以這些都是唯一的屬性包含。 請注意不定義名稱作為字串,但作為挖空可觀察到的物件。 這是重要的是要牢記時設置值,正如您看到的進一步研究。

JSON 格式獲取 OData

我將使用的 OData 查詢只是將來自資料服務返回的第一人。 目前,這來自我發展的伺服器:

HTTP://localhost:43447/DataService.svc/People?$top=1

預設情況下,OData 結果返回作為原子 (這使用 XML 表示)。 Knockout.js 與 JSON 資料,不過,其中 OData 也可以提供工作。 因此,我直接在 JavaScript 中工作,因為它是 JSON 結果會比用 XML 處理簡單得多。 在 JavaScript 請求中,可以將參數追加到 OData 查詢指定為 JSON 返回的結果:"$ 格式 = json。"但這需要您特定的資料服務知道如何處理格式的查詢選項。 我不會。 如果我想要走這條路 — — 例如,如果我使用 AJAX,使我的 OData 電話 — — 我不得不在我的服務中使用擴展以支援 JSON 輸出 (請參見 bit.ly/mtzpN4 的詳細資訊)。

然而,因為我使用的 OData 的 datajs 工具組 (datajs.codeplex.com),我不需要與此有關。 該工具組的預設行為是將自動添加到請求的標頭資訊,這樣,他們就會返回 JSON 的結果。 所以我不需要將 JSONP 副檔名添加到我的資料服務。 來自 datajs 工具組的 OData 物件有一個讀的方法,使您可以執行一個查詢,其結果將是 JSON 格式:

OData.read({
  requestUri: http://localhost:43447/DataService.svc/People?$top=1"
  })

推入 PersonViewModel 的 OData

一旦被返回的結果 — — 在我一個人的情況中,鍵入按照我的域模型的定義 — — 我然後想要從結果創建一個 PersonViewModel 實例。 我的 JavaScript 方法,personToViewModel,需要一個人物件從其值創建新的 PersonViewModel、 然後返回 PersonViewModel:

function personToViewModel(person) {
  var vm=new PersonViewModel;
  vm.FirstName(person.FirstName);
  vm.LastName(person.LastName);
  return vm;
}

請注意我通過在新的值中傳遞,仿佛屬性的方法設置值。最初,我設置使用 vm 的值。名字 = 人。名字。但是,變成名字字串,而不是相當可觀的。我掙扎了一會兒,想看看自己為什麼挖空不是後續更改為的值,並注意到最後不得不屈服並尋求説明。屬性是函數,不是字串,所以您需要將它們設置使用方法語法。

我想要在查詢回應中運行 personToViewModel。這是可能的因為 OData.read,可以告訴它什麼已成功執行查詢時要使用的回檔方法。到一個稱為 mapResultsToViewModel,其中,反過來,調用 personToViewModel 方法在這種情況下,就會通過結果 (請參見圖 1)。預其它地方在解決方案中,我已經定義的 peopleFeed 變數為"HTTP://localhost:43447/DataService.svc/People"。

圖 1 執行查詢和處理回應

OData.read({
  requestUri: peopleFeed + "?$top=1"
  },
  function (data, response) {
    mapResultsToViewModel(data.results);
  },
  function (err) {
    alert("Error occurred " + err.message);
  });
  function mapResultsToViewModel(results) {
    person = results[0];
    vm = personToViewModel(person)
    ko.applyBindings(vm);
}

綁定到 HTML 控制項

請注意 mapResultsToViewModel 方法中的代碼:ko.applyBindings(vm)。 這是挖空的工作原理的另一個重要方面。 但什麼我申請到綁定? 這就是我在我的標記中將詳細的說明。 在我的標記代碼中,我使用挖空的資料繫結屬性將從我 PersonViewModel 的值綁定到一些輸入元素:

<body>
  <input data-bind="value: FirstName"></input>
  <input data-bind="value: LastName"></input>
  <input id="save" type="button" value="Save" onclick="save();"></input>
</body>

如果我只想要顯示的資料,可以使用標籤的元素,而不是資料繫結的值,可以綁定到的文本的。 範例:

<label data-bind="text: FirstName"></label>

但我想要編輯,所以我不只使用的輸入的元素。我挖空資料繫結還指定了我綁定到這些屬性的值。

向我的解決方案提供的挖空效果的關鍵因素是我查看模型中的可觀察到的屬性,我標記的元素,並添加了挖空,通知這些元素屬性值更改時所需的運行時邏輯的 applyBindings 方法的資料繫結屬性。

如果我跑到目前為止我有應用程式中,我可以看到在偵錯模式中,查詢所返回的人,如中所示圖 2

Person Data from the OData Service
圖 2 人資料從 OData 服務

圖 3 顯示在頁面上顯示的 PersonViewModel 屬性值。

The PersonViewModel Object Bound to Input Controls
圖 3 PersonViewModel 物件綁定到的輸入控制項

保存回資料庫

由於挖空,當要保存的時候我不需要提取的輸入元素的值。挖空已更新的 PersonViewModel 物件,被綁定到表單。在我保存方法我來推的 PersonViewModel 值回人物件 (即來自該服務),然後保存這些更改返回到該資料庫以我的服務方式。我保持最初從 OData 查詢返回的人實例和我在這裡使用的相同的物件,您將看到代碼下載中。一旦用 viewModeltoPerson 方法更新的人,我可以然後將它傳遞到 OData.request 作為一個請求的物件,如中所示圖 4。請求物件是第一個參數,並包括該 URI、 方法和資料。看一看在 datajs 檔 bit.ly/FPTkZ5 瞭解更多關於請求方法。請注意我我利用人實例的 __metadata.uri 屬性中存儲的 URI,它綁定到的事實。使用該屬性,我不會有硬編碼 URI,這是"HTTP://localhost:43447/DataService.svc/People(1)"。

圖 4 將更改保存回資料庫

function save() {
  viewModeltoPerson(vm, person);
  OData.request(
    {
      requestUri: person.__metadata.uri,
      method: "PUT",
      data: person
    },
    success,
    saveError
    );
  }
  function success(data, response) {
    alert("Saved");
  }
  function saveError(error) {
    alert("Error occurred " + error.message);
  }
}
function viewModeltoPerson(vm,person) {
  person.FirstName = vm.FirstName();
  person.LastName = vm.LastName();
}

現在當我修改的資料 — — 通過朱莉,例如更改朱麗婭 — — 並點擊保存按鈕,不僅做得到"保存"警報,指示沒有錯誤發生,但我可以看到我事件探測器中更新的資料庫:

    exec sp_executesql N'update [dbo].[People]
    set [FirstName] = @0
    where ([PersonId] = @1)
    ',N'@0 nvarchar(max) ,@1 int',@0=N'Julie',@1=1

Knockout.js 和群眾 WCF 資料服務

探索 Knockout.js 推我學會一些新的工具,可由任何條帶化,而不僅僅是在.net 平臺的開發人員使用。 並且雖然它並未強迫我行使有些生銹的 JavaScript 技能,我寫的代碼集中的物件操作熟悉任務而不是與控制項進行交互的苦差事。 這也讓我下建築良善,使用 MVVM 方法來區分那些我要我的 UI 中展示我的模型物件的路徑。 有一定到什麼你可以用 Knockout.js,尤其是用於生成回應的 Web Ui 的更多。 您還可以使用強大的工具,像 WCF Web API (bit.ly/kthOgY) 來創建您的資料來源。 我期待著更多專業人士的學習和尋找其他藉口來在用戶端上的工作。

Julie Lerman 是 Microsoft MVP,.net 的導師和顧問住在佛蒙特州的丘陵。您可以找到她介紹資料訪問和使用者組和世界各地的會議其他 Microsoft.net 主題。在她博客 thedatafarm.com/blog 是作者的"程式設計實體框架"(O'Reilly 媒體,2010年) 和"程式設計實體框架:代碼第一次"(O'Reilly 媒體,2011年)。跟她在 Twitter 上 twitter.com/julielerman

由於下面的技術專家,檢討這篇文章:John PapaAlejandro Trigo