AngularJS-使用ES6导入而不是angular DI系统 [英] AngularJS - Use ES6 imports instead of angular DI system

查看:117
本文介绍了AngularJS-使用ES6导入而不是angular DI系统的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在将Webpack与angular 1.6.x和Typescript一起使用,而我退出使用angular DI来支持ES6导入.当我需要诸如$http$resource之类的ng函数时,我可以通过装饰器使用angular.injector函数直接注入它们,如下所示:

I'm using Webpack with angular 1.6.x and Typescript and I quit using angular DI in favor of ES6 imports. When I need some ng functions like $http, $resource and such I inject them directly using the angular.injector function through a decorator, like this:

// inject.ts
    import * as angular from 'angular';

    export function inject (...params: string[]) {

        function doCall ( param: string, klass: Function) {
            const injector = angular.injector([ 'ng' ]);
            const service = injector.get(param);
            try {
                klass.prototype[ param ] = service;
            } catch ( e ) {
                window.console.warn( e );
            }
        }

        // tslint:disable-next-line:ban-types
        return function ( klass: Function ) {
            params.forEach( ( param ) => {
                doCall( param, klass );
            } );
        };
    }

// posts.service.ts
import { inject } from './inject';
import { IPost, Post } from './post';

@inject('$http')
export class PostsService {
    public $http: angular.IHttpService;
    get (): Promise<IPost[]> {
        const posts: IPost[] = [];
        const promise = new Promise<IPost[]>( (resolve, reject) => {
            this.$http.get<IPost[]>('https://jsonplaceholder.typicode.com/posts')
            .then(( response ) => {
                response.data.forEach(item => {
                    posts.push( new Post(item) );
                });

                resolve( posts );
            });
        });

        return promise;
    }
}


// post.ts
export interface IPost {
    userId: number;
    id: number;
    title: string;
    body: string;
}
export class Post implements IPost {
    userId: number;
    id: number;
    title: string;
    body: string;

    constructor (item: IPost) {
        this.userId = item.userId;
        this.id = item.id;
        this.title = item.title;
        this.body = item.body;
    }
}


// controller.ts
import { IPost } from './post';
import { PostsService } from './posts.service';

export class Controller {
    public postService: PostsService;
    public posts: IPost[];
    constructor ( private $scope: angular.IScope ) {
        this.postService = new PostsService();
    }

    $onInit () {
        this.postService.get()
        .then((posts) => {
            this.posts = posts;
            this.$scope.$digest();
        });
    }
}

// index.ts
import * as angular from 'angular';

import { Controller } from './app/controller';

import './index.scss';

export const app: string = 'app';

angular
  .module(app, [])
  .controller('controller', Controller);


angular.bootstrap(document.body, [app]);

我不知道它是否符合最佳实践,但到目前为止,它运行良好.

I don't know if it's in compliance with best practices or not, but it is working quite nicely so far.

我想听听您对这个问题的想法:使用这种方法是否存在任何问题(性能,不良做法等)?

I would like to hear your thoughts on the subject: is there any problem (performance, bad practice and such) using this approach?

推荐答案

ES模块无法替换Angular模块和DI.它们彼此互补,并保持应用程序模块化和可测试.

ES modules cannot replace Angular modules and DI. They compliment each other and keep the application modular and testable.

ES6模块提供了额外的可扩展性,例如控制器/服务子类化(仅使用Angular模块和DI时看起来不太好).

ES6 modules provide extra layer of extensibility, for example controller/service subclassing (something that doesn't look good with Angular modules and DI alone).

ES6或TypeScript的推荐方法是按常规方式进行DI,并带有$inject注释:

The recommended approach with ES6 or TypeScript is to do DI conventionally, with $inject annotation:

export class PostsService {
  static $inject = ['$http'];
  constructor(
    public $http: angular.IHttpService
  ) {}
  ...
}

每个文件有一个模块也是一种好习惯,这样应用程序可以保持模块化和可测试性:

It's also a good practice to have one module per file, this way the application stays modular and testable:

export default angular.module('app.posts', [])
  .service('posts', `PostsService)
  .name;`

default导出是可以在直接依赖于它的另一个模块中导入的模块名称:

Its default export is module name that can be imported in another module that directly depends on it:

import postsModule from '...';
...
export default angular.module('app.controller', [postsModule])
  .controller('controller', Controller)
  .name;`

通常无法从装饰器到达应用程序注入器.即使黑客有可能使其在生产环境中正常工作,它也会在测试中混乱.

Application injector cannot be normally reached from a decorator. Even if it's possible with a hack to make it work in production, it will be messed up in tests.

angular.injector创建新的注入器(即应用程序实例),并且在生产中的使用用途非常有限:

angular.injector creates new injector (i.e. application instance) and has very limited proper uses in production:

angular.injector(['ng']).get('$rootScope') !== angular.injector(['ng']).get('$rootScope');

当开发人员不知道如何获取当前的$injector实例时,通常会滥用它.当然不应该在这种情况下使用它.

It is often misused when a developer doesn't know how to get current $injector instance. It certainly shouldn't be used in a case like this one.

这篇关于AngularJS-使用ES6导入而不是angular DI系统的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆