使用TypeScript,AngularJs和Web API构建基本的CRUD Web 应用

   2023-02-10 学习力0
核心提示:原文地址:using typescript with angularjs and web api 版权归其作者所有.在这篇文章中我将向大家展示如何使用TypeScript,Angular Js 和Asp.net Web API 来构建一个基本的实现CRUD功能的Web应用程序. Typescript提供了一系列的功能来方便程序员构造和组织更

原文地址:using typescript with angularjs and web api 版权归其作者所有.

在这篇文章中我将向大家展示如何使用TypeScript,Angular Js 和Asp.net Web API 来构建一个基本的实现CRUD功能的Web应用程序. Typescript提供了一系列的功能来方便程序员构造和组织更具有可维护性的Js应用程序.同时也可以集成现有的第三方库文件,你可以在接下来的Demo中看到这项特性.这个基本的HTML应用将借助Asp.net Web API实现增,删,查,改功能.

主要特点如下:

  • 使用TypeScript构建AngularJs的Controller,
  • 使用TypeScript并利用AngularJs 的Ajax功能与Web API进行通信,
  • 使用TypeScript的强类型来定义AngularJs对象.

在这个例子中,我使用VS 2012和Sublime Text来编写代码.你也可以选择自己喜欢的文本编辑器,如果你需要语法高亮或者代码自动补全功能,你需要单独下载程序包.

对于VS插件和windows下的可执行文件(tsc.exe,安装包的一部分),请访问: http://www.typescriptlang.org/. 如果你想选择一个不同的编辑器,(例如:Sublime Text或者Vim),请从这里寻找帮助 : http://aka.ms/qwe1qu. TypeScript编译程序是必不可少的工具.

服务端通过Asp.net Web API实现(.Net平台下构建Http服务的实现,我个人很喜欢),当然你也可以选择自己喜欢的技术.

使用Asp.net Web API 提供Http服务.

对于这个例子,我处理的模型由一个单一实体构成----Product.

//Model
public
abstract class Entity { public Guid Id { get; set; } } public class Product : Entity { public string Name { get; set; } public decimal Price { get; set; } }

我们需要一个持久化机制来存储这些实体.我选择使用仓储模式把这些内容存在内存里.请根据需要,随意替换成适合你的东西(例如:Entity Framework或者Nhibernate.)

// IRepository
public
interface IRepository<TEntity> where TEntity : Entity { TEntity Add(TEntity entity); TEntity Delete(Guid id); TEntity Get(Guid id); TEntity Update(TEntity entity); IQueryable<TEntity> Items { get; } }
//InMemoryRepository
public class InMemoryRepository<TEntity> : IRepository<TEntity> where TEntity : Entity
{
    private readonly ConcurrentDictionary<Guid, TEntity> _concurrentDictionary 
        = new ConcurrentDictionary<Guid, TEntity>();

    public TEntity Add(TEntity entity)
    {
        if (entity == null)
        {
            //we dont want to store nulls in our collection
            throw new ArgumentNullException("entity");
        }

        if (entity.Id == Guid.Empty)
        {
            //we assume no Guid collisions will occur
            entity.Id = Guid.NewGuid();
        }

        if (_concurrentDictionary.ContainsKey(entity.Id))
        {
            return null;
        }

        bool result = _concurrentDictionary.TryAdd(entity.Id, entity);

        if (result == false)
        {
            return null;
        }
        return entity;
    }

    public TEntity Delete(Guid id)
    {
        TEntity removed;
        if (!_concurrentDictionary.ContainsKey(id))
        {
            return null;
        }
        bool result = _concurrentDictionary.TryRemove(id, out removed);
        if (!result)
        {
            return null;
        }
        return removed;
    }

    public TEntity Get(Guid id)
    {
        if (!_concurrentDictionary.ContainsKey(id))
        {
            return null;
        }
        TEntity entity;
        bool result = _concurrentDictionary.TryGetValue(id, out entity);
        if (!result)
        {
            return null;
        }
        return entity;
    }

    public TEntity Update(TEntity entity)
    {
        if (entity == null)
        {
            throw new ArgumentNullException("entity");
        }
        if (!_concurrentDictionary.ContainsKey(entity.Id))
        {
            return null;
        }
        _concurrentDictionary[entity.Id] = entity;
        return entity;
    }

    public IQueryable<TEntity> Items
    {
        get { return _concurrentDictionary.Values.AsQueryable(); }
    }
}

一旦我们在这里完成了对象持久化,我们就可以创造一个Http服务,来提供一些基本的操作.我使用的是Asp.net Web API,所以我还要再创建一个 Controller.

//Product HTTP Service
public class ProductsController : ApiController
{
    public static IRepository<Product> ProductRepository
        = new InMemoryRepository<Product>();

    public IEnumerable<Product> Get()
    {
        return ProductRepository.Items.ToArray();
    }

    public Product Get(Guid id)
    {
        Product entity = ProductRepository.Get(id);
        if (entity == null)
        {
            throw new HttpResponseException(HttpStatusCode.NotFound);
        }
        return entity;
    }

    public HttpResponseMessage Post(Product value)
    {
        var result = ProductRepository.Add(value);
        if (result == null)
        {
            // the entity with this key already exists
            throw new HttpResponseException(HttpStatusCode.Conflict);
        }
        var response = Request.CreateResponse<Product>(HttpStatusCode.Created, value);
        string uri = Url.Link("DefaultApi", new { id = value.Id });
        response.Headers.Location = new Uri(uri);
        return response;
    }

    public HttpResponseMessage Put(Guid id, Product value)
    {
        value.Id = id;
        var result = ProductRepository.Update(value);
        if (result == null)
        {
            // entity does not exist
            throw new HttpResponseException(HttpStatusCode.NotFound);
        }
        return Request.CreateResponse(HttpStatusCode.NoContent);
    }

    public HttpResponseMessage Delete(Guid id)
    {
        var result = ProductRepository.Delete(id);
        if (result == null)
        {
            throw new HttpResponseException(HttpStatusCode.NotFound);
        }
        return Request.CreateResponse(HttpStatusCode.NoContent);
    }
}

我们努力去实现标准的Http,因此附加逻辑来处理 Response.在这个步骤结束后,我们将会有一个功能完整的,(实现了CRUD)Http服务.

使用TypeScript,AngularJs和Web API构建基本的CRUD Web 应用

 

开始使用Angular Js 和 TypeScript

服务端创建好以后,我们接着开始创建真正的网站部分.它将完全由Html/CSS/Js(TypeScript将会编译成Js)构成.我选择的初始模版像这样:

<!DOCTYPE html>
<html ng-app>
<head>
    <title>Product list</title>
    <link rel="stylesheet" href="Content/bootstrap.css"/>
    <script type="text/javascript" src="Scripts/bootstrap.js"></script>
    <script type="text/javascript" src="Scripts/angular.js"></script>
    <script type="text/javascript" src="Scripts/Controllers/ProductsController.js"></script>
</head>
    <body>
        <div ng-controller="Products.Controller">
        </div>
    </body>
</html>

 

请注意:ProductsController.js文件是从名为ProductsController.ts的TypeScript源代码通过tsc.exe编译得到的.(我使用了命令行来执行这个编译步骤.).让我们为这个页面创建一个Angular Js的Controller.

 

//ProductsController.ts
module Products {
    export interface Scope {
        greetingText: string;
    }

    export class Controller {
        constructor ($scope: Scope) {
            $scope.greetingText = "Hello from TypeScript + AngularJS";
        }
    }
}

 

Produscts Module将被编译成一个 Js的命名空间,我们的Controller将被转译为 Products.Controller供程序使用.现在我们可以在页面中绑定一个欢迎致辞.请注意:结合TypeScript的特点,我们以Scope接口的形式定义了$scope对象.Typescript也允许我们使用 any 这种类型来定义,但就个人而言,我更倾向于使用更加严格的定义方式,因为他可以帮助你在编译时捕获错误信息.(VS2012甚至会在你编写的错误代码下面加入红色下划线,这真是太棒了.)现在,我们需要编译ProductsController.ts,在HTML中引用ProductsController.js,并且修改视图(view)来显示信息.

<div ng-controller="Products.Controller">
    <p>{{greetingText}}</p>
</div>

使用TypeScript,AngularJs和Web API构建基本的CRUD Web 应用

现在AngularJs Controller已经完成,让我们继续添加更多的功能.

创建Model模块

我们将创建一个Model模块,它会包含一个Product类,作为DTO对象(序列化为JSON)与Http的服务端进行交互.

 

module Model {
    export class Product {
        Id: string;
        Name: string;
        Price: number;
    }
}

 

这个简单的模块包含了一个类型的定义,将会在页面的contrller中使用.

环境声明( ambient declarations.)

为了使用AngularJs提供的Ajax功能,我们将$Http服务传入到Controller的构造器中:

 

class Controller {
    private httpService: any;

    constructor ($scope: Scope, $http: any) {
        this.httpService = $http;
        //...
    }
    //...
}

 

由于我们将$Http定义成了any的类型,所以编译器不会帮助我们在编译时发现潜在的错误.为了解决这个问题,我们使用环境声明(译者注:元数据??).环境声明用来告诉编译器将要被引入的元素有特殊的意义(在这里是指Angular Js)并且不会被扩展.换而言之就是第三方类库的接口.声明源文件(.d.ts扩展名)被限制为只能包含环境声明.下面的angular.d.ts文件定义了两个接口,被我们用来调用Http服务.

 

declare module Angular {
    export interface HttpPromise {
        success(callback: Function) : HttpPromise;
        error(callback: Function) : HttpPromise;
    }
    export interface Http {
        get(url: string): HttpPromise;
        post(url: string, data: any): HttpPromise;
        delete(url: string): HttpPromise;
    }
}

 

declare关键字是可选的,他会被隐式声明在所有的 .d.ts 文件中.

TypeScript 和 Angular Js

为了让编译器知道新增的两个模块(Model和Angular),我们需要添加两个引用信息到ProductsController.ts中.同时我们想要定义 Scope接口来包含视图使用的所有属性和方法.

页面将包含一个新增Product的表单(name,price文本框和一个按钮)同时展示一个包含所有Product的列表,其中的每个记录都可以被单独的删除.为了使演示变的简单,我忽略了更新记录的功能,但是只要我们实现了相应的操作,更新实现起来也是很简单的.

Scope接口看起来如下:

/// <reference path='angular.d.ts' />
/// <reference path='model.ts' />

module Products {

    export interface Scope {
        newProductName: string;
        newProductPrice: number;
        products: Model.Product[];
        addNewProduct: Function;
        deleteProduct: Function;
    }
    // ...
}

只要有product被新增或者被删除,我们就从服务端重新获取所有的product并刷新列表.由于先前我们所做的工作,现在我们可以使用强类型的 Angular.Http和Angular.HttpPromise接口.

controller将包含私有方法与我们的服务端进行通信(getAllProducts, addProduct and deleteProduct).

export class Controller {
    private httpService: any;

    constructor ($scope: Scope, $http: any) {
        this.httpService = $http;

        this.refreshProducts($scope);

        var controller = this;

        $scope.addNewProduct = function () {
            var newProduct = new Model.Product();
            newProduct.Name = $scope.newProductName;
            newProduct.Price = $scope.newProductPrice;

            controller.addProduct(newProduct, function () {
                controller.getAllProducts(function (data) {
                    $scope.products = data;
                });
            });
        };

        $scope.deleteProduct = function (productId) {
            controller.deleteProduct(productId, function () {
                controller.getAllProducts(function (data) {
                    $scope.products = data;
                });
            });
        }
    }

    getAllProducts(successCallback: Function): void{
        this.httpService.get('/api/products').success(function (data, status) {
            successCallback(data);
        });
    }

    addProduct(product: Model.Product, successCallback: Function): void {
        this.httpService.post('/api/products', product).success(function () {
            successCallback();
        });
    }

    deleteProduct(productId: string, successCallback: Function): void {
        this.httpService.delete('/api/products/'+productId).success(function () {
            successCallback();
        });
    }

    refreshProducts(scope: Scope) {
        this.getAllProducts(function (data) {
                    scope.products = data;
                });
    }

}

非常棒的一点就是,我们不需要人为的引入任何定制的序列化逻辑.当通过$http服务取回数据后,我们可以把他们当成强类型的Product集合进行操作.add操作也是一样----我们仅仅传入一个Product,他将被自动序列化并最终在服务端被解析.

创建视图(View)

最后一步,我们需要创建一个集合新controller特性的视图.我将使用bootstrap来使他变简单一些.

 

<!DOCTYPE html>
<html ng-app>
<head>
    <title>Product list</title>
    <link rel="stylesheet" href="Content/bootstrap.css" />
    <script type="text/javascript" src="Scripts/angular.js"></script>
    <script type="text/javascript" src="Scripts/Controllers/model.js"></script>
    <script type="text/javascript" src="Scripts/Controllers/productsController.js"></script>
</head>
<body>
    <div ng-controller="Products.Controller">
        <form class="form-horizontal" ng-submit="addNewProduct()">
            <input type="text" ng-model="newProductName" size="30"
                placeholder="product name">
            <input type="text" ng-model="newProductPrice" size="5"
                placeholder="product price">
            <button class="btn" type="submit" value="add">
                <i class="icon-plus"></i>
            </button>
        </form>
        <table class="table table-striped table-hover" style="width: 500px;">
            <thead>
                <tr>
                    <th>Name</th>
                    <th>Price</th>
                    <th></th>
                </tr>
            </thead>
            <tbody>
                <tr ng-repeat="product in products">
                    <td>{{product.Name}}</td>
                    <td>${{product.Price}}</td>
                    <td>
                        <button class="btn-small" ng-click="deleteProduct(product.Id)">
                            <i class="icon-trash"></i>
                        </button>
                    </td>
                </tr>
            </tbody>
        </table>
    </div>
</body>
</html>

 

最终的结果就像这样:

 

使用TypeScript,AngularJs和Web API构建基本的CRUD Web 应用

现在我们的页面应该实现了应有的功能,并且可以与Http 服务端按照预期的情况进行通信工作了.

使用TypeScript,AngularJs和Web API构建基本的CRUD Web 应用

 

最后:Wordpress和Android应用可能会因为一些原因影响post数据,不完整版,非常抱歉.

 

 
反对 0举报 0 评论 0
 

免责声明:本文仅代表作者个人观点,与乐学笔记(本网)无关。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
    本网站有部分内容均转载自其它媒体,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责,若因作品内容、知识产权、版权和其他问题,请及时提供相关证明等材料并与我们留言联系,本网站将在规定时间内给予删除等相关处理.

  • 项目中使用TypeScript的TodoList实例详解
    项目中使用TypeScript的TodoList实例详解
    目录为什么用todolisttodolist的ts化数据到视图实现handleTodoItemreadonly分类交叉类型新增功能联合类型可选属性数据转视图总结为什么用todolist现代的框架教程目前再也不是写个hello world那么简单了,而是需要有一定基础能力能够做到数据绑定、遍历、条件
    03-16
  • React之 hook / class 结合typescript笔记
    React之 hook / class 结合typescript笔记
    使用 create-react-app 开启 TypeScriptCreate React App 是一个官方支持的创建 React 单页应用程序的CLI,它提供了一个零配置的现代构建设置。当你使用 Create React App 来创建一个新的 TypeScript React 工程时,你可以运行 npx create-react-app my-app
    03-08
  • Angular基础(三) TypeScript
    Angular基础(三) TypeScript
       一、模仿Reddita) 运行ng new –ng4angular-reddit创建应用,从随书代码中复制样式文件,新建组件app-root,代码为:界面可以看到了:b) 对于界面输入的数据,获取的方式有点特别,使用了#newlink这样的语法,newlink是一个对象,现在代表就是所在的inp
    03-08
  • electron教程(番外篇二): 使用TypeScript版本的
    electron教程(一): electron的安装和项目的创建electron教程(番外篇一): 开发环境及插件, VSCode调试, ESLint + Google JavaScript Style Guide代码规范electron教程(番外篇二): 使用TypeScript版本的electron, VSCode调试TypeScript, TS版本的ESLintelectron
    03-08
  • 使用 ESModule 和 TypeScript 构建 Node.js 环境
    使用 ESModule 和 TypeScript 构建 Node.js 环
    介绍由于我经常使用 React,所以我在前端接触过 Node.js,但我从未接触过后端。正常搭建环境的时候,不能使用import语句,变成了require语句,很不方便。我认为有各种各样的错误,所以如果你能指出它们,我将不胜感激。执行环境macOS 蒙特雷 ver12.5.1MacBook
    03-08
  • [个人发展] 我做了一个可以永远谈论任何事情的女士对话AI(TypeScript,Python)
    [个人发展] 我做了一个可以永远谈论任何事情的
    在个人发展中对话式人工智能服务 Eveki我做了虚构角色1这是一项以人工智能为特色的服务,可以再现并享受自然对话。这一次,作为第一个艾小姐发表了。请先尝试实物。服务概览与人工智能对话基本上只需输入您的信息是。对话是用女士的语言进行的,就像人类一样
    03-08
  • 使用 Node.js (TypeScript) 和 Azure Functions 创建无服务器 REST API,并获得 CosmosDB 更改源作为奖励。
    使用 Node.js (TypeScript) 和 Azure Functions
    介绍在本文中,我们将使用 azure 函数和 ComsmosDB 创建一个无服务器 REST API 应用程序。使用的语言是 Node.js/TypeScript。此外,由于我们使用 CosmosDB 作为数据库,因此我们将使用 Azure 函数触发器接收 Change Feed 事件作为奖励。创建资源创建资源组az
    03-08
  • 安装 TypeScript 并编译成JS
    安装 TypeScript 并编译成JS
    官网: https://github.com/microsoft/TypeScriptTypeScript是一种由微软开发的开源、跨平台的编程语言。它是JavaScript的超集,最终会被编译为JavaScript代码。TypeScript是一种应用级JavaScript语言。TypeScript为JavaScript添加了可选类型,支持针对任何浏
    03-08
  • Typescript 中类的继承
    Typescript中类的定义与继承与后端开发语言java/C#等非常像,实现起来非常方便,而且代码便于阅读。用Typescript写较大项目时是非常有优势的。/** * BaseClass */class BaseClass {constructor(name:string,age:number) {this.name=name;this.age=age;}name:s
    02-09
  • TypeScript实现设计模式——工厂模式
    上回用typescript实现了单例模式,这回来实现工厂模式。工厂模式又分为简单工厂模式、工厂方法模式以及抽象工厂模式。简单工厂模式简单工厂模式通常在业务比较简单的情况下使用,它有三个部分组成:工厂类、抽象产品类、具体产品类。抽象产品类abstract class
    02-09
点击排行