本文章是由機器翻譯。

Node.js

在 Microsoft Azure 中使用 MEAN 堆疊與 OData 建置 Web 應用程式

Long Lee

下載代碼示例

Microsoft.NET 開發人員通常在伺服器端生成大應用程式在使用 JavaScript 對用戶端和ASP.NET(C# 或Visual Basic.NET)。但如果你可以用一種語言來構建應用程式的堆疊中,一切從瀏覽器和伺服器端業務處理、,甚至導致查詢和資料庫程式設計服務層的所有圖層上嗎?現在你可以與 Node.js。 Node.js 已經存在了數年,但近年來其通過拾取顯著。Node.js 棧,如 MongoDB,快遞,AngularJS,Node.js (平均值) 堆疊,帶來很多好處到構建應用程式,包括這樣的事實,是很少斷開連接 (如果有),前端、 中介層和後端開發人員之間。在許多情況下同樣的程式師可以開發一個應用程式的所有圖層,因為它做在 JavaScript 中。此外,您現在可以構建 Node.js 應用程式直接在Visual Studio2013 Node.js 工具Visual Studio(ⅰ),包括完整的調試能力。

快速入門

在這篇文章我要去告訴你通過使用平均堆疊,建設創建、 讀取、 更新和刪除 (CRUD)-重型應用程式可以快速和容易。我要去假設你有 AngularJS 的基本概念的理解 (angularjs.org),Node.js (nodejs.org),MongoDB (mongodb.org) 和表達 (expressjs.com)。如果你打算跟著,請務必安裝下列程式:

第一步是在Visual Studio中打開新建專案對話方塊中,選擇空白微軟 Azure Node.js Web 應用程式範本,如中所示圖 1。你可以快捷方式幾個專案,通過選擇基本微軟 Azure 表示應用程式範本中,但一個空白範本提供更精細的控制作為中介軟體 Node.js 申請安裝哪些元件。

創建一個空白的微軟 Azure Node.js Web 應用程式
圖 1 創建一個空白的微軟 Azure Node.js Web 應用程式

Node.js 中介軟體是什麼?簡單地說,它是簡單模組您可以插入到應用程式 Node.js 表達的 HTTP 要求管道。通常情況下,為每個 HTTP 要求執行獲取中介軟體。

接下來,安裝使用節點封裝管理員(NPM) 的表達。如果您熟悉使用 NuGet 套裝程式,故宮包基本上是同樣的事情,但對於 Node.js 應用程式。

正如你可以看到在圖 2,@3 其他 npm 參數在文字欄位中,為將安裝最新版本的表達 3 添加。 雖然表達 4 已被釋放,你需要堅持表達 3 因為將安裝的其他模組還沒有更新到一些表達 4 重大更改。

查找和安裝新公共管理包快遞等
圖 2 查找和安裝新公共管理包快遞等

您需要下載並安裝其餘的所需的新公共管理套裝程式:表達,odata 伺服器、 stringify 物件和身體-語法分析器,但就沒有必要有任何"其他 npm 參數,"我會使用最新版本的每個這些 npm 的套裝軟體。

設置 Server.js 檔

所示的檔 (有時命名 app.js) server.js 圖 3,基本上是 Node.js 應用程式的起始點。這是在那裡你將應用程式佈建和注入任何所需的中介軟體模組。

圖 3 Server.js 檔

1    var http = require('http');
2    var express = require( 'express' );
3    var odata = require( './server/data/odata' );
4    var stringify = require( 'stringify-object' );
5    var config = require("./server/config/config");
6    var bodyParser = require("body-parser");
7    var app = express( );
8    odata.config( app );
9    app.use(bodyParser.json());
10   app.use( express.static( __dirname + "/public" ) );
11   var port = process.env.port || 1337;
12   app.get("/", function(req, res) {
13   res.sendfile("/public/app/views/index.html", { root: __dirname });
14   });
15   http.createServer(app).listen(port);
16   console.log(stringify( process.env ));

為了消耗所需的 NPM 包/庫下載,您需要使用關鍵字要求 ("包名稱"),使這些圖書館中範圍對於一個給定的 Node.js 類,行 1 到 6 中所示圖 3。我先回顧一下 server.js 的內容:

  • 第 1-6 行:所需的套裝軟體帶入 server.js 範圍,因此他們可以初始化並插入到 HTTP 要求管道中。
  • 第 7 行:初始化一個新的表達的 Web 應用程式。
  • 第 8 行:定義 OData 配置為其他終結點 ; 更多的考慮到這一點。
  • 第 10 行:插上 express.static 和傳遞的目錄路徑,使公開傳遞的目錄路徑。這讓人達到放置在 NodejsWebApp/公共目錄中的任何內容。例如,HTTP://localhost:1337/image/myImage.gif 將呈現到瀏覽器中 NodejsWebApp/Public/image/myimage.gif 的圖像。
  • 第 12 行:設置預設登錄頁使用 app.get 方法。第一個參數以路徑 (該應用程式的根路徑)。在這裡,我只通過提供指向它的路徑呈現一個靜態的 HTML 檔案。
  • 第 15 行:指示應用程式聽和服務 HTTP 要求指定的埠 ; 為發展目的我使用埠 1337,所以我的應用程式將偵聽請求在 HTTP://localhost:1337。
  • 第 16 行:列印到 Node.js 主控台視窗的 Node.js 環境帶來一些能見度的環境變數。

配置 OData

與 server.js 建立了,我要去焦點現在在行 8 上,哪裡配置 OData 其他終結點。首先,您需要創建兩個模組:NodejsWebApp/server/data/northwind.js (圖 4) 和 NodejsWebApp/server/data/odata.js (圖 5)。

圖 4 NodejsWebApp/server/data/northwind.js

$data.Entity.extend( 'Northwind.Category', {
  CategoryID: { key: true, type: 'id', nullable: false, computed: true },
  CategoryName: { type: 'string', nullable: false, required: true, maxLength: 15 },
  Description: { type: 'string', maxLength: Number.POSITIVE_INFINITY },
  Picture: { type: 'blob', maxLength: Number.POSITIVE_INFINITY },
  Products: { type: 'Array', elementType: 'Northwind.Product', inverseProperty: 'Category' }
} );
$data.Entity.extend( 'Northwind.Product', {
  ProductID: { key: true, type: 'id', nullable: false, computed: true },
  ProductName: { type: 'string', nullable: false, required: true, maxLength: 40 },
  EnglishName: { type: 'string', maxLength: 40 },
  QuantityPerUnit: { type: 'string', maxLength: 20 },
  UnitPrice: { type: 'decimal' },
  UnitsInStock: { type: 'int' },
  UnitsOnOrder: { type: 'int' },
  ReorderLevel: { type: 'int' },
  Discontinued: { type: 'bool', nullable: false, required: true },
  Category: { type: 'Northwind.Category', inverseProperty: 'Products' },
  Order_Details: { type: 'Array', elementType: 'Northwind.Order_Detail', 
  inverseProperty: 'Product' },
  Supplier: { type: 'Northwind.Supplier', inverseProperty: 'Products' }
} );
$data.Class.define( "NorthwindContext", $data.EntityContext, null, {
  Categories: { type: $data.EntitySet, elementType: Northwind.Category },
  Products: { type: $data.EntitySet, elementType: Northwind.Product },
  // Other entity registrations removed for brevity, please see actual source code.
} );
// Other entity definitions removed for brevity, please see actual source code.
NorthwindContext.generateTestData = function( context, callBack ) {
  var category1 = new Northwind.Category( { CategoryName: 'Beverages',
    Description: 'Soft drinks, coffees, teas, beer, and ale' } );
  // Other category instances removed for brevity, please see actual source code.
  context.Categories.add( category1 );
  // Other category inserts removed for brevity, please see actual source code.
  context.Products.add( new Northwind.Product( 
   { ProductName: 'Ipoh Coffee', EnglishName: 'Malaysian Coffee',
    UnitPrice: 46, UnitsInStock: 670, Discontinued: false, Category: category1 } ) );
  // Other product inserts removed for brevity, please see actual source code.
  context.saveChanges( function ( count ) {
    if ( callBack ) {
      callBack( count );
    }
  } );
};
module.exports = exports = NorthwindContext;

圖 5 NodejsWebApp/server/data/odata.js 模組

( function (odata) {
  var stringify = require( 'stringify-object' );
  var config = require( "../config/config" );
  console.log( stringify( config ) );
  odata.config = function ( app ) {
    var express = require( 'express' );
    require( 'odata-server' );
    var northwindContextType = require( './northwind.js' );
    var northwindContext = new NorthwindContext( {
      address: config.mongoDb.address,
      port: config.mongoDb.port,
      username: config.mongoDb.username,
      password: config.mongoDb.password,
      name: config.mongoDb.name,
      databaseName: config.mongoDb.databaseName,
      dbCreation: $data.storageProviders.DbCreationType.DropAllExistingTables
    } );
    console.log( "northwindContext :" );
    stringify( northwindContext );
    northwindContext.onReady( function ( db ) {
      northwindContextType.generateTestData( db, function ( count ) {
        console.log( 'Test data upload successful. ', count, 'items inserted.' );
        console.log( 'Starting Northwind OData server.' );
        app.use( express.basicAuth( function ( username, password ) {
          if ( username == 'admin' ) {
            return password == 'admin';
          } else return true;
        } ) );

請注意 MongoDB 是一個 NoSQL 資料庫 — — 那就是,非關聯式的文獻資料庫。當傳統的羅斯文資料庫移轉到 MongoDB 採取 NoSQL 模型的優點,可以有許多方法來構建它。這篇文章,我將離開 Northwind 架構,大多數情況下,完好無損。(我已經刪除了其他實體模型定義、 登記和從插入圖 4 為簡潔起見。)

圖 4 模型和實體被簡單地被定義,稍後可以重用在用戶端上執行 CRUD 操作,如創建新的產品,例如時。此外,NorthwindCoNtext.generateTestData 方法將種子資料庫,每次應用程式重新開機時,它會派上用場當你部署到現場演示網站的應用程式。這使得它容易刷新資料簡單地通過回收應用程式需要的時候。更為簡潔的方法會將這段代碼包裝到 Azure WebJob 並安排它刷新按照設置的頻率,但將其保持原樣,現在。在此模組中的最後一行 module.exports = 出口 = NorthwindCoNtext,體膜一切等等,稍後您可以"要求"本模組和使用"new"運算子來創建顯示在中的 NodejsWebApp/server/data/odata.js 模組中完成的羅斯文物件類型的新實例圖 5

您可以通過命令列查詢 MongoDB 或通過使用在那裡 (如 RoboMongo) 的許多 MongoDB GUI 工具之一來確認種子實際上插入資料。因為這篇文章的重點是 OData,使用 LINQPad,因為它包含了內置的提供程式使用LINQ對 OData 版本 3 來應答查詢。

若要測試端點,請下載並安裝 LINQPad (linqpad.net),然後運行您的應用程式 (F5 在Visual Studio2013年)。然後點燃 LINQPad 並設置到 OData 端點的新連接。要這樣做,請按一下添加連接並選擇 OData 作為您 LINQPad 資料提供程式。然後配置 ODataLINQ與 URI HTTP://localhost:1337/northwind.svc ; 連接 使用者名 Admin ; 和密碼,管理員。LINQPad 將呈現層次結構基於 ODataCSDL端點,如你可以看到在左上角的圖 6

的LINQ查詢並使用中發現的資料模型及其結果
圖 6 的LINQ查詢並使用中發現的資料模型及其結果

應基於種子所用的資料在伺服器端 (NodejsWebApp/server/northwind.js),所以你要做一個快速的LINQ查詢上使用 LINQPad 產品的產品資料:

Products.Take(100)

圖 6 也顯示查詢和其結果。

正如你所看到的 OData 伺服器正確設置了,你可以通過 HTTP 發佈LINQ查詢並取回的產品清單。如果您按一下請求日誌選項卡上,您實際上可以看到從LINQ語句生成的 HTTP GET OData URL LINQPad:HTTP://localhost:1337,northwind.svc,產品 ()? $top = 100。

一旦你確定了你 OData 伺服器的確 Node.js 表示 Web 應用程式上運行,你會想要利用這而開始建立一些常見的用例可以消耗,OData 美好的事物。將所有內容放在"公共"資料夾和資料夾命名伺服器中的伺服器運行的所有代碼中的用戶端。創建您的應用程式提前作為存根 (stub) 或預留位置,所需的所有檔,然後回到周圍和填空。圖 7 顯示了 NodejsWebApp 專案的結構。

NodejsWebApp 專案
圖 7 NodejsWebApp 專案

在所示的 app.js 檔 (NodejsWebApp/public/app/app.js) 圖 8 基本上是 (用戶端) AngularJS 應用程式的起始點。我不會去談所有的細節 ; 這裡的要點是你想要與 $routeProvider 註冊為單頁面應用程式 (SPA) 您用戶端的路由。對於每個 (定義為當方法) 的路線,提供視圖 (HTML),要通過設置 templateUrl 屬性,呈現的路徑並指定視圖控制器的控制器屬性設置為給定的路線。AngularJS 控制器是所有的代碼住,以便無論視圖需要的地方 — — 簡而言之,所有的 JavaScript 代碼視圖。形成潮氣可能方法用於配置不匹配任何路線的任何傳入請求的預設路由 (主視圖)。

圖 8 App.js 檔

'use strict';
var myApp = angular.module('myApp',
  [
    'ngRoute',
    'ngAnimate',
    'kendo.directives',
    'jaydata'
  ])
  .factory("northwindFactory",
  [
    '$data',
    '$q',
    function($data, $q) {
      // Here you wrap a jquery promise into an angular promise.
      // Simply returning jquery promise causes bogus things
      var defer = $q.defer();
      $data.initService("/northwind.svc").then(function(ctx) {
        defer.resolve(ctx);
      });
      return defer.promise;
    }
  ])
  .config(function($routeProvider) {
    $routeProvider
      .when('/home',
      {
        templateUrl: 'app/views/home.html'
      })
      .when('/product',
      {
        templateUrl: 'app/views/product.html',
        controller: 'productController',
        resolve: {
          northwind: 'northwindFactory'
        }
      })
      .when('/edit/:id',
      {
        templateUrl: 'app/views/edit.html',
        controller: 'editController',
        resolve: {
          northwind: 'northwindFactory'
        }
      })
      .when('/chart',
      {
        templateUrl: 'app/views/chart.html',
        controller: 'chartController',
        resolve: {
          northwind: 'northwindFactory'
        }
      })
      .otherwise(
      {
        redirectTo: '/home'
      });
  });

這裡是一個快速回顧一下的模型-視圖-模型 (MVVM) 模式的關切在應用程式中的表示方式:

  • 視圖 = *.html
  • ViewModel = *controller.js
  • 模型 = 從其他終結點返回的實體,通常是域模型和 (或) 實體

圖 9 顯示哪些檔在應用程式位址涉及 MVVM 模式。

的模型-視圖-視圖模型模式
圖 9 的模型-視圖-視圖模型模式

作為一種 AngularJS 服務定義 JayData 用戶端 DataCoNtext

因為大多數的控制器將使用羅斯文上下文,要創建名為 northwindFactory 維修廠。並且因為羅斯上下文的初始化是非同步你會想要設置一個 JavaScript 承諾確保羅斯上下文的初始化已完成並準備好要使用的時間任何控制器載入。所以,簡單地說,羅斯文上下文將在完成載入 northwindFactory 載入依賴的任何控制器。請注意所有已配置的路由有一個"解決"的屬性,它是你怎麼定義承諾解決之前的控制器是載入所需。在這種情況下,屬性,"羅斯文,"設置為 northwindFactory。屬性名稱"northwind"也將會被注入到控制器的實例的名稱。你會看到有點 productController.js 的建構函式 (在圖 11),在那裡 northwindFactory 注入作為羅斯文,為 northwindFactory 在路線的決心屬性中設置的屬性名稱。

Index.html,示圖 10,基本上會佈局頁面,AngularJS 將會知道哪些視圖來換成用屬性吳觀 div。請注意,您必須指定的 AngularJS 應用程式通過配置任何 HTML 元素的父元素的 div 歸因於以"吳觀"。在這種情況下您想要設置"吳 app"到"myApp",這是應用程式的命名 app.js 是什麼。

圖 10 Index.html 檔

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <meta charset="utf-8" />
    <title>NodejsWebApp</title>
    <link href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css"
      rel="stylesheet">
    <link href="//cdn.kendostatic.com/2014.2.716/styles/kendo.common.min.css"
      rel="stylesheet" />
    <link href="//cdn.kendostatic.com/2014.2.716/styles/kendo.bootstrap.min.css"
      rel="stylesheet" />
    <link href="//cdn.kendostatic.com/2014.2.716/styles/kendo.dataviz.min.css"
      rel="stylesheet" />
    <link href="//cdn.kendostatic.com/2014.2.716/styles/
      kendo.dataviz.bootstrap.min.css" rel="stylesheet" />
    <link href="../../css/site.css" rel="stylesheet" />
  </head>
    <body>
    <div class="navbar navbar-inverse navbar-fixed-top">
      <div class="container">
        <div class="navbar-header">
          <button type="button" class="navbar-toggle"
            data-toggle="collapse" data-target=".navbar-collapse">
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
          </button>
          <a class="navbar-brand" href="/">NodejsWebApp</a>
        </div>
        <div class="navbar-collapse collapse">
          <ul class="nav navbar-nav">
            <li>
              <a href="#/home">Home</a>
            </li>
            <li>
              <a href="#/about">About</a>
            </li>
            <li>
              <a href="#/contact">Contact</a>
            </li>
            <li>
              <a href="#/product">Product</a>
            </li>
            <li>
              <a href="#/chart">Chart</a>
            </li>
          </ul>
        </div>
       </div>
    </div>
    <!-- Binding the application to our AngularJS app: "myApp" -->
    <div class="container body-content" ng-app="myApp">
      <br />
      <br/>
      <!-- AngularJS will swap our Views inside this div -->
      <div ng-view></div>
      <hr />
      <footer>
        <p>&copy; 2014 - My Node.js Application</p>
      </footer>
    </div>
    <script src="//code.jquery.com/jquery-2.1.1.min.js"></script>
    <script src=
      "//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js">
    </script>
    <script src="//code.angularjs.org/1.3.0-beta.16/angular.min.js"></script>
    <script src="//code.angularjs.org/1.3.0-beta.16/angular-route.min.js"></script>
    <script src="//code.angularjs.org/1.3.0-beta.16/angular-animate.min.js"></script>
    <script src="//cdn.kendostatic.com/2014.2.716/js/kendo.all.min.js"></script>
    <script src="//include.jaydata.org/datajs-1.0.3-patched.js"></script>
    <script src="//include.jaydata.org/jaydata.js"></script>
    <script src="//include.jaydata.org/jaydatamodules/angular.js"></script>
    <script src="/lib/jaydata-kendo.js"></script>
    <!--<script src="//include.jaydata.org/jaydatamodules/kendo.js"></script>-->
    <script src="/app/app.js"></script>
    <script src="/app/controllers/productController.js"></script>
    <script src="/app/controllers/chartController.js"></script>
    <script src="/app/controllers/editController.js"></script>
  </body>
</html>

所有我的用戶端 JavaScript 庫包含,請注意我使用一個內容傳遞網路 (CDN)。您可以下載本地在命令列上使用涼亭 (如通常做的事對於.NET 專案 NuGet 使用封裝管理員主控台) 的用戶端庫。在 Microsoft.NET 框架中,您使用 NuGet 用戶端和伺服器端的套裝軟體。然而,在 Node.js 境界,涼亭用於下載用戶端庫/包,而新公共管理用來下載並安裝伺服器端庫/包。

對於 UI 佈局,我使用一個香草的引導主題,Visual StudioASP.NETMVC 5 專案範本生成的那個。

產品視圖

產品視圖 (NodejsWebApp/public/app/views/products.html) 需要的 HTML 的只需要幾行。第一個塊是 AngularJS 來呈現網格的劍道指令:

<!-- Kendo UI's AngularJS directive for the grid -->
<div kendo-grid="grid" k-options="options"></div>
<!-- AngularJS template for our View Detail Button in the Grid Toolbar -->
<script type="text/x-kendo-template" id="viewDetail">
  <a
    class="k-button "
    ng-click="viewDetail(this)">View Detail</a>
</script>

第二塊是只是 AngularJS 範本為您添加到網格的工具列自訂查看詳細資訊按鈕。

圖 11 顯示產品控制器,NodejsWebApp/app/controllers/productController.js。

圖 11 產品控制器

myApp.controller("productController",
  function($scope, northwind, $location) {
    var dataSource =
      northwind
        .Products
        .asKendoDataSource({ pageSize: 10 });
    $scope.options = {
      dataSource: dataSource,
      filterable: true,
      sortable: true,
      pageable: true,
      selectable: true,
      columns: [
        { field: "ProductID" },
        { field: 'ProductName' },
        { field: "EnglishName" },
        { field: "QuantityPerUnit" },
        { field: "UnitPrice" },
        { field: 'UnitsInStock' },
        { command: ["edit", "destroy"] }
      ],
      toolbar: [
        "create",
        "save",
        "cancel",
        {
          text: "View Detail",
          name: "detail",
          template: $("#viewDetail").html()
        }
      ],
      editable: "inline"
    };
    $scope.viewDetail = function(e) {
      var selectedRow = $scope.grid.select();
      if (selectedRow.length == 0)
        alert("Please select a row");
      var dataItem = $scope.grid.dataItem(selectedRow);;
      $location.url("/edit/" + dataItem.ProductID);
    };
  });

以水合物產品網格,您需要具現化一個劍道 UI 資料來源 ($scope.options.dataSource)。JayData 提供了一個説明器方法來初始化一個劍道 UI 資料來源綁定到其 OData 其他終結點。JayData asKendoDataSourcehelper 方法知道如何創建基於發佈由 OData 伺服器 (HTTP://localhost:1337/northwindsvc),然後用來配置中在 app.js northwindFactory 的 $data 實例的中繼資料資訊的資料來源。 當我演示與劍道 DataViz 圖表框架的視覺印象,你會看到更多的劍道資料來源。

隨著開箱按鈕 (創建、 保存和取消) 配置網格的工具列中,您將添加一個自訂的按鈕以導航到另一個視圖將呈現所選的產品行 ($scope.viewDetail) 的完整詳細資訊。當查看詳細資訊按鈕按一下事件發生時,所選的產品 DataItem,然後,使用 AngularJS 的 $location 服務,導航到該產品的編輯檢視 (MyNodejsWebApp/scripts/app/views/edit.html)。

圖 12 顯示的 Edit.html 檔 NodejsWebApp/public/app/views/edit.html。

圖 12 Edit.html 檔

<div class="demo-section">
  <div class="k-block" style="padding: 20px">
    <div class="k-block k-info-colored">
      <strong>Note: </strong>Please fill out all of the fields in this form.
    </div>
    <div>
      <dl>
        <dt>
          <label for="productName">Name:</label>
        </dt>
        <dd>
          <input id="productName" type="text"
            ng-model="product.ProductName" class="k-textbox" />
        </dd>
        <dt>
          <label for="englishName">English Name:</label>
        </dt>
        <dd>
          <input id="englishName" type="text"
            ng-model="product.Englishname" class="k-textbox" />
        </dd>
        <dt>
          <label for="quantityPerUnit">Quantity Per Unit:</label>
        </dt>
        <dd>
          <input id="quantityPerUnit" type="text"
            ng-model="product.QuantityPerUnit" class="k-textbox" />
        </dd>
        <dt>
          <label for="unitPrice">Unit Price:</label>
        </dt>
        <dd>
          <input id="unitPrice" type="text"
            ng-model="product.UnitPrice" class="k-textbox" />
        </dd>
        <dt>
          <label for="unitsInStock">Units in Stock:</label>
        </dt>
        <dd>
          <input id="unitsInStock" type="text"
            ng-model="product.UnitsInStock" class="k-textbox" />
        </dd>
        <dt>
          <label for="reorderLevel">Reorder Level</label>
        </dt>
        <dd>
          <input id="reorderLevel" type="text"
            ng-model="product.ReorderLevel" class="k-textbox" />
        </dd>
        <dt>
          <label for="discontinued">Discontinued:</label>
        </dt>
        <dd>
          <input id="discontinued" type="text"
            ng-model="product.Discontinued" class="k-textbox" />
        </dd>
        <dt>
          <label for="category">Category:</label>
        </dt>
        <dd>
           <select
             kendo-drop-down-list="dropDown"
             k-data-text-field="'CategoryName'"
             k-data-value-field="'CategoryID'"
             k-data-source="categoryDataSource"
             style="width: 200px"></select>
        </dd>
      </dl>
      <button kendo-button ng-click="save()"
        data-sprite-css-class="k-icon k-i-tick">Save</button>
      <button kendo-button ng-click="cancel()">Cancel</button>
      <style scoped>
        dd {
          margin: 0px 0px 20px 0px;
          width: 100%;
        }
        label {
          font-size: small;
          font-weight: normal;
        }
        .k-textbox { width: 100%; }
        .k-info-colored {
          margin: 10px;
          padding: 10px;
        }
      </style>
    </div>
  </div>
</div>

請注意如何投入都裝飾著吳模型屬性中,是以聲明方式指示該輸入的值將存儲在屬性控制器 $scope 吳模型值設置為 AngularJS 方法。例如,在此視圖中的第一個輸入欄位,其 HTML 元素 id 設置為產品名稱 (id ="產品名稱"),吳模型被設置為產品。產品名稱。 這意味著在任何使用者輸入輸入欄位 (文字方塊) 中,$scope.productName 的值會相應地設置。此外,無論 $scope.product.productName 設置為以程式設計方式在 editController 將自動反映在產品名稱輸入欄位的值。

作為一個例子,當認為第一次載入,載入由 ID 產品在通過 URL,然後將 $scope.product 設置為該產品 (見圖 13)。一旦發生這種情況,在視圖中用吳模型設置為 $scope.property.* 的一切都將反映在 $scope.product 中的所有屬性值。 在過去,開發人員通常在中設置值為任何類型的 DOM 操作使用 jQuery 或直 JavaScript 的輸入欄位當建築具有 MVVM 模式 (不考慮框架) 的應用程式,最佳做法是操作只能通過改變 ViewModel,從不直接 (例如,用 JavaScript 或 jQuery) 到 DOM。我絕對不暗示有什麼毛病的 JavaScript 代碼或 jQuery,但是如果你決定使用一種模式來解決特定的問題 (在我的情況下使用 MVVM 保持視圖、 視圖和模型之間的分離),它應該是在您的應用程式保持一致。

圖 13 editController.js 檔

myApp.controller("editController",
  function($scope, northwind, $routeParams, $location) {
    var productId = $routeParams.id;
    $scope.categoryDataSource = northwind.Categories.asKendoDataSource();
    northwind
      .Products
      .include("Category")
      .single(
        function(product) {
          return product.ProductID == productId;
        },
        { productId: productId },
        function(product) {
          $scope.product = product;
          northwind.Products.attach($scope.product);
          $scope.dropDown.value($scope.product.Category.CategoryID);
          $scope.$apply();
        });
    $scope.save = function() {
      var selectedCategory = $scope
                            .categoryDataSource
                            .get($scope.product.Category.CategoryID);
      console.log("selecctedCategory: ", selectedCategory.innerInstance());
      $scope.product.Category = selectedCategory.innerInstance();
      // Unwrap kendo dataItem to pure JayData object
      northwind.saveChanges();
    };
    $scope.cancel = function() {
      $location.url("/product");
    };
  });

請注意你可以實現 POST 伺服器端操作上 Node.js,這是什麼通常是與ASP.NETWeb API。然而,在這裡的目的是演示如何與 Node.js 和 OData:

app.post('/api/updateProduct', function(req, res) {
  var product = req.body;
  // Process update here, typically what is done with the ASP.NET Web API
});

圖表視圖 (NodejsWebApp/public/app/views/chart.html),你只需要一行的標記:

<kendo-chart k-options="options"></kendo-chart>

這裡發生的一切宣佈劍道 UI 橫條圖指令,設置這些選項要綁定到的控制器命名選項中的一個屬性。圖 14 顯示產品圖表視圖和圖 15 顯示產品圖表控制器。

產品圖表視圖
圖 14 產品圖表視圖

圖 15 產品圖表控制器

myApp.controller("chartController",
  function($scope, northwind) {
    var dataSource = northwind.Products.asKendoDataSource();
    $scope.options = {
      theme: "metro",
      dataSource: dataSource,
      chartArea: {
        width: 1000,
        height: 550
      },
      title: {
        text: "Northwind Products in Stock"
      },
      legend: {
        position: "top"
      },
      series: [
        {
          labels: {
            font: "bold italic 12px Arial,Helvetica,sans-serif;",
            template: '#= value #'
          },
          field: "UnitsInStock",
          name: "Units In Stock"
        }
      ],
      valueAxis: {
        labels: {
          format: "N0"
        },
        majorUnit: 100,
        plotBands: [
          {
            from: 0,
            to: 50,
            color: "#c00",
            opacity: 0.8
          }, {
            from: 50,
            to: 200,
            color: "#c00",
            opacity: 0.3
          }
        ],
        max: 1000
      },
      categoryAxis: {
        field: "ProductName",
        labels: {
          rotation: -90
        },
        majorGridLines: {
          visible: false
        }
      },
      tooltip: {
        visible: true
      }
    };
  });

隨著 productController.js,在這裡你還注入 northwindFactory 作為控制器的建構函式中,在羅斯文再次使用 JayData 助手 asKendoDataSource 方法創建一個劍道資料來源。下面是在圖表控制器中發生了什麼事的更多詳細資訊:

$scope.options.series

  • 類型:此配置圖表的類型。
  • 欄位:從模型/實體將用於系列 (X 軸) 值的欄位。

$scope.options.valueAxis

  • majorUnit:主要部門之間的間隔。如果將 valueAxis.type 設置為登錄,majorUnit 值將用於對數的底。
  • plotBands:情節帶圖,用於在視覺上顯示的產品數量。如果數量低於指定的水準,使用者應援引進貨過程的產物。
  • 最大:Y 軸最大值。

$scope.options.categoryAxis

  • 欄位:X 軸欄位標籤。
  • labels.rotation:把標籤旋轉度。在這裡您配置標籤 X 軸垂直于正在運行的 X 軸值設置為-90 (度),那就是,把標籤逆時針旋轉 90 度的角度上。
  • majorGridLines.visible:打開或關閉的主要格線。你可能想要將它們關閉化妝品的原因,以賦予其一個更清潔和更多拋光看。
  • tooltip.visible:這使工具提示,當使用者懸停在一個分隔號。

劍道 UI 圖表 API 的詳細資訊,請參閱 bit.ly/1owgWrS

蔚藍的 Web 網站部署

因為原始程式碼中方便地承載在 CodePlex Git 存儲庫中,使用 Azure Web 網站設置連續部署 (連續交付) 是簡單,它獲取:

  1. 導航到您的 Azure Web 網站儀表板並選擇部署從原始程式碼管理設置。
  2. 選擇您的存儲庫 ; 此示例中,請選擇 CodePlex。
  3. 按 [Next (下一步)]。
  4. 選擇您的 CodePlex 專案。
  5. 選擇的分支。
  6. 按一下檢查。
  7. 每次同步到你的 Git 存儲庫,將會出現一個生成和部署。

就這樣。與幾個簡單的點擊,您的應用程式部署與持續集成和交付。有關部署與 Git 的詳細資訊,請訪問 bit.ly/1ycBo9S

作為.NET 開發人員,我是來真的很喜歡如何快速和生成 CRUD 重型應用程式與ASP.NETMVC、 AngularJS、ASP.NETWeb API、Entity Framework、 OData 劍道 UI 是容易。現在,通過開發平均堆疊上,我仍然可以利用很多這個領域的知識和經驗,JayData 庫的説明。兩個堆疊之間的唯一區別是伺服器端層。如果您曾經開發過ASP.NETMVC 和ASP.NETWeb API,Node.js 不應該存在許多問題,因為你已經有了一些基本的 JavaScript 經驗。你會發現完整的原始程式碼示例在這篇文章在 msdnmeanstack.codeplex.com,並在現場演示 meanjaydatakendo.azurewebsites.net


Long Lee 是世邦公司的建築師主要應用程式開發 和 Telerik/劍道 UI MVP。他花了他大部分的時間制訂框架和應用程式塊,為最佳實踐和模式,提供指導和規範企業技術堆疊。在他的業餘時間,他喜歡寫博客 (blog.longle.net),玩使命召喚或者指導 (codementor.io/lelong37)。你可以到達並跟隨他在 Twitter 上 twitter.com/LeLong37

衷心感謝以下技術專家對審查的這篇文章中:羅伯特 Bany (JayData)、 伯克荷蘭 (Telerik) 和PeterZentai (JayData)