2017-09-01 47 views
0

我正在使用帶有角度1.6.x和Typescript的Webpack,並且我退出了使用角度DI來支持ES6導入。當我需要一個像$http$resource和這樣一些NG功能,我把他們注入直接使用angular.injector功能通過一個裝飾,如:AngularJS - 使用ES6導入代替角度DI系統

// 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]); 

我不知道這是否符合最佳實踐與否,但目前它的工作狀況非常好。

我想聽聽你對這個問題的想法:使用這種方法是否存在任何問題(表現,不良習慣等)?

+0

角度模塊/ DI和ES6模塊相互補充。它們不可互換。 *直接使用angular.injector * - 這是非常錯誤的,你很少需要使用'angular.injector',因爲它沒有達到你期望的效果。 – estus

+0

我覺得這是一個很好的問題,但在這裏寫的地方不合適。你有代碼是完全有效的,這是第一個紅旗,以及聲明「我想聽聽你對這個主題的想法」,這幾乎直接在[dont-ask]中引用(https://stackoverflow.com /幫助/不-問)。我認爲這個問題是有價值的,但是你可能想要考慮將其重新說成更多關於這種技術的問題和原因,而不是討論問題。 – Claies

回答

2

ES模塊不能代替角模塊和DI。它們彼此互補,並保持應用程序的模塊化和可測試性。

ES6模塊提供了額外的可擴展層,例如控制器/服務子類(這些東西在Angular模塊和DI單獨使用時看起來不太好)。

與ES6或打字稿中推薦的方法是做DI以往,$inject註釋:

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

這也是一個很好的做法,每個文件一個模塊,這樣的應用程序都模塊化和可測試:

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

default出口是模塊名稱,可以在另一個模塊引入直接依賴於它:

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

應用程序注入器不能從裝飾器正常到達。即使可以用黑客來製作它,它也會在測試中混亂。

angular.injector創造了新的注射器(即應用實例),並在生產中非常有限的正確用法:

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

它經常被誤當開發人員不知道如何獲得當前$injector實例。它肯定不應該用在像這樣的情況下。

+0

謝謝。我確實知道你在這裏發佈的這種方法,但只是想出了使用angular.injector通過裝飾器使用角度私有函數的想法,並且不知道它是否是好的。我想現在我會堅持使用有角度的DI。 – darksoulsong

+0

在那裏,做到了。不,這確實不是一個好習慣。理論上可能會在引導過程中暴露一個噴油器,並在裝飾器中使用它,但這可能會破壞事物,因爲可能同時有多個噴油器。 TypeScript中通常需要答案中顯示的樣式(對於ES6它可能會有所不同)。 – estus