[Angular 2] Understanding OpaqueToken
When using provider string tokens, there’s a chance they collide with other third-party tokens. Angular has with the concept of opaque tokens, that allow us to make whatever token we use unique, so we don’t run into collision problems. In this lesson we’ll explore how they work.
providers: [ TodoService, ConsoleService, TranslateService, ,{ provide: LoggerProvider, useFactory: (cs, ts) => { return new LoggerProvider(cs, ts, true) }, deps: [ConsoleService, TranslateService] } ,{ provide: apiUrl, useValue: 'http://localhost:3000/api' } ],
It turns out that this can be problematic in case we're using, for example, a third-party library that comes with its own provider that introduces the same token.
third-party.ts:
export const THIRD_PARTY_PRIVODERS = [ { provide: apiUrl, useValue: 'someurl' } ]
So when you inject third-pary library into our app.ts:
providers: [ TodoService, ConsoleService, TranslateService, ,{ provide: LoggerProvider, useFactory: (cs, ts) => { return new LoggerProvider(cs, ts, true) }, deps: [ConsoleService, TranslateService] } ,{ provide: apiUrl, useValue: 'http://localhost:3000/api' } ,THIRD_PARTY_PROVIDERS ],
Then it will rewrite our 'apiUrl' because THIRD_PARTY_PROVIDERS comes behind apiUrl.
To solve this problem, Angular introduce OpaqueToken.
app.tokens.ts:
import {OpaqueToken} from '@angular/core'; export const API_URL = new OpaqueToken('apiUrl')
Now 'API_URL' is a class instance not just a string, class instance is always unique.
Then in app.ts:
import {API_URL} from './app.tokens' providers: [ TodoService, ConsoleService, TranslateService, ,{ provide: LoggerProvider, useFactory: (cs, ts) => { return new LoggerProvider(cs, ts, true) }, deps: [ConsoleService, TranslateService] } ,{ provide: API_URL, useValue: 'http://localhost:3000/api' } ,THIRD_PARTY_PROVIDERS ],
In DataService:
import {LoggerProvider} from './LoggerProvider'; import {Injectable} from '@angular/core'; import {Http} from '@angular/core'; import {Inject} from '@angular/core'; import {API_URL} from './app.tokens'; @Injectable export class TodoService{ constructor(@Inject(API_URL) private apiUrl, private logger: LoggerProvider, private http: Http){ } getTodos(){ this.logger.debug('Items', this.todos); return this.http.get(`${this.apiUrl}/todos`).map(res => res.json()); } }
Now we won't have conflict anymore.
As a general rule, always create opaque tokens when using string tokens for providers. For example:
third-party.ts:
import {OpaqueToken} from '@angular/core'; const API_URL = new OpaqueToken('apiUrl'); const CONFIG_URL = new OpaqueToken('configUrl'); export const THIRD_PARTY_PROVIDERS = [ { provide: API_URL, useValue: 'somevalue' }, { provide: CONFIG_URL, useValue: 'somevalue' } ]
相关文章
- AngularJS进阶(五)Angular实现下拉菜单多选
- 模块化开发 Angular 应用 [含懒加载]
- Angular SSR 应用的 SEO 实现一个例子 - meta 和 title 元素的赋值
- 如何在Angular项目中使用MQTT
- Angular HTTPClient 发送请求的触发方式讨论
- Angular 里 HTTP 请求和响应结构的拦截器(interceptors)在 SAP Spartacus 中的应用
- Angular 面试题汇总2-Component/Service (Angular v8+)
- Angular Universal Application 应该处理 HTTP POST 请求吗?
- 关于在 Angular 应用里重复调用 RouterModule.forRoot(ROUTES) 的讨论
- 【Angular教程】组件动效u002F动态组件u002F视图封装模式
- 【Angular教程】-内容投影u002F@ContentChildu002F@ViewChild
- 使用 Angular HTTP_INTERCEPTOR 拦截器来记录超时请求的一些思考
- 什么是 Angular library 的 secondary entry points?