65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 TypeScript 和 AngularJS 的 SharePoint 应用

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.78/5 (9投票s)

2016年2月22日

CPOL

2分钟阅读

viewsIcon

27558

downloadIcon

296

如何使用 TypeScript 和 Angular Js 创建 SharePoint 应用。

TypeScript 是什么

  • 它为 JavaScript 添加了静态类型和结构化(类、模块等)。
  • 类型注解
  • 静态类型检查
  • 类型定义
  • 编译时检查
  • 开源
  • Angular2 支持

强类型

TypeScript 定义了成员变量和函数参数的类型。在转换为 JavaScript 时,类型会被移除。这使得编译器能够在编译时捕获类型错误,并为 IDE 提供智能感知功能。

JavaScript Typescript
function test(a ,b )
{
    return a*b;        
}
alert(test('one','two'))
function test(a:number,b:number):number
{
    return a*b;
}
alert(test(10,20));

编译器

我们用 TypeScript 编写的代码会被编译成 JavaScript 和映射文件。映射文件用于将 JavaScript 和 TypeScript 文件行映射起来,以便调试 TypeScript。

编译:tsc test.ts -> test.js

在将 TypeScript 代码编译成 JavaScript 时,类型注解会被移除。

var a:number = 3;                            var a = 3;
var b:string = 'abc';                        var b = 'abc';

DefinitelyTyped

DefinitelyTyped 以接口的形式为现有的许多 JavaScript 库添加了定义。

  • 描述了外部库中定义的类型(d.ts
  • 仅用于开发目的,不部署
  • 用于检查类型

替代方案

  • Dart
  • CoffeeScript
  • ClojureScript
  • Fay

模块 & 导出关键字

模块与 C# 中的 namespace 相同,用于避免名称冲突并获得 IIFE 的功能。

使用模块的 TypeScript

要使模块的内部方面在模块外部可访问,我们需要使用 export 关键字声明。由于 Angular 控制器会访问模型和服务,因此我们使用了 export 关键字。

使用 NuGet 包管理器创建一个 SharePoint 托管应用和必要的 TypeScript 定义文件。

验证项目属性中是否可用 TypeScript 选项

如果缺少 TypeScript 选项,请按照以下步骤操作

卸载项目

编辑项目并包含以下行

<PropertyGroup>
<TypeScriptSourceMap>true</TypeScriptSourceMap>
</PropertyGroup>
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\
TypeScript\Microsoft.TypeScript.targets" />

保存并重新加载项目。

通过包管理器控制台包含 DefinitelyTyped。

Install-Package angularjs.TypeScript.DefinitelyTyped

Project.ts

module App.Model {

    export class Project {
        public Title: string;
        public Id: number;
        public Client: string;

    }
}

ProjectService.ts

///<reference path="project.ts">
module App.Service {
    export class ProjectService {

        static $inject = ['$http'];
        constructor(private $http: ng.IHttpService) {
        }

        public getProjects(): ng.IPromise<any> {
            var url = App.Config.appWebUrl + "/_api/SP.AppContextSite(@target)" +
                "/web/lists/getbytitle('Projects')/items?$select=Title,ID,Client&" +
                "@target='" + App.Config.hostUrl + "'";
            console.log(url);
            return this.$http({
                method: 'GET',
                url: url,
                headers: { "Accept": "application/json; odata=verbose" }
            });
        }

        public addProject(project: App.Model.Project): any {
            console.log($("#__REQUESTDIGEST").val());
            var data = {
                __metadata: { 'type': 'SP.Data.ProjectsListItem' },
                Title: project.Title,
                Client: project.Client
            };
            var url = App.Config.appWebUrl + "/_api/SP.AppContextSite(@target)" +
                "/web/lists/getbytitle('Projects')/items?" + 
                "@target='" + App.Config.hostUrl + "'";
            return this.$http({
                url: url,
                method: "POST",
                headers: {
                    "Content-Type": "application/json;odata=verbose",
                    "Accept": "application/json;odata=verbose",
                    "X-RequestDigest": $("#__REQUESTDIGEST").val()

                },
                data: data
            });
        }
    }
}

$Inject

如果没有注入,程序在 Js 被压缩之前可以正常工作。压缩过程可能会更改参数的名称,从而导致 Angular 无法注入。

$inject 是 AngularJS 的一个特殊属性,用于确定需要在运行时注入哪些服务。它应该标记为 static,并且是一个 string 数组。数组 string 的顺序和构造函数参数的顺序应该匹配。

ProjectCtrl.ts

///<reference path="projectservice.ts" />
module App.Controller {

    export class ProjectCtrl {
        public projects: Array<App.Model.Project>
        public project: App.Model.Project;

        static $inject = ['ProjectService'];
        constructor(private projectService: App.Service.ProjectService) {
            this.project = new App.Model.Project();
        }
        public getProjects(): void {
            this.projectService.getProjects().then(data => {
                this.projects = data.data.d.results;
                console.log(this.projects);
            }).catch(e => {
                alert('Error' + e);
            });
        }

        public addProject(): void {
            this.projectService.addProject(this.project).then(data => {
                this.getProjects();
                this.project = new App.Model.Project();
            }).catch(e => {
                alert('Error' + e);
            });
        }
    }
}

App.ts

///<reference path="../scripts/typings/angularjs/angular.d.ts" />
///<reference path="../scripts/typings/angular-ui-router/angular-ui-router.d.ts" />
///<reference path="project/projectctrl.ts" />
module App {
    export class Config {
        private static manageQueryStringParameter(paramToRetrieve: string): any {
            var params =
                document.URL.split("?")[1].split("&");
            var strParams = "";
            for (var i = 0; i < params.length; i = i + 1) {
                var singleParam = params[i].split("=");
                if (singleParam[0] == paramToRetrieve)
                    return singleParam[1];
            }
        }

        public static appWebUrl: string;
        public static hostUrl: string;

        static $inject = ["$stateProvider", "$urlRouterProvider"];

        public static loadConfig(): void {
            Config.appWebUrl = decodeURIComponent(this.manageQueryStringParameter("SPAppWebUrl"));
            Config.hostUrl = decodeURIComponent(this.manageQueryStringParameter("SPHostUrl"));
        }
    }
    var main = angular.module('projectApp', ['ui.router']);
    App.Config.loadConfig();
    main.controller('ProjectCtrl', App.Controller.ProjectCtrl);
    main.service('ProjectService', ['$http', '$q', App.Service.ProjectService]);
}

构建项目并合并 TS 文件。

构建并将 test.js 和 test.map 文件包含在项目中。

打开element.xml,删除 .ts 文件路径,并包含 test.js 和 test.map 文件。

    <?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <Module Name="App">
    <File Path="App\test.js" Url="App/test.js" ReplaceContent="TRUE" />
    <File Path="App\test.js.map" Url="App/test.js.map" ReplaceContent="TRUE" />
  </Module>
</Elements>
<html>
<head>
    <link rel="Stylesheet" type="text/css" href="../Content/App.css" />
    <script src="../Scripts/jquery-1.9.1.js"></script>
    <script src="../Scripts/angular.js"></script>
    <script src="../Scripts/angular-ui-router.js"></script>
    <script src="../App/test.js"></script>
</head>
<body>
    <form runat="server">
    </form>
    <h1>Project </h1>
    <div ng-app="projectApp">
        <div ng-controller="ProjectCtrl as vm">
            <div style="float: left; border: 1px solid gray;">
                <table ng-init="vm.getProjects()">
                    <tr>
                        <td>SNO</td>
                        <td>Project</td>
                        <td>Client</td>
                    </tr>
                    <tr ng-repeat="project in vm.projects">
                        <td>{{$index+1}}</td>
                        <td>{{project.Title}}</td>
                        <td>{{project.Client}}</td>
                    </tr>
                </table>
            </div>
            <div>
                <table>
                    <tr>
                        <td>Project</td>
                        <td>
                            <input type="text" ng-model="vm.project.Title" /></td>
                    </tr>
                    <tr>
                        <td>Client</td>
                        <td>
                            <input type="text" ng-model="vm.project.Client" /></td>
                    </tr>
                    <tr>
                        <td colspan="2">
                            <button ng-click="vm.addProject()">Add Project</button></td>
                    </tr>
                </table>
            </div>
        </div>
    </div>
</body>
</html>
© . All rights reserved.