共用方式為


建立 ToDoList 範例應用程式

在本教學課程中,您將學習如何使用 AngularJS 建立工作清單範例應用程式 (AngularJSToDo)。 這個應用程式可讓使用者建立新的工作、將它們取消核取,以及移除它們。 應用程式也會使用 HTML5 Web 儲存體將工作儲存至裝置上。 (完整的範例使用 Microsoft Azure 行動服務儲存資料,也會使用 Bing Maps 提供有效的地址。) 這個範例使用 JavaScript 程式碼,但您也可以使用 TypeScript 撰寫 Cordova 應用程式。

注意事項注意事項

如需建置 Cordova 應用程式所需的工作概觀,請參閱建立 Apache Cordova 應用程式

工作清單範例應用程式適用於多個架構,並可以在這裡下載:

若要下載其他 Visual Studio Tools for Apache Cordova 範例以示範多頁瀏覽和其他功能,請參閱 AngularJS 主版詳細資料頁面範例WinJS 瀏覽應用程式範本

在本教學課程中,您將遵循下列步驟:

  1. 建立專案

  2. 建立 UI

  3. 加入 AngularJS 架構

  4. 註冊應用程式模組

  5. 加入資料模型

  6. 加入檢視邏輯和資料繫結

  7. 建置並執行待辦事項清單應用程式

  8. 加入 Bing Maps 服務

  9. 加入 Azure 行動服務

必要條件

建立新專案前,請先確認您符合所有系統需求,並安裝 Visual Studio 的 Visual Studio Tools for Apache Cordova 擴充功能。 如需詳細資訊,請參閱安裝 Visual Studio Tools for Apache Cordova

建立專案

遵循Create Your First Hello World App所述的步驟,在 Visual Studio 中建立新的 Cordova 專案。 或者,您可以選擇 Visual Studio 中的 [檔案]、[新增] 與 [專案],從新的空白應用程式開始。 在 [新增專案] 對話方塊中,依序選擇 [已安裝]、[範本]、[JavaScript]、[Apache Cordova 應用程式] 以及 [空白應用程式] 範本。

建立 UI

工作清單範例應用程式中的主要 UI 是由下列項目所組成:

  • 新清單項目的 <input> 項目。

  • 將會顯示工作清單中的每個工作的 AngularJS 範本。

<input> 項目看起來像這樣:

<input id="new-todo" placeholder="What needs to be done?" ng-text-change="addToDo()" ng-model="newToDoText" autofocus>

當您第一次執行應用程式時,有些在上述程式碼中的屬性不會執行任何動作。 例如,AngularJS ng-model 指示詞會啟用雙向資料繫結,並可讓您在 addToDo() 函式執行時儲存輸入的工作。

針對工作清單中,我們會使用某些包裝數個其他項目的巢狀 <div> 項目來定義範本。 例如,此處所示的巢狀 <input> 項目用來顯示每個工作字串。

<div class="templateWrapper" ng-repeat="toDoItem in todos">
    <div class="templateContainer">
        <input class="templateTitle" ng-class="{crossedOut: toDoItem.done}" type="text" ng-text-change="changeToDoText(toDoItem)" ng-model="toDoItem.text" />
        <!-- More list item HTML elements -->
    </div>
</div>

在上述程式碼中,AngularJS 屬性 ng-repeat 可讓您將最上方的 <div> 項目定義成範本以顯示工作清單項目。 之後,在附加實際資料並執行應用程式時,ng-repeat 會將 <div> 項目 (templateContainer) 及其子項目加入至每個儲存工作清單項目的 DOM。

注意事項注意事項

因為 Cordova 不依賴任何特定的 JavaScript 架構,所以我們不會在這些步驟中提供 AngularJS 程式設計 的深入資訊。不過,我們會用一個良好的範例說明如何使用 Visual Studio Tools for Apache Cordova 建立跨平台應用程式。

現在,我們將加入 index.html 的完整標記。

加入清單的標記

  • 開啟 index.html,並將 <body> 項目取代為下列程式碼。

    <body ng-app="xPlat">
        <section id="todoapp" ng-controller="ToDoCtrl">
            <header id="header">
                <div id="headerBand"></div>
                <input id="new-todo" placeholder="What needs to be done?" ng-text-change="addToDo()" ng-model="newToDoText" autofocus>
            </header>
            <section id="main">
                <div id="todo-list">
                    <div class="templateWrapper" ng-repeat="toDoItem in todos">
                        <div class="templateContainer">
                            <input class="templateTitle" ng-class="{crossedOut: toDoItem.done}" type="text" ng-text-change="changeToDoText(toDoItem)" ng-model="toDoItem.text" />
                            <h3 class="templateAddress">{{toDoItem.address}}</h3>
                            <button class="templateLeft templateToggle" ng-class="{'checked': toDoItem.done, 'unchecked': !toDoItem.done}" ng-mousedown="toggleToDoDone(toDoItem)"></button>
                            <button class="templateLeft templateRemove" ng-click="removeToDo(toDoItem)"></button>
                        </div>
                        <div class="templateBorder"></div>
                    </div>
                </div>
            </section>
        </section>
    
        <script src="scripts/index.js"></script>
    </body>
    

    在加入 AngularJS 架構 (於稍後步驟中) 時,index.html 中指定的其他 AngularJS 屬性就會變得有意義,但現在執行應用程式時還未有任何效果。 以下是 index.html 中包含的其他 AngularJS 屬性:

    • ng-app 指示詞,可指定 AngularJS 應用程式的根節點。

    • ng-controller 可指定 AngularJS 控制器以支援 MVC。

    空白應用程式範本中的預設 <body> 項目已包含 Apache Cordova 參考以及已覆寫之 platformOverrides.js 的參考。 在下一個步驟中,您會將這些參考加回檔案的 <head> 項目。

加入 Cordova 程式庫參考

  • 在 index.html 中,會在其他指令碼參考之前,於 <head> 項目中加入下列指令碼參考。

    <!-- Cordova reference -->
    <script src="cordova.js"></script>
    <script src="scripts/platformOverrides.js"></script>
    

加入 CSS 樣式資訊

  • css 資料夾中,開啟 index.css,並加入 HTML 項目和範本的下列 CSS 樣式資訊。

    /* reset layout*/
    html,
    body {
        margin: 0;
        padding: 0;
    }
    
    /* body*/
    body {
        background: #F7f7f7;
        color: #4d4d4d;
        width: 100%;
        margin: 0 auto;
    }
    
    /* no outline for buttons & checkboxes*/
    button,
    input[type="checkbox"] {
        outline: none;
    }
    
    /* section styles*/
    @media (min-width: 550px) {
        #todoapp {
            width: 74vw;
            left: 13vw;
            top: 50px;
        }
    }
    
    #todoapp {
        background: rgba(255, 255, 255, 0.9);
        border: 1px solid #ccc;
        position: relative;
        border-top-left-radius: 2px;
        border-top-right-radius: 2px;
        box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.2), 0 25px 50px 0 rgba(0, 0, 0, 0.15);
    }
    
    /* the 2 red rulers*/
    #todoapp:before {
        content: '';
        border-style: solid;
        border-left-color: rgba(242, 103, 103, 1);
        border-right-color: rgba(242, 103, 103, 1);
        border-width: 1px;
        z-index: 2;
        width: 2px;
        position: absolute;
        top: 0;
        left: 40px;
        height: 100%;
    }
    
    /* dark band on the header*/
    #headerBand {
        position: relative;
        height: 4vh;
        max-height: 20px;
        border-bottom: 1px solid #6c615c;
        background: rgba(52, 59, 69, 1);
        border-top-left-radius: 1px;
        border-top-right-radius: 1px;
    }
    
    /* the new to-do entry*/
    #new-todo {
        background: rgba(237, 237, 237, 0.9);
        position: relative;
        margin: 0;
        height: 10vh;
        max-height: 70px;
        font-size: 21px;
        font-family: "Arial";
        border: 0;
        outline: none;
        color: rgb(114, 115, 115);
        padding: 0 0 0 56px;
        width: 100%;
        box-sizing: border-box;
    }
    
    /* the main section that hosts the listview*/
    #main {
        position: relative;
        z-index: 1;
        border-top: 1px dotted #adadad;
    }
    
    /*todo list*/
    #todo-list {
        height: 86vh;
        min-height: calc(100vh - 90px);
        margin: 0px;
        overflow-y: auto;
    }
    
    /*the host template*/
    .templateWrapper {
        position: relative;
        overflow: hidden;
    }
    
    .templateBorder {
        height: 0;
        border-bottom: 2px solid #bfdbf2;
    }
    
    /* container for the todo-address div*/
    .templateContainer {
        width: calc(100% - 50px);
        margin: 4px 5px 0px 45px;
    }
    
    .templateContainer input[type="text"] {
        font-size: 18px;
        font-family: "Arial";
        background: none;
        color: #2d3239;
        border: 1px solid rgba(0, 0, 0, 0);
        line-height: 0.6em;
        margin: 0px;
        width: calc(100% - 10px);
        display: block;
        padding: 4px 0px 4px 10px;
    }
    
    .templateContainer input[type="text"]:active,
    .templateContainer input[type="text"]:focus {
        color: #2d3239;
        border: 1px solid #b2b2b2;
        outline: none;
        margin-left: 2px;
        text-decoration: none !important;
        padding-left: 8px;
    }
    
    input[type="text"]:active ~ .templateRemove,
    input[type="text"]:focus ~ .templateRemove,
    .templateRemove:active,
    .templateRemove:focus {
        display: inline-block;
    }
    
    input[type="text"]:active ~ .templateToggle,
    input[type="text"]:focus ~ .templateToggle,
    .templateRemove:active ~ .templateToggle,
    .templateRemove:focus ~ .templateToggle {
        display: none;
    }
    
    .crossedOut.templateTitle {
        text-decoration: line-through;
    }
    
    .templateContainer .templateAddress {
        color: #727272;
        font-size: 12px;
        font-family: "Arial";
        padding-top: 0px;
        margin: 0px 0px 10px 11px;
        font-weight: normal;
    }
    
    .templateContainer p {
        margin: 0px 0px 4px 0px;
    }
    
    /* checkbox on the templated item*/
    .templateLeft {
        position: absolute;
        top: 6px;
        left: 5px;
        border: none;
        width: 29px;
        height: 29px;
        min-width: 0;
        min-height: 0;
    }
    
    /* button for remove*/
    .templateRemove {
        display: none;
        background-image: url('https://go.microsoft.com/fwlink/?LinkID=403181');
    }
    
    button {
        background-color: transparent;
    }
    
    button.checked {
        background-image: url('https://go.microsoft.com/fwlink/?LinkID=403179');
    }
    
    button.unchecked {
        background-image: url('https://go.microsoft.com/fwlink/?LinkID=403180');
    }
    

您可以查看其中一個模擬器中的空白工作清單以確認一切看起來正確。 在這個步驟中,您將在 Windows 或 Apache Ripple 模擬器上執行 AngularJSToDo 清單應用程式,這具有基本設定需求。 如果您偏好在其他目標上測試應用程式,請參閱以下主題:在 Android 上執行 Apache Cordova 應用程式安裝工具以建置 iOS,以及在 Windows Phone 上執行 Apache Cordova 應用程式

建置和執行應用程式

  1. 從 [方案平台] 清單中,選擇 Windows-x64、Windows-x86 或 Android。

  2. 如果您選擇 Android 平台,請選擇其中一個 Ripple 模擬器 (如此處所示)。

    選取 Ripple 模擬器

    如果您選擇 Windows 平台,則可以在預設部署目標 [本機電腦] 上執行應用程式。

  3. 按 F5 啟動偵錯,或按 Shift+F5 啟動但不偵錯。

    下圖顯示 AngularJSToDo 清單應用程式在其中一個 Ripple 模擬器 (不含、也不附加任何實際資料) 中的外觀範例。

    不含資料的初始待辦清單

    提示

    如果您正在 Ripple 模擬器上執行,並且收到錯誤指出您需要安裝新版的 Android SDK,請使用 Android SDK 管理員來安裝它。在 Windows 中,SDK Manager.exe 位於 C:\Program Files (x86)\Android\android-sdk。

在專案中加入 AngularJS 架構

驗證過設定之後,您就可以建立 AngularJSToDo 應用程式。 應用程式會使用 AngularJS 來分隔檢視模型 (MVC)、提供資料繫結,以及支援不同平台的原生 UI。

將 AngularJS 加入專案

  1. AngularJS 網站中,選擇 [下載]。

    在 [下載 AngularJS] 對話方塊中,確認已選取變小的 AngularJS 1.2.x 版 (預設版本),然後選擇 [下載] 將 angular.min.js 指令碼儲存至您的電腦。

  2. 在 [下載 AngularJS] 對話方塊中,選擇 [瀏覽其他模組],並下載 angular-resource.min.js。

  3. 在 Visual Studio 方案總管中,於專案的 scripts 資料夾下加入新的資料夾,並將其命名為 frameworks

    注意事項注意事項

    在執行應用程式時,您無法加入此資料夾。按 Shift + F5 停止偵錯工具。

  4. 開啟 frameworks 資料夾的捷徑功能表,然後選擇 [加入] 和 [現有項目]。 將步驟 1 和 2 中的兩個 AngularJS 檔案加入專案。

更新指令碼參考

  • 在 index.html 中,會在 Cordova 和 platformOverrides 指令碼參考之後,於 <head> 項目中加入下列 AngularJS 參考。

        <script src="scripts/frameworks/angular.min.js"></script>
        <script src="scripts/frameworks/angular-resource.min.js"></script>
    

    <head> 項目中的指令碼參考應該看起來像這樣。

        <script src="cordova.js"></script>
        <script src="scripts/platformOverrides.js"></script>
        <script src="scripts/frameworks/angular.min.js"></script>
        <script src="scripts/frameworks/angular-resource.min.js"></script>
    
    注意事項注意事項

    cordova.js 需要在 AngularJS 架構檔案之前載入。

  • 在 <body> 項目結尾加入 AngularJS 模組的指令碼參考。 這些參考現在應該看起來像這樣。

        <script src="scripts/index.js"></script>
        <script src="scripts/services.js"></script>
        <script src="scripts/controllers.js"></script>
        <script src="scripts/directives.js"></script>
    

註冊應用程式模組

在本節中,您會註冊 AngularJS 應用程式模組,以協助個別的應用程式考量。 此應用程式中的模組包含的資料模型 (xPlat.services)、AngularJS 控制器 (xPlat.controller) 和 AngularJS 指示詞 (xPlat.directives) 可支援資料繫結。 若要註冊模組,請使用 angular.module 函式。

註冊 Angular 模組

  1. 在 [方案總管] 中,開啟 scripts 資料夾的捷徑功能表,然後選擇 [加入] 和 [新增項目]。

  2. 在 [加入新項目] 對話方塊中,選擇 [JavaScript 檔案],並將它命名為 services.js。

  3. 重複步驟 2,將兩個以上的 JavaScript 檔案加入 scripts 資料夾:

    • controllers.js

    • directives.js

  4. 開啟 index.js,並將預設程式碼取代為下列程式碼。

    (function() {
        'use strict';
        angular.module('xPlat', ['xPlat.services', 'xPlat.controllers', 'xPlat.directives']);
        angular.module('xPlat.directives', []);
        angular.module('xPlat.controllers', []);
        angular.module('xPlat.services', ['ngResource']);
    })();
    

加入資料模型

資料模型透過 xPlat.services 模組呈現,而您將在 services.js 檔案中實作後者。 此程式碼所含的服務使用 HTML5 Web 儲存體提供工作清單項目的本機存放區 (localStorage 屬性)。 在這個初始實作中,應用程式也提供 Bing Maps 服務的預留位置程式碼,稍後可以完全實作。 完整範例應用程式也會使用 Azure 來儲存資料。

在下列程式碼中,應用程式會呼叫 xPlat.services 模組的 Factory 方法,以產生每個資料模型服務,例如 localStorage 服務。 這裡要注意的一件事是,服務提供者函式中包含的 $q 服務元件。 這個物件可以啟用非同步程式設計,以便使用 $q.defer 建立 promise 物件。 使用 promise 物件,您可以在非同步作業完成時解決或拒絕此作業。

加入資料模型的程式碼

  • scripts 資料夾中,開啟 services.js,然後加入下列程式碼。

    (function () {
        'use strict';
    
        angular.module("xPlat.services")
            .factory("guidGenerator", function () {
                var generatePart = function () {
                    var guidPartNumber = (Math.random() * 0x10000) | 0;
                    return (guidPartNumber + 0x10000).toString(16).substring(1).toUpperCase();
                };
    
                return function () {
                    return generatePart()
                        + generatePart()
                        + "-"
                        + generatePart()
                        + "-"
                        + generatePart()
                        + "-"
                        + generatePart()
                        + "-"
                        + generatePart()
                        + generatePart()
                        + generatePart();
                };
            })
            .factory("localStorage", ['$q', "$window", "guidGenerator", function ($q, $window, guidGenerator) {
                var localStorageKey = "toDoItems";
    
                var loadFromStorage = function () {
                    return angular.fromJson($window.localStorage.getItem(localStorageKey)) || [];
                };
    
                var saveToStorage = function (items) {
                    $window.localStorage.setItem(localStorageKey, angular.toJson(items));
                }
    
                return {
                    getAll: function () {
                        return loadFromStorage();
                    },
    
                    create: function (text, address) {
                        var item = {
                            id: guidGenerator(),
                            text: text,
                            address: address,
                            done: false
                        }
                        var items = loadFromStorage();
                        items.push(item);
                        saveToStorage(items);
                        return $q.when(item);
                    },
    
                    update: function (item) {
                        var items = loadFromStorage();
                        for (var i = 0; i < items.length; i++) {
                            if (items[i].id === item.id) {
                                items[i] = item;
                                break;
                            }
                        }
    
                        saveToStorage(items);
                        return $q.when(item);
                    },
    
                    del: function (item) {
                        var items = loadFromStorage();
                        for (var i = 0; i < items.length; i++) {
                            if (items[i].id === item.id) {
                                items.splice(i, 1);
                                break;
                            }
                        }
    
                        saveToStorage(items);
                        return $q.when(null);
                    }
                }
            }])
    
            // To support Azure, add Azure storage service
            // code here ("azureStorage").
    
            .factory("storage", ["$injector", function ($injector) {
                // var azureService = $injector.get('azureStorage');
                // return azureService.isAvailable ? azureService : $injector.get('localStorage');
                return $injector.get('localStorage');
            }])
    
            // To support Bing maps, replace mapSimulator 
            // with map code.
            .factory('mapsSimulator', ["$rootScope", "$q", "$timeout", function(rootScope, $q, $timeout) {
    
                return {                
                    getUnknownAddress: function() {
                        var deferred = $q.defer();
    
                        $timeout(function() {
                            deferred.resolve([43.465187, -80.522372]);
                        }, 1500);
    
                        return deferred.promise;
                    }
                }
            }])
    
            .factory("cordova", ['$q', "$window", "$timeout", function ($q, $window, $timeout) {
                var deferred = $q.defer();
                var resolved = false;
    
                document.addEventListener('deviceready', function () {
                    resolved = true;
                    deferred.resolve($window.cordova);
                }, false);
    
                $timeout(function () {
                    if (!resolved && $window.cordova) {
                        deferred.resolve($window.cordova);
                    }
                });
    
                return { ready: deferred.promise };
            }]);
    })();
    

加入應用程式的檢視邏輯並實作資料繫結

在本節中,您將實作 AngularJS 控制器模組 (xPlat.controllers) 來處理檢視邏輯以及操作資料模型。 程式碼會實作 HTML 中的宣告式函式 (例如 addToDo),這樣會將新的工作項目加入清單。 在本節中,您也可以加入 AngularJS 指示詞,以協助實作雙向資料繫結。

此程式碼的重要層面是,使用 $scope 保持同步資料模型和檢視。 例如,藉由指定 $scope.addToDo = function () {},就能讓 addToDo 方法可用於檢視 (index.html) 中的宣告式繫結。

加入控制器

  • scripts 資料夾中,開啟 controllers.js,然後加入下列程式碼。

    index.html 中的 AngularJS ToDoCtrl 指示詞也會參考控制器名稱 ng-controller。

    (function () {
        'use strict';
    
        angular.module("xPlat.controllers")
            .controller('ToDoCtrl', ['$scope', 'mapsSimulator', 'storage', function ($scope, mapsSimulator, storage) {
            //.controller('ToDoCtrl', ['$scope', 'storage', function ($scope, storage) {
                var refresh = function () {
                    $scope.todos = storage.getAll();
                }
    
                var getAddress = function () {
                    //return maps.getCurrentPosition()
                    //    .then(maps.getAddressFromPosition, function (error) { return error.message; });
    
                    return mapsSimulator.getUnknownAddress();
                }
    
                $scope.addToDo = function () {
                    var text = $scope.newToDoText;
                    if (!text) {
                        return;
                    };
    
                    $scope.newToDoText = '';
                    getAddress().then(
                        function (address) {
                            return storage.create(text, address);
                        },
                        function (errorMessage) { return storage.create(text, errorMessage); })
                    .then(function (todo) {
                        $scope.todos.push(todo);
                    });
                }
    
                $scope.changeToDoText = function (toDoItem) {
                    getAddress().then(function (address) {
                        toDoItem.address = address;
                        return storage.update(toDoItem);
                    }, function (errorMessage) {
                        toDoItem.address = errorMessage;
                        return storage.update(toDoItem);
                    });
                }
    
                $scope.toggleToDoDone = function (toDoItem) {
                    toDoItem.done = !toDoItem.done;
                    storage.update(toDoItem);
                }
    
                $scope.removeToDo = function (toDoItem) {
                    storage.del(toDoItem).then(function (todo) {
                        var index = $scope.todos.indexOf(todo);
                        $scope.todos.splice(index, 1);
                    });
                }
                refresh();
            }]);
    })();
    

接下來,您將實作 directives 模組。 在這個程式碼中,您將建立自訂指示詞來指定 onchange DOM 事件的行為。 在執行階段中,此程式碼會將正確的事件處理常式 (宣告於 index.html 中的 HTML 標記) 與項目建立關聯,可以是 addToDoText 或 changeToDoText 函式。 這些會在 controllers.js 中實作。

加入資料繫結的指示詞

  • scripts 資料夾中,開啟 directives.js,然後加入下列程式碼。

    (function () {
        'use strict';
        angular.module('xPlat.directives')
            .directive('ngTextChange', function () {
                return {
                    restrict: 'A',
                    replace: 'ngModel',
                    link: function (scope, element, attr) {
                        element.on('change', function () {
                            scope.$apply(function () {
                                scope.$eval(attr.ngTextChange);
                            });
                        });
                    }
                };
            });
    })();
    

建置並執行應用程式

在這個步驟中,您將在 Windows 或 Apache Ripple 模擬器上執行 AngularJSToDo 清單應用程式。

建置和執行應用程式

  • 按 F5 鍵,在您先前指定的相同目標上執行應用程式。 Windows 和 Ripple 模擬器有最小安裝需求,因此我們建議您一開始以其中兩個平台為目標。

    下圖顯示 AngularJSToDo 清單應用程式在 Ripple 模擬器中之外觀的範例。

    在 Ripple 模擬器上執行待辦清單應用程式

加入 Bing Maps 服務

完整範例包含 Bing Maps 服務,可建立目前地址與每個工作清單項目的關聯。

將 Bing Maps 支援加入應用程式:

  1. 將 controllers.js 中的 getAddress 函式取代為完整範例中的下列程式碼。

    var getAddress = function() {
        return maps.getCurrentPosition()
            .then(maps.getAddressFromPosition,
             function(error) { return error.message; });
    }
    
  2. 將 controllers.js 中的兩個 mapsSimulator 參考取代為 maps 參考。

    angular.module("xPlat.controllers")
        .controller('ToDoCtrl', ['$scope', 'maps', 'storage', function ($scope, maps, storage) {
            var refresh = function () {
                $scope.todos = storage.getAll();
            }
    
  3. 將 services.js 中的 mapsSimulator 服務取代為完整範例中的下列程式碼。

            .factory("maps", ["$rootScope", "$q", "$window", "$resource", "cordova", function ($rootScope, $q, $window, $resource, cordova) {
                var key = ''; // Add your Bing Maps API key
                var url = 'http://dev.virtualearth.net/REST/v1/Locations/:latitude,:longitude?key='+key;
    
                return {
                    getCurrentPosition: function () {
                        return cordova.ready.then(function () {
                            var deferred = $q.defer();
                            $window.navigator.geolocation.getCurrentPosition(function (successValue) {
                                $rootScope.$apply(function () {
                                    deferred.resolve(successValue);
                                });
                            }, function (errorValue) {
                                $rootScope.$apply(function () {
                                    deferred.reject(errorValue);
                                });
                            });
    
                            return deferred.promise;
                        });
                    },
    
                    getAddressFromPosition: function (position) {
                        return $resource(url, {})
                            .get({ latitude: position.coords.latitude, longitude: position.coords.longitude })
                            .$promise.then(function(response) {
                                return response.resourceSets[0].resources[0].address.formattedAddress;
                            }, function (error) {
                                return position.coords.latitude + "," + position.coords.longitude
                            });
                    }
                }
            }])
    
  4. 在 [方案總管] 中按兩下 config.xml,並選擇 [外掛程式] 索引標籤,然後選擇 [地理位置],以將 Cordova Geolocation 外掛程式加入應用程式。

    如需詳細資訊,請參閱管理由 Visual Studio Tools for Apache Cordova 建置之應用程式的外掛程式

  5. 取得 Bing Maps 金鑰,並將它包括在 services.js 中已更新程式碼所指示的位置。

加入 Azure 行動服務

完整範例包括額外的程式碼,以使用 Azure 行動服務來儲存和擷取工作清單項目。 在 services.js 中,會將這個程式碼實作為其他服務 (名稱為 azureStorage)。 您可以從完整範例應用程式取得這個程式碼,也可以遵循這裡的指示加入服務。

將 Azure 行動服務加入應用程式

  1. 如果您尚未擁有,請建立 Microsoft Azure 帳戶

  2. 遵循新增已連線服務的指示,將 Azure 行動服務加入您的應用程式,以及建立 SQL 資料庫。

    注意事項注意事項

    如果專案中還沒有 services.js 檔案,便會在您新增已連線服務後加入該檔案。產生的程式碼會不同於 ToDoList 範例應用程式。

  3. 在 services.js 中,取消註解泛型 "storage" 服務的下列數行程式碼。

                // var azureService = $injector.get('azureStorage');
                // return azureService.isAvailable ? azureService : $injector.get('localStorage');
    

    並移除下一行程式碼:

                return $injector.get('localStorage');
    

    在取消註解程式碼並移除指定的程式碼之後,泛型 "storage" 服務程式碼看起來像這樣。

            .factory("storage", ["$injector", function ($injector) {
                var azureService = $injector.get('azureStorage');
               return azureService.isAvailable ? azureService : $injector.get('localStorage');
    
            }])
    
  4. 在 services.js 中,於程式碼註解所指出的位置加入 Azure 服務的程式碼。

            // To support Azure, add Azure storage service
            // code here ("azureStorage").
    
            .factory("azureStorage", ["$q", "$resource", "$rootScope", "guidGenerator", function ($q, $resource, $rootScope, guidGenerator) {
                var azureMobileServicesInstallationId = guidGenerator();
                var azureMobileServicesKey = ''; // Add your Azure Mobile Service Application Key
                var azureMobileServicesAddress = ''; // Add your Azure Mobile Service Application URL
                var azureMobileServicesTableAddress = azureMobileServicesAddress + 'tables/todoitem/:id';
                var headers = {
                    'X-ZUMO-APPLICATION': azureMobileServicesKey,
                    'X-ZUMO-INSTALLATION-ID': azureMobileServicesInstallationId,
                    'X-ZUMO-VERSION': 'ZUMO/1.0 (lang=Web; os=--; os_version=--; arch=--; version=1.0.20218.0)',
                    'Content-Type':'application/json'
                };
    
                var toDoItem = $resource(azureMobileServicesTableAddress, { id: '@id' }, {
                    'query': {
                        method: 'GET',
                        params: { $top: '1000' },
                        isArray: true,
                        headers: headers
                    },
                    'delete': {
                        method: 'DELETE',
                        headers: headers
                    },
                    'save': {
                        method: 'POST',
                        headers: headers
                    },
                    'update': {
                        method: 'PATCH',
                        headers: headers
                    }
                });
    
    
                var azureStorage = {
                    getAll: function () {
                        return toDoItem.query();
                    },
    
                    create: function (text, address) {
                        var item = new toDoItem({
                            text: text,
                            address: address,
                            done: false
                        });
    
                        return item.$save();
                    },
    
                    update: function (item) {
                        return item.$update();
                    },
    
                    del: function (item) {
                        return item.$delete();
                    },
                };
    
                Object.defineProperty(azureStorage, "isAvailable", {
                    enumerable: false,
                    get : function(){ return azureMobileServicesKey && azureMobileServicesAddress; },
                });
    
                return azureStorage;
            }])
    
  5. 取得與 Azure 帳戶相關聯的 Azure 行動服務應用程式金鑰和 URL,並將它們包含在先前程式碼中指出的位置。

  6. 在 [方案總管] 中按兩下 config.xml,並選擇 [外掛程式] 索引標籤,然後選擇 [Azure 行動服務用戶端],以將 Cordova Azure 行動服務外掛程式加入應用程式。

    如需詳細資訊,請參閱管理由 Visual Studio Tools for Apache Cordova 建置之應用程式的外掛程式