From d33b95228b9126bebceeddba0883e62ebe43a52a Mon Sep 17 00:00:00 2001 From: Minh Van Date: Fri, 23 Sep 2016 23:28:30 +0700 Subject: [PATCH 1/6] Init "Dependency Injection" article --- .../_article-1474380939.component.js | 126 ++++++++++++++ .../article-1474380939.component.js | 126 ++++++++++++++ ...article-1474380939.component.prebuild.json | 4 + .../code-blocks/class-provider-1.html | 5 + .../code-blocks/class-provider-2.html | 7 + .../code-blocks/class-provider-3.html | 60 +++++++ .../code-blocks/dependency-visibility.html | 51 ++++++ .../code-blocks/factory-provider.html | 42 +++++ .../code-blocks/host-dependency.html | 11 ++ .../code-blocks/optional-dependency.html | 13 ++ .../1474380939/code-blocks/simple-di.html | 52 ++++++ .../code-blocks/value-provider-1.html | 13 ++ .../code-blocks/value-provider-2.html | 45 +++++ cms/articles/1474380939/index.js | 15 ++ .../classProvider-example-1474380939.png | Bin 0 -> 52538 bytes ...ependencyVisibility-example-1474380939.png | Bin 0 -> 47102 bytes .../images/simpleDI-example-1474380939.png | Bin 0 -> 41381 bytes .../templates/article-1474380939.html | 159 ++++++++++++++++++ cms/articles/index.js | 6 +- 19 files changed, 734 insertions(+), 1 deletion(-) create mode 100644 cms/articles/1474380939/_article-1474380939.component.js create mode 100644 cms/articles/1474380939/article-1474380939.component.js create mode 100644 cms/articles/1474380939/article-1474380939.component.prebuild.json create mode 100644 cms/articles/1474380939/code-blocks/class-provider-1.html create mode 100644 cms/articles/1474380939/code-blocks/class-provider-2.html create mode 100644 cms/articles/1474380939/code-blocks/class-provider-3.html create mode 100644 cms/articles/1474380939/code-blocks/dependency-visibility.html create mode 100644 cms/articles/1474380939/code-blocks/factory-provider.html create mode 100644 cms/articles/1474380939/code-blocks/host-dependency.html create mode 100644 cms/articles/1474380939/code-blocks/optional-dependency.html create mode 100644 cms/articles/1474380939/code-blocks/simple-di.html create mode 100644 cms/articles/1474380939/code-blocks/value-provider-1.html create mode 100644 cms/articles/1474380939/code-blocks/value-provider-2.html create mode 100644 cms/articles/1474380939/index.js create mode 100644 cms/articles/1474380939/resources/images/classProvider-example-1474380939.png create mode 100644 cms/articles/1474380939/resources/images/dependencyVisibility-example-1474380939.png create mode 100644 cms/articles/1474380939/resources/images/simpleDI-example-1474380939.png create mode 100644 cms/articles/1474380939/templates/article-1474380939.html diff --git a/cms/articles/1474380939/_article-1474380939.component.js b/cms/articles/1474380939/_article-1474380939.component.js new file mode 100644 index 0000000..f5b4f6c --- /dev/null +++ b/cms/articles/1474380939/_article-1474380939.component.js @@ -0,0 +1,126 @@ +import * as ngCore from '@angular/core'; +import { DomSanitizationService } from '@angular/platform-browser'; +import highlight from 'highlight.js'; + +import { + CODE_PANEL_DIRECTIVES, + HIGHLIGHT_DIRECTIVES +} from 'xblog-cores/components'; +import { resourceUtils } from 'xblog-cores/utils'; +import { cmsArticleService } from '../../cores/services'; + +function _article1474380939Component(){ + this.constructor = [ + DomSanitizationService, + cmsArticleService, + + function article1474380939Component(sanitizer, articleService){ + this.id = 1474380939; + this.sanitizer = sanitizer; + this.articleService = articleService; + } + ]; + + this.ngOnInit = function() { + this.simpleDI = { + sourceCode: { + name: 'simple-di', + link: resourceUtils.getGithubArticleFileLink(this.id, 'simple-di') + }, + codeBlocks: { + 1: this.getCodeBlock('simple-di.html') + }, + screenCaptures: { + 1: resourceUtils.getImg('simpleDI-example-1474380939.png') + } + }; + + this.classProvider = { + sourceCode: { + name: 'class-provider', + link: resourceUtils.getGithubArticleFileLink(this.id, 'class-provider') + }, + codeBlocks: { + 1: this.getCodeBlock('class-provider-1.html'), + 2: this.getCodeBlock('class-provider-2.html'), + 3: this.getCodeBlock('class-provider-3.html') + }, + screenCaptures: { + 1: resourceUtils.getImg('classProvider-example-1474380939.png') + } + }; + + this.valueProvider = { + sourceCode: { + name: 'value-provider', + link: resourceUtils.getGithubArticleFileLink(this.id, 'value-provider') + }, + codeBlocks: { + 1: this.getCodeBlock('value-provider-1.html'), + 2: this.getCodeBlock('value-provider-2.html') + } + }; + + this.factoryProvider = { + sourceCode: { + name: 'factory-provider', + link: resourceUtils.getGithubArticleFileLink(this.id, 'factory-provider') + }, + codeBlocks: { + 1: this.getCodeBlock('factory-provider.html') + } + }; + + this.optionalDependency = { + sourceCode: { + name: 'optional-dependency', + link: resourceUtils.getGithubArticleFileLink(this.id, 'optional-dependency') + }, + codeBlocks: { + 1: this.getCodeBlock('optional-dependency.html') + } + }; + + this.hostDependency = { + sourceCode: { + name: 'host-dependency', + link: resourceUtils.getGithubArticleFileLink(this.id, 'host-dependency') + }, + codeBlocks: { + 1: this.getCodeBlock('host-dependency.html') + } + }; + + this.dependencyVisibility = { + sourceCode: { + name: 'dependency-visibility', + link: resourceUtils.getGithubArticleFileLink(this.id, 'dependency-visibility') + }, + codeBlocks: { + 1: this.getCodeBlock('dependency-visibility.html') + }, + screenCaptures: { + 1: resourceUtils.getImg('dependencyVisibility-example-1474380939.png') + } + }; + }; + + this.getCodeBlock = function(fileName) { + var _codeBlock = this.articleService.getCodeBlock(this.id, fileName); + _codeBlock = highlight.highlightAuto(_codeBlock, ['javascript']).value; + return this.sanitizer.bypassSecurityTrustHtml(_codeBlock); + }; +} + +export var article1474380939Component = ngCore.Component({ + selector: 'article', + templateUrl: './templates/article-1474380939.html', + directives: [ + CODE_PANEL_DIRECTIVES, + HIGHLIGHT_DIRECTIVES + ], + host: { + '[class.xblog-article-1474380939]': 'true' + } +}) +.Class(new _article1474380939Component()); diff --git a/cms/articles/1474380939/article-1474380939.component.js b/cms/articles/1474380939/article-1474380939.component.js new file mode 100644 index 0000000..474c2a3 --- /dev/null +++ b/cms/articles/1474380939/article-1474380939.component.js @@ -0,0 +1,126 @@ +import * as ngCore from '@angular/core'; +import { DomSanitizationService } from '@angular/platform-browser'; +import highlight from 'highlight.js'; + +import { + CODE_PANEL_DIRECTIVES, + HIGHLIGHT_DIRECTIVES +} from 'xblog-cores/components'; +import { resourceUtils } from 'xblog-cores/utils'; +import { cmsArticleService } from '../../cores/services'; + +function _article1474380939Component(){ + this.constructor = [ + DomSanitizationService, + cmsArticleService, + + function article1474380939Component(sanitizer, articleService){ + this.id = 1474380939; + this.sanitizer = sanitizer; + this.articleService = articleService; + } + ]; + + this.ngOnInit = function() { + this.simpleDI = { + sourceCode: { + name: 'simple-di', + link: resourceUtils.getGithubArticleFileLink(this.id, 'simple-di') + }, + codeBlocks: { + 1: this.getCodeBlock('simple-di.html') + }, + screenCaptures: { + 1: resourceUtils.getImg('simpleDI-example-1474380939.png') + } + }; + + this.classProvider = { + sourceCode: { + name: 'class-provider', + link: resourceUtils.getGithubArticleFileLink(this.id, 'class-provider') + }, + codeBlocks: { + 1: this.getCodeBlock('class-provider-1.html'), + 2: this.getCodeBlock('class-provider-2.html'), + 3: this.getCodeBlock('class-provider-3.html') + }, + screenCaptures: { + 1: resourceUtils.getImg('classProvider-example-1474380939.png') + } + }; + + this.valueProvider = { + sourceCode: { + name: 'value-provider', + link: resourceUtils.getGithubArticleFileLink(this.id, 'value-provider') + }, + codeBlocks: { + 1: this.getCodeBlock('value-provider-1.html'), + 2: this.getCodeBlock('value-provider-2.html') + } + }; + + this.factoryProvider = { + sourceCode: { + name: 'factory-provider', + link: resourceUtils.getGithubArticleFileLink(this.id, 'factory-provider') + }, + codeBlocks: { + 1: this.getCodeBlock('factory-provider.html') + } + }; + + this.optionalDependency = { + sourceCode: { + name: 'optional-dependency', + link: resourceUtils.getGithubArticleFileLink(this.id, 'optional-dependency') + }, + codeBlocks: { + 1: this.getCodeBlock('optional-dependency.html') + } + }; + + this.hostDependency = { + sourceCode: { + name: 'host-dependency', + link: resourceUtils.getGithubArticleFileLink(this.id, 'host-dependency') + }, + codeBlocks: { + 1: this.getCodeBlock('host-dependency.html') + } + }; + + this.dependencyVisibility = { + sourceCode: { + name: 'dependency-visibility', + link: resourceUtils.getGithubArticleFileLink(this.id, 'dependency-visibility') + }, + codeBlocks: { + 1: this.getCodeBlock('dependency-visibility.html') + }, + screenCaptures: { + 1: resourceUtils.getImg('dependencyVisibility-example-1474380939.png') + } + }; + }; + + this.getCodeBlock = function(fileName) { + var _codeBlock = this.articleService.getCodeBlock(this.id, fileName); + _codeBlock = highlight.highlightAuto(_codeBlock, ['javascript']).value; + return this.sanitizer.bypassSecurityTrustHtml(_codeBlock); + }; +} + +export var article1474380939Component = ngCore.Component({ + selector: 'article', + template: "

Angular ships with its own dependency injection framework and we really can't build an Angular application without it

An Angular application is a tree of components. Each component instance has its own injector. The tree of components parallels the tree of injectors.

We can re-configure the injectors at any level of that component tree with interesting and useful results.


Consider a simple example about TodosComponent


{{simpleDI.sourceCode.name}}full code

Each component instance gets its own injector and an injector at one level is a child injector of the injector above it in the tree.


When a component at the bottom requests a dependency, Angular tries to satisfy that dependency with a provider registered in that component's own injector.

If the component's injector lacks the provider, it passes the request up to its parent component's injector. If that injector can't satisfy the request, it passes it along to its parent component's injector.

The requests keep bubbling up until we find an injector that can handle the request or run out of component ancestors. If we run out of ancestors, Angular throws an error.


Dependencies are singletons within the scope of an injector.


In our example, logSerivce are shared among todosComponent, todoListComponent, todoItemComponent. Because it is hosted by todosComponent which is parents of todoListComponent & todoItemComponent

todoListComponent can inject logSerivce from todosComponent via its constructor. However, nested injectors at todoItemComponent create their own service instances by using providers to host logService itself



Injector providers

A provider provides the concrete of a dependency value.

The injector relies on providers to create instances of the services that the injector injects into components and other services.


As you know, we can register service provider or directive provider by using providers & directives in component's declaration

Look back our example, you can see the way we registered logSerivce in TodosComponent


But there are many ways that we can configure the injector with alternative providers that can deliver an object that behaves like logSerivce. We'll expore them now.


Class Provider

We wrote the providers array like this: providers: [ logSerivce ]

This is actually a short-hand expression for a provider registration




The first is the token that serves as the key for both locating a dependency value and registering the provider.

The second is a provider definition object, which we can think of as a recipe for creating the dependency value


With this expression, it's easy for us specify another class to provide the service

For example we have another service is superLogService, We can register it for todoListComponent with logSerivce token instead of logSerivce class




However, lets look back the example that you registered logService in todosComponent then you used useClass to register superLogService in todoListComponent

So how can todoItemComponent inject logService from todoComponent instead of superLogService from todoListComponent ?


The solution for this case is you should use useExisting with rootLogService token for register in todosComponent


{{classProvider.sourceCode.name}}full code


Value Provider

Sometimes it's easier to provide a object rather than ask the injector to create it from a class.

We can re-write superLogService as an object then registering it by using useValue like this




Now, you have seen I used a class as the token such as logService, rootLogService for register, acttualy, there's another way for you to get the same result.

The way I'm mentioning is using OpaqueToken & ngCore.Inject


{{valueProvider.sourceCode.name}}full code

OpaqueToken is a good solution for us to inject global variables such as window, localstorage into our component


Factory provider

Sometimes we need to create the dependent value dynamically, based on information we won't have until the last possible moment. This situation calls for a factory provider.


Let's illustrate, we want to implement a logic like that if user is authenticated, superLogService should be injected into our components, otherwise, logSerivce should be used.

Assume that we have userService which provide information about authentication. We re-write declaration for providers as below


{{factoryProvider.sourceCode.name}}full code

The deps property is an array of provider tokens which our factory requires for injection


Optional dependencies

As you know, if Angular can't resolve injection for component, it'll throw an exception.

In fact, there're situations, we allow the constructor's arguments to be null. We can tell Angular that the dependency is optional by annotating the constructor argument with Optional

Of course, your code must be prepared to handle a null value.


{{optionalDependency.sourceCode.name}}full code

Dependency visibility

Well, as we learned, we can use the providers property to define providers for its injector.

However, it turns out that there’s another property viewProviders that basically allows us to do the same thing. What’s the difference between those two them ?


viewProviders allows us to define injector providers that are only available for a component’s view.

Let’s take a closer look at what that means by using our TodosComponent example.


{{dependencyVisibility.sourceCode.name}}full code

As you can see, todoTitleComponent is contentChild of TodoListComponent, todoItemComponent is viewChild of TodoListComponent

Both todoTitleComponent & todoItemComponent require an instance of the class which is provided via logSerivce token

How should we do if we expect that todoTitleComponent require logSerivce's instance, todoItemComponent require superLogService's instance ?


With viewProviders we can tell the DI system very specifically, which providers are available to which child injectors.

To make our code work as expected, all we have to do is to make the supperLogService provider of todoListComponent explicitly available only for its viewChild by using viewProviders instead of providers



Now, whenever a component of todoListComponent’s view asks for something of type logSerivce, it’ll get an instance of superLogService as expected.

Other child components from the outside world(contentChild) that ask for the same type, however, they won’t see this provider and will continue with the lookup in the injector tree.

Which means todoTitleComponent now gets an expected instance from another parent injector without even knowing that todoListComponent actually introduces its own provider.


Note that, viewProviders are also only available in components, not in directives. That’s simply because a directive doesn’t have its own view.


Restricting dependency lookup

We'll go on with the example in Dependency visibility subject.

Now, look back again, in the example, todoItemComponent requires logSerivce, follow DI rules, it will receice superLogService which is provided by todoListComponent.

This's so cool, however this can be problematic. Just imagine someone uses our todoItemComponent with their customTodoListComponent which doesn't provide superLogService.

What will happen ? our todoItemComponent will receice logSerivce's instance from another parent injector instead. It's unexpected.


If we need to ensure that superLogService instance is always instatiated by our component’s host or an exception should be thrown. Host dependency is a solution for us.


{{hostDependency.sourceCode.name}}full code", + directives: [ + CODE_PANEL_DIRECTIVES, + HIGHLIGHT_DIRECTIVES + ], + host: { + '[class.xblog-article-1474380939]': 'true' + } +}) +.Class(new _article1474380939Component()); diff --git a/cms/articles/1474380939/article-1474380939.component.prebuild.json b/cms/articles/1474380939/article-1474380939.component.prebuild.json new file mode 100644 index 0000000..da22ce5 --- /dev/null +++ b/cms/articles/1474380939/article-1474380939.component.prebuild.json @@ -0,0 +1,4 @@ +{ + "origin": "./cms/articles/1474380939/_article-1474380939.component.js", + "inline": "./cms/articles/1474380939/article-1474380939.component.js" +} \ No newline at end of file diff --git a/cms/articles/1474380939/code-blocks/class-provider-1.html b/cms/articles/1474380939/code-blocks/class-provider-1.html new file mode 100644 index 0000000..05b98d3 --- /dev/null +++ b/cms/articles/1474380939/code-blocks/class-provider-1.html @@ -0,0 +1,5 @@ +ngCore.Component({ + ..... + providers: [{ provide: logSerivce, useClass: logSerivce }] +}) +.Class(.....); \ No newline at end of file diff --git a/cms/articles/1474380939/code-blocks/class-provider-2.html b/cms/articles/1474380939/code-blocks/class-provider-2.html new file mode 100644 index 0000000..e48610b --- /dev/null +++ b/cms/articles/1474380939/code-blocks/class-provider-2.html @@ -0,0 +1,7 @@ +export var todoListComponent = ngCore.Component({ + ..... + providers: [ + { provide: logService, useClass: supperLogService } + ] +}) +.Class(new _todoListComponent()); \ No newline at end of file diff --git a/cms/articles/1474380939/code-blocks/class-provider-3.html b/cms/articles/1474380939/code-blocks/class-provider-3.html new file mode 100644 index 0000000..e886661 --- /dev/null +++ b/cms/articles/1474380939/code-blocks/class-provider-3.html @@ -0,0 +1,60 @@ +import * as ngCore from '@angular/core'; + +function _rootLogService(){ + this.constructor = function(){}; +} +export var rootLogService = ngCore.Class(new _rootLogService()); + +/*---------------------------------------------------------*/ + +function _supperLogService(){ + this.constructor = function(){ + this.name = 'supperLogService'; + }; +} +export var supperLogService = ngCore.Class(new _supperLogService()); + +/*---------------------------------------------------------*/ + +function _todoItemComponent(){ + this.constructor = [rootLogService, function(logService){ + console.log('todoItemComponent', logService.name); + }]; +}; +export var todoItemComponent = ngCore.Component({ + ..... +}) +.Class(new _todoItemComponent()); + +/*---------------------------------------------------------*/ + +function _todoListComponent(){ + this.constructor = [logService, function(logService){ + console.log('todoListComponent', logService.name + ' is hosted by todoListComponent'); + }]; +}; +export var todoListComponent = ngCore.Component({ + ..... + directives: [ todoItemComponent ], + providers: [ + { provide: logService, useClass: supperLogService } + ] +}) +.Class(new _todoListComponent()); + +/*---------------------------------------------------------*/ + +function _todosComponent(){ + this.constructor = [logService, function(logService){ + logService.setName('logService is hosted by todosComponent'); + }]; +}; +export var todosComponent = ngCore.Component({ + ..... + directives: [ todoListComponent, todoItemComponent ], + providers: [ + logService, + { provide: rootLogService, useExisting: logService } + ] +}) +.Class(new _todosComponent()); diff --git a/cms/articles/1474380939/code-blocks/dependency-visibility.html b/cms/articles/1474380939/code-blocks/dependency-visibility.html new file mode 100644 index 0000000..309e0f3 --- /dev/null +++ b/cms/articles/1474380939/code-blocks/dependency-visibility.html @@ -0,0 +1,51 @@ +function _todoTitleComponent(){ + this.constructor = [logService, function(logService){ + console.log('todoTitleComponent', logService.name); + }]; +} +export var todoTitleComponent = ngCore.Component({.....}) +.Class(new _todoTitleComponent()); + +/*---------------------------------------------------------*/ + +function _todoItemComponent(){ + this.constructor = [logService, function(logService){ + console.log('todoItemComponent', logService.name); + }]; +} +export var todoItemComponent = ngCore.Component({.....}) +.Class(new _todoItemComponent()); + +/*---------------------------------------------------------*/ + +function _todoListComponent(){ + this.constructor = [logService, function(logService){}]; +} + +export var todoListComponent = ngCore.Component({ + ..... + template: [ + '', + '' + ].join(''), + viewProviders: [ + { provide: logService, useClass: supperLogService } + ] +}) +.Class(new _todoListComponent()); + +/*---------------------------------------------------------*/ + +function _todosComponent(){ + this.constructor = [logService, function(logService){}]; +} +export var todosComponent = ngCore.Component({ + ..... + template: [ + '', + '', + '' + ].join(''), + providers: [ logService ] +}) +.Class(new _todosComponent()); \ No newline at end of file diff --git a/cms/articles/1474380939/code-blocks/factory-provider.html b/cms/articles/1474380939/code-blocks/factory-provider.html new file mode 100644 index 0000000..df51139 --- /dev/null +++ b/cms/articles/1474380939/code-blocks/factory-provider.html @@ -0,0 +1,42 @@ +function _userService(){ + this.constructor = function(){}; + + this.setAuth = function(isAuth){ + this.isAuth = isAuth; + }; +} +export var userService = ngCore.Class(new _userService()); + +/*---------------------------------------------------------*/ + +function _todoListComponent(){ + this.constructor = [logService, function(logService){ + console.log('todoListComponent', logService.name); + }]; +} +export var todoListComponent = ngCore.Component({ + ..... + providers: [ + { + provide: logService, + useFactory: function(userService){ + return userService.isAuth ? new supperLogService() : new logService(); + }, + deps: [userService] + } + ] +}) +.Class(new _todoListComponent()); + +/*---------------------------------------------------------*/ + +function _todosComponent(){ + this.constructor = [userService, function(userService){ + this.userService.setAuth(true); + }]; +} +export var todosComponent = ngCore.Component({ + ..... + providers: [ userService ] +}) +.Class(new _todosComponent()); \ No newline at end of file diff --git a/cms/articles/1474380939/code-blocks/host-dependency.html b/cms/articles/1474380939/code-blocks/host-dependency.html new file mode 100644 index 0000000..2c3315b --- /dev/null +++ b/cms/articles/1474380939/code-blocks/host-dependency.html @@ -0,0 +1,11 @@ +function _todoItemComponent(){ + this.constructor = [ + [ new ngCore.Host(), ngCore.Inject(logService) ], + + function(logService){ + console.log('todoItemComponent', logService.name); + } + ]; +} +export var todoItemComponent = ngCore.Component({.....}) +.Class(new _todoItemComponent()); \ No newline at end of file diff --git a/cms/articles/1474380939/code-blocks/optional-dependency.html b/cms/articles/1474380939/code-blocks/optional-dependency.html new file mode 100644 index 0000000..853e51a --- /dev/null +++ b/cms/articles/1474380939/code-blocks/optional-dependency.html @@ -0,0 +1,13 @@ +function _todoListComponent(){ + this.constructor = [ + [ new ngCore.Optional(), ngCore.Inject(logService) ], + + function(logService){ + if(!logService) { + console.log('todoListComponent', 'logService is null'); + } + } + ]; +} +export var todoListComponent = ngCore.Component({.....}) +.Class(new _todoListComponent()); \ No newline at end of file diff --git a/cms/articles/1474380939/code-blocks/simple-di.html b/cms/articles/1474380939/code-blocks/simple-di.html new file mode 100644 index 0000000..1ea1e96 --- /dev/null +++ b/cms/articles/1474380939/code-blocks/simple-di.html @@ -0,0 +1,52 @@ +import * as ngCore from '@angular/core'; + +function _logService(){ + this.constructor = function(){ + this.name = 'logService'; + }; + + this.setName = function(name){ + this.name = name; + }; +}; +export var logService = ngCore.Class(new _logService()); + +/*---------------------------------------------------------*/ + +function _todoItemComponent(){ + this.constructor = [logService, function(logService){ + console.log('todoItemComponent', logService.name); + }]; +}; +export var todoItemComponent = ngCore.Component({ + ..... + providers: [ logService ] +}) +.Class(new _todoItemComponent()); + +/*---------------------------------------------------------*/ + +function _todoListComponent(){ + this.constructor = [logService, function(logService){ + console.log('todoListComponent', logService.name); + }]; +}; +export var todoListComponent = ngCore.Component({ + ..... + directives: [ todoItemComponent ] +}) +.Class(new _todoListComponent()); + +/*---------------------------------------------------------*/ + +function _todosComponent(){ + this.constructor = [logService, function(logService){ + logService.setName('logService is hosted by todosComponent'); + }]; +}; +export var todosComponent = ngCore.Component({ + ..... + providers: [ logService ], + directives: [ todoListComponent, todoItemComponent ] +}) +.Class(new _todosComponent()); diff --git a/cms/articles/1474380939/code-blocks/value-provider-1.html b/cms/articles/1474380939/code-blocks/value-provider-1.html new file mode 100644 index 0000000..29aeeab --- /dev/null +++ b/cms/articles/1474380939/code-blocks/value-provider-1.html @@ -0,0 +1,13 @@ +export var supperLogService = { + name: 'supperLogService' +}; + +/*---------------------------------------------------------*/ + +export var todoListComponent = ngCore.Component({ + ..... + providers: [ + { provide: logService, useValue: supperLogService } + ] +}) +.Class(new _todoListComponent()); \ No newline at end of file diff --git a/cms/articles/1474380939/code-blocks/value-provider-2.html b/cms/articles/1474380939/code-blocks/value-provider-2.html new file mode 100644 index 0000000..eb0b135 --- /dev/null +++ b/cms/articles/1474380939/code-blocks/value-provider-2.html @@ -0,0 +1,45 @@ +import { OpaqueToken } from '@angular/core'; + +export var WINDOW = new OpaqueToken('window'); + +export var WINDOW_PROVIDERS = [ + { provide: WINDOW, useValue: window } +]; + +/*---------------------------------------------------------*/ + +import { WINDOW } from './window.model'; + +function _logService(){ + this.constructor = [ + ngCore.Inject(WINDOW), + + function(window){ + this.window = window; + } + ]; + + this.log = function(text){ + this.window.console.log(text); + } +} +export var logService = ngCore.Class(new _logService()); + +/*---------------------------------------------------------*/ + +import { WINDOW_PROVIDERS } from './window.model'; + +function _todosComponent(){ + this.constructor = [logService, function(logService){ + logService.log('This message is logged by using window.console via DI'); + }]; +} +export var todosComponent = ngCore.Component({ + ..... + providers: [ + logService, + WINDOW_PROVIDERS + ] +}) +.Class(new _todosComponent()); + diff --git a/cms/articles/1474380939/index.js b/cms/articles/1474380939/index.js new file mode 100644 index 0000000..17767a6 --- /dev/null +++ b/cms/articles/1474380939/index.js @@ -0,0 +1,15 @@ +import { resourceUtils } from 'xblog-cores/utils'; +import { article1474380939Component } from './article-1474380939.component'; + +export var article1474380939 = { + id: 1474380939, + title: 'Dependency Injection', + postedDate: 'Tue Sep 20 2016 21:15:38 GMT+0700 (SE Asia Standard Time)', + author: 'Minh Van', + cover: resourceUtils.getImg('xblog-home-cover.jpg'), + routeLink: resourceUtils.getArticleRouteLink('dependency-injection-1474380939.html'), + relatedArticles: [], + tags: [], + description: 'An Angular application is a tree of components. Each component instance has its own injector! The tree of components parallels the tree of injectors. We can re-configure the injectors at any level of that component tree with interesting and useful results', + content: article1474380939Component, +}; diff --git a/cms/articles/1474380939/resources/images/classProvider-example-1474380939.png b/cms/articles/1474380939/resources/images/classProvider-example-1474380939.png new file mode 100644 index 0000000000000000000000000000000000000000..9edbd04aeed79625aeda93daf68890c7e4614a31 GIT binary patch literal 52538 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 QXy9YQHnpbjN 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 literal 0 HcmV?d00001 diff --git a/cms/articles/1474380939/resources/images/dependencyVisibility-example-1474380939.png b/cms/articles/1474380939/resources/images/dependencyVisibility-example-1474380939.png new file mode 100644 index 0000000000000000000000000000000000000000..c78149f3babe861260b566e0f7338069a986b418 GIT binary patch literal 47102 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 ships with its own dependency injection framework and we really can't build an Angular application without it

+

An Angular application is a tree of components. Each component instance has its own injector. The tree of components parallels the tree of injectors.

+

We can re-configure the injectors at any level of that component tree with interesting and useful results.

+
+

Consider a simple example about TodosComponent

+
+ + {{simpleDI.sourceCode.name}} + full code + + +
+
+

Each component instance gets its own injector and an injector at one level is a child injector of the injector above it in the tree.

+
+

When a component at the bottom requests a dependency, Angular tries to satisfy that dependency with a provider registered in that component's own injector.

+

If the component's injector lacks the provider, it passes the request up to its parent component's injector. If that injector can't satisfy the request, it passes it along to its parent component's injector.

+

The requests keep bubbling up until we find an injector that can handle the request or run out of component ancestors. If we run out of ancestors, Angular throws an error.

+
+

Dependencies are singletons within the scope of an injector.

+
+

In our example, logSerivce are shared among todosComponent, todoListComponent, todoItemComponent. Because it is hosted by todosComponent which is parents of todoListComponent & todoItemComponent

+

todoListComponent can inject logSerivce from todosComponent via its constructor. However, nested injectors at todoItemComponent create their own service instances by using providers to host logService itself

+
+
+
+

Injector providers

+

A provider provides the concrete of a dependency value.

+

The injector relies on providers to create instances of the services that the injector injects into components and other services.

+
+

As you know, we can register service provider or directive provider by using providers & directives in component's declaration

+

Look back our example, you can see the way we registered logSerivce in TodosComponent

+
+

But there are many ways that we can configure the injector with alternative providers that can deliver an object that behaves like logSerivce. We'll expore them now.

+
+

Class Provider

+

We wrote the providers array like this: providers: [ logSerivce ]

+

This is actually a short-hand expression for a provider registration

+
+ + + +
+
+

The first is the token that serves as the key for both locating a dependency value and registering the provider.

+

The second is a provider definition object, which we can think of as a recipe for creating the dependency value

+
+

With this expression, it's easy for us specify another class to provide the service

+

For example we have another service is superLogService, We can register it for todoListComponent with logSerivce token instead of logSerivce class

+
+ + + +
+
+

However, lets look back the example that you registered logService in todosComponent then you used useClass to register superLogService in todoListComponent

+

So how can todoItemComponent inject logService from todoComponent instead of superLogService from todoListComponent ?

+
+

The solution for this case is you should use useExisting with rootLogService token for register in todosComponent

+
+ + {{classProvider.sourceCode.name}} + full code + + +
+
+
+
+

Value Provider

+

Sometimes it's easier to provide a object rather than ask the injector to create it from a class.

+

We can re-write superLogService as an object then registering it by using useValue like this

+
+ + + +
+
+

Now, you have seen I used a class as the token such as logService, rootLogService for register, acttualy, there's another way for you to get the same result.

+

The way I'm mentioning is using OpaqueToken & ngCore.Inject

+
+ + {{valueProvider.sourceCode.name}} + full code + + +
+
+

OpaqueToken is a good solution for us to inject global variables such as window, localstorage into our component

+
+

Factory provider

+

Sometimes we need to create the dependent value dynamically, based on information we won't have until the last possible moment. This situation calls for a factory provider.

+
+

Let's illustrate, we want to implement a logic like that if user is authenticated, superLogService should be injected into our components, otherwise, logSerivce should be used.

+

Assume that we have userService which provide information about authentication. We re-write declaration for providers as below

+
+ + {{factoryProvider.sourceCode.name}} + full code + + +
+
+

The deps property is an array of provider tokens which our factory requires for injection

+
+

Optional dependencies

+

As you know, if Angular can't resolve injection for component, it'll throw an exception.

+

In fact, there're situations, we allow the constructor's arguments to be null. We can tell Angular that the dependency is optional by annotating the constructor argument with Optional

+

Of course, your code must be prepared to handle a null value.

+
+ + {{optionalDependency.sourceCode.name}} + full code + + +
+
+

Dependency visibility

+

Well, as we learned, we can use the providers property to define providers for its injector.

+

However, it turns out that there’s another property viewProviders that basically allows us to do the same thing. What’s the difference between those two them ?

+
+

viewProviders allows us to define injector providers that are only available for a component’s view.

+

Let’s take a closer look at what that means by using our TodosComponent example.

+
+ + {{dependencyVisibility.sourceCode.name}} + full code + + +
+
+

As you can see, todoTitleComponent is contentChild of TodoListComponent, todoItemComponent is viewChild of TodoListComponent

+

Both todoTitleComponent & todoItemComponent require an instance of the class which is provided via logSerivce token

+

How should we do if we expect that todoTitleComponent require logSerivce's instance, todoItemComponent require superLogService's instance ?

+
+

With viewProviders we can tell the DI system very specifically, which providers are available to which child injectors.

+

To make our code work as expected, all we have to do is to make the supperLogService provider of todoListComponent explicitly available only for its viewChild by using viewProviders instead of providers

+
+
+
+

Now, whenever a component of todoListComponent’s view asks for something of type logSerivce, it’ll get an instance of superLogService as expected.

+

Other child components from the outside world(contentChild) that ask for the same type, however, they won’t see this provider and will continue with the lookup in the injector tree.

+

Which means todoTitleComponent now gets an expected instance from another parent injector without even knowing that todoListComponent actually introduces its own provider.

+
+

Note that, viewProviders are also only available in components, not in directives. That’s simply because a directive doesn’t have its own view.

+
+

Restricting dependency lookup

+

We'll go on with the example in Dependency visibility subject.

+

Now, look back again, in the example, todoItemComponent requires logSerivce, follow DI rules, it will receice superLogService which is provided by todoListComponent.

+

This's so cool, however this can be problematic. Just imagine someone uses our todoItemComponent with their customTodoListComponent which doesn't provide superLogService.

+

What will happen ? our todoItemComponent will receice logSerivce's instance from another parent injector instead. It's unexpected.

+
+

If we need to ensure that superLogService instance is always instatiated by our component’s host or an exception should be thrown. Host dependency is a solution for us.

+
+ + {{hostDependency.sourceCode.name}} + full code + + \ No newline at end of file diff --git a/cms/articles/index.js b/cms/articles/index.js index ce4eebe..37f22a0 100644 --- a/cms/articles/index.js +++ b/cms/articles/index.js @@ -1,4 +1,8 @@ -let _ARTICLES = []; +import { article1474380939 } from './1474380939'; + +let _ARTICLES = [ + article1474380939 +]; export var ARTICLE_STORE = _init(); From f4ed4539ef6d88e95f391cfec621e2d18e31a806 Mon Sep 17 00:00:00 2001 From: Minh Van Date: Sat, 8 Oct 2016 00:16:00 +0700 Subject: [PATCH 2/6] Changed to use syntax ngCore.Component().Class() --- .../_article-1474380939.component.js | 130 ++++++++++++++++- .../article-1474380939.component.js | 132 +++++++++++++++++- .../templates/article-1474380939.html | 40 +++--- 3 files changed, 278 insertions(+), 24 deletions(-) diff --git a/cms/articles/1474380939/_article-1474380939.component.js b/cms/articles/1474380939/_article-1474380939.component.js index f5b4f6c..3d2ae6c 100644 --- a/cms/articles/1474380939/_article-1474380939.component.js +++ b/cms/articles/1474380939/_article-1474380939.component.js @@ -4,7 +4,10 @@ import highlight from 'highlight.js'; import { CODE_PANEL_DIRECTIVES, - HIGHLIGHT_DIRECTIVES + HIGHLIGHT_DIRECTIVES, + TABLE_CONTENT_DIRECTIVES, + TABLE_CONTENT_PROVIDERS, + tableContentService, } from 'xblog-cores/components'; import { resourceUtils } from 'xblog-cores/utils'; import { cmsArticleService } from '../../cores/services'; @@ -117,10 +120,131 @@ export var article1474380939Component = ngCore.Component({ templateUrl: './templates/article-1474380939.html', directives: [ CODE_PANEL_DIRECTIVES, - HIGHLIGHT_DIRECTIVES + HIGHLIGHT_DIRECTIVES, + TABLE_CONTENT_DIRECTIVES ], + providers: [ TABLE_CONTENT_PROVIDERS ], host: { '[class.xblog-article-1474380939]': 'true' } }) -.Class(new _article1474380939Component()); +.Class({ + constructor: [ + DomSanitizationService, + cmsArticleService, + tableContentService, + + function (sanitizer, articleService, tableContentService){ + this.id = 1474380939; + this.sanitizer = sanitizer; + this.articleService = articleService; + this.tableContentService = tableContentService; + } + ], + + ngOnInit: function() { + this.tableContents = this.tableContentService + .getBuilder() + .addHeadings([ + { id: 'injector-providers', name: 'Injector providers' }, + { id: 'class-provider', name: 'Class provider' }, + { id: 'value-provider', name: 'Value provider' }, + { id: 'factory-provider', name: 'Factory provider' }, + { id: 'optional-dependencies', name: 'Optional dependencies' }, + { id: 'dependency-visibility', name: 'Dependency visibility' }, + { id: 'restricting-dependency-lookup', name: 'Restricting dependency lookup' }, + ]) + .build(); + + this.simpleDI = { + sourceCode: { + name: 'simple-di', + link: resourceUtils.getGithubArticleFileLink(this.id, 'simple-di') + }, + codeBlocks: { + 1: this.getCodeBlock('simple-di.html') + }, + screenCaptures: { + 1: resourceUtils.getImg('simpleDI-example-1474380939.png') + } + }; + + this.classProvider = { + sourceCode: { + name: 'class-provider', + link: resourceUtils.getGithubArticleFileLink(this.id, 'class-provider') + }, + codeBlocks: { + 1: this.getCodeBlock('class-provider-1.html'), + 2: this.getCodeBlock('class-provider-2.html'), + 3: this.getCodeBlock('class-provider-3.html') + }, + screenCaptures: { + 1: resourceUtils.getImg('classProvider-example-1474380939.png') + } + }; + + this.valueProvider = { + sourceCode: { + name: 'value-provider', + link: resourceUtils.getGithubArticleFileLink(this.id, 'value-provider') + }, + codeBlocks: { + 1: this.getCodeBlock('value-provider-1.html'), + 2: this.getCodeBlock('value-provider-2.html') + } + }; + + this.factoryProvider = { + sourceCode: { + name: 'factory-provider', + link: resourceUtils.getGithubArticleFileLink(this.id, 'factory-provider') + }, + codeBlocks: { + 1: this.getCodeBlock('factory-provider.html') + } + }; + + this.optionalDependency = { + sourceCode: { + name: 'optional-dependency', + link: resourceUtils.getGithubArticleFileLink(this.id, 'optional-dependency') + }, + codeBlocks: { + 1: this.getCodeBlock('optional-dependency.html') + } + }; + + this.hostDependency = { + sourceCode: { + name: 'host-dependency', + link: resourceUtils.getGithubArticleFileLink(this.id, 'host-dependency') + }, + codeBlocks: { + 1: this.getCodeBlock('host-dependency.html') + } + }; + + this.dependencyVisibility = { + sourceCode: { + name: 'dependency-visibility', + link: resourceUtils.getGithubArticleFileLink(this.id, 'dependency-visibility') + }, + codeBlocks: { + 1: this.getCodeBlock('dependency-visibility.html') + }, + screenCaptures: { + 1: resourceUtils.getImg('dependencyVisibility-example-1474380939.png') + } + }; + }, + + getCodeBlock: function(fileName, lang) { + var _langs = lang ? [ lang ] : ['javascript', 'html', 'css']; + + var _codeBlock = this.articleService.getCodeBlock(this.id, fileName); + _codeBlock = highlight.highlightAuto(_codeBlock, _langs).value; + + return this.sanitizer.bypassSecurityTrustHtml(_codeBlock); + } +}); diff --git a/cms/articles/1474380939/article-1474380939.component.js b/cms/articles/1474380939/article-1474380939.component.js index 474c2a3..30d2508 100644 --- a/cms/articles/1474380939/article-1474380939.component.js +++ b/cms/articles/1474380939/article-1474380939.component.js @@ -4,7 +4,10 @@ import highlight from 'highlight.js'; import { CODE_PANEL_DIRECTIVES, - HIGHLIGHT_DIRECTIVES + HIGHLIGHT_DIRECTIVES, + TABLE_CONTENT_DIRECTIVES, + TABLE_CONTENT_PROVIDERS, + tableContentService, } from 'xblog-cores/components'; import { resourceUtils } from 'xblog-cores/utils'; import { cmsArticleService } from '../../cores/services'; @@ -114,13 +117,134 @@ function _article1474380939Component(){ export var article1474380939Component = ngCore.Component({ selector: 'article', - template: "

Angular ships with its own dependency injection framework and we really can't build an Angular application without it

An Angular application is a tree of components. Each component instance has its own injector. The tree of components parallels the tree of injectors.

We can re-configure the injectors at any level of that component tree with interesting and useful results.


Consider a simple example about TodosComponent


{{simpleDI.sourceCode.name}}full code

Each component instance gets its own injector and an injector at one level is a child injector of the injector above it in the tree.


When a component at the bottom requests a dependency, Angular tries to satisfy that dependency with a provider registered in that component's own injector.

If the component's injector lacks the provider, it passes the request up to its parent component's injector. If that injector can't satisfy the request, it passes it along to its parent component's injector.

The requests keep bubbling up until we find an injector that can handle the request or run out of component ancestors. If we run out of ancestors, Angular throws an error.


Dependencies are singletons within the scope of an injector.


In our example, logSerivce are shared among todosComponent, todoListComponent, todoItemComponent. Because it is hosted by todosComponent which is parents of todoListComponent & todoItemComponent

todoListComponent can inject logSerivce from todosComponent via its constructor. However, nested injectors at todoItemComponent create their own service instances by using providers to host logService itself



Injector providers

A provider provides the concrete of a dependency value.

The injector relies on providers to create instances of the services that the injector injects into components and other services.


As you know, we can register service provider or directive provider by using providers & directives in component's declaration

Look back our example, you can see the way we registered logSerivce in TodosComponent


But there are many ways that we can configure the injector with alternative providers that can deliver an object that behaves like logSerivce. We'll expore them now.


Class Provider

We wrote the providers array like this: providers: [ logSerivce ]

This is actually a short-hand expression for a provider registration




The first is the token that serves as the key for both locating a dependency value and registering the provider.

The second is a provider definition object, which we can think of as a recipe for creating the dependency value


With this expression, it's easy for us specify another class to provide the service

For example we have another service is superLogService, We can register it for todoListComponent with logSerivce token instead of logSerivce class




However, lets look back the example that you registered logService in todosComponent then you used useClass to register superLogService in todoListComponent

So how can todoItemComponent inject logService from todoComponent instead of superLogService from todoListComponent ?


The solution for this case is you should use useExisting with rootLogService token for register in todosComponent


{{classProvider.sourceCode.name}}full code


Value Provider

Sometimes it's easier to provide a object rather than ask the injector to create it from a class.

We can re-write superLogService as an object then registering it by using useValue like this




Now, you have seen I used a class as the token such as logService, rootLogService for register, acttualy, there's another way for you to get the same result.

The way I'm mentioning is using OpaqueToken & ngCore.Inject


{{valueProvider.sourceCode.name}}full code

OpaqueToken is a good solution for us to inject global variables such as window, localstorage into our component


Factory provider

Sometimes we need to create the dependent value dynamically, based on information we won't have until the last possible moment. This situation calls for a factory provider.


Let's illustrate, we want to implement a logic like that if user is authenticated, superLogService should be injected into our components, otherwise, logSerivce should be used.

Assume that we have userService which provide information about authentication. We re-write declaration for providers as below


{{factoryProvider.sourceCode.name}}full code

The deps property is an array of provider tokens which our factory requires for injection


Optional dependencies

As you know, if Angular can't resolve injection for component, it'll throw an exception.

In fact, there're situations, we allow the constructor's arguments to be null. We can tell Angular that the dependency is optional by annotating the constructor argument with Optional

Of course, your code must be prepared to handle a null value.


{{optionalDependency.sourceCode.name}}full code

Dependency visibility

Well, as we learned, we can use the providers property to define providers for its injector.

However, it turns out that there’s another property viewProviders that basically allows us to do the same thing. What’s the difference between those two them ?


viewProviders allows us to define injector providers that are only available for a component’s view.

Let’s take a closer look at what that means by using our TodosComponent example.


{{dependencyVisibility.sourceCode.name}}full code

As you can see, todoTitleComponent is contentChild of TodoListComponent, todoItemComponent is viewChild of TodoListComponent

Both todoTitleComponent & todoItemComponent require an instance of the class which is provided via logSerivce token

How should we do if we expect that todoTitleComponent require logSerivce's instance, todoItemComponent require superLogService's instance ?


With viewProviders we can tell the DI system very specifically, which providers are available to which child injectors.

To make our code work as expected, all we have to do is to make the supperLogService provider of todoListComponent explicitly available only for its viewChild by using viewProviders instead of providers



Now, whenever a component of todoListComponent’s view asks for something of type logSerivce, it’ll get an instance of superLogService as expected.

Other child components from the outside world(contentChild) that ask for the same type, however, they won’t see this provider and will continue with the lookup in the injector tree.

Which means todoTitleComponent now gets an expected instance from another parent injector without even knowing that todoListComponent actually introduces its own provider.


Note that, viewProviders are also only available in components, not in directives. That’s simply because a directive doesn’t have its own view.


Restricting dependency lookup

We'll go on with the example in Dependency visibility subject.

Now, look back again, in the example, todoItemComponent requires logSerivce, follow DI rules, it will receice superLogService which is provided by todoListComponent.

This's so cool, however this can be problematic. Just imagine someone uses our todoItemComponent with their customTodoListComponent which doesn't provide superLogService.

What will happen ? our todoItemComponent will receice logSerivce's instance from another parent injector instead. It's unexpected.


If we need to ensure that superLogService instance is always instatiated by our component’s host or an exception should be thrown. Host dependency is a solution for us.


{{hostDependency.sourceCode.name}}full code", + template: "
Table of Contents

Angular ships with its own dependency injection framework and we really can't build an Angular application without it

An Angular application is a tree of components. Each component instance has its own injector. The tree of components parallels the tree of injectors.

We can re-configure the injectors at any level of that component tree with interesting and useful results.


Consider a simple example about TodosComponent


{{simpleDI.sourceCode.name}}full code

Each component instance gets its own injector and an injector at one level is a child injector of the injector above it in the tree.


When a component at the bottom requests a dependency, Angular tries to satisfy that dependency with a provider registered in that component's own injector.

If the component's injector lacks the provider, it passes the request up to its parent component's injector. If that injector can't satisfy the request, it passes it along to its parent component's injector.

The requests keep bubbling up until we find an injector that can handle the request or run out of component ancestors. If we run out of ancestors, Angular throws an error.


Dependencies are singletons within the scope of an injector.


In our example, logSerivce are shared among todosComponent, todoListComponent, todoItemComponent. Because it is hosted by todosComponent which is parents of todoListComponent & todoItemComponent

todoListComponent can inject logSerivce from todosComponent via its constructor. However, nested injectors at todoItemComponent create their own service instances by using providers to host logService itself



Injector providers

A provider provides the concrete of a dependency value.

The injector relies on providers to create instances of the services that the injector injects into components and other services.


As you know, we can register service provider or directive provider by using providers & directives in component's declaration

Look back our example, you can see the way we registered logSerivce in TodosComponent


But there are many ways that we can configure the injector with alternative providers that can deliver an object that behaves like logSerivce. We'll expore them now.


Class Provider

We wrote the providers array like this: providers: [ logSerivce ]

This is actually a short-hand expression for a provider registration




The first is the token that serves as the key for both locating a dependency value and registering the provider.

The second is a provider definition object, which we can think of as a recipe for creating the dependency value


With this expression, it's easy for us specify another class to provide the service

For example we have another service is superLogService, We can register it for todoListComponent with logSerivce token instead of logSerivce class




However, lets look back the example that you registered logService in todosComponent then you used useClass to register superLogService in todoListComponent

So how can todoItemComponent inject logService from todoComponent instead of superLogService from todoListComponent ?


The solution for this case is you should use useExisting with rootLogService token for register in todosComponent


{{classProvider.sourceCode.name}}full code


Value Provider

Sometimes it's easier to provide a object rather than ask the injector to create it from a class.

We can re-write superLogService as an object then registering it by using useValue like this




Now, you have seen I used a class as the token such as logService, rootLogService for register, acttualy, there's another way for you to get the same result.

The way I'm mentioning is using OpaqueToken & ngCore.Inject


{{valueProvider.sourceCode.name}}full code

OpaqueToken is a good solution for us to inject global variables such as window, localstorage into our component


Factory provider

Sometimes we need to create the dependent value dynamically, based on information we won't have until the last possible moment. This situation calls for a factory provider.


Let's illustrate, we want to implement a logic like that if user is authenticated, superLogService should be injected into our components, otherwise, logSerivce should be used.

Assume that we have userService which provide information about authentication. We re-write declaration for providers as below


{{factoryProvider.sourceCode.name}}full code

The deps property is an array of provider tokens which our factory requires for injection


Optional dependencies

As you know, if Angular can't resolve injection for component, it'll throw an exception.

In fact, there're situations, we allow the constructor's arguments to be null. We can tell Angular that the dependency is optional by annotating the constructor argument with Optional

Of course, your code must be prepared to handle a null value.


{{optionalDependency.sourceCode.name}}full code

Dependency visibility

Well, as we learned, we can use the providers property to define providers for its injector.

However, it turns out that there’s another property viewProviders that basically allows us to do the same thing. What’s the difference between those two them ?


viewProviders allows us to define injector providers that are only available for a component’s view.

Let’s take a closer look at what that means by using our TodosComponent example.


{{dependencyVisibility.sourceCode.name}}full code

As you can see, todoTitleComponent is contentChild of TodoListComponent, todoItemComponent is viewChild of TodoListComponent

Both todoTitleComponent & todoItemComponent require an instance of the class which is provided via logSerivce token

How should we do if we expect that todoTitleComponent require logSerivce's instance, todoItemComponent require superLogService's instance ?


With viewProviders we can tell the DI system very specifically, which providers are available to which child injectors.

To make our code work as expected, all we have to do is to make the supperLogService provider of todoListComponent explicitly available only for its viewChild by using viewProviders instead of providers



Now, whenever a component of todoListComponent’s view asks for something of type logSerivce, it’ll get an instance of superLogService as expected.

Other child components from the outside world(contentChild) that ask for the same type, however, they won’t see this provider and will continue with the lookup in the injector tree.

Which means todoTitleComponent now gets an expected instance from another parent injector without even knowing that todoListComponent actually introduces its own provider.


Note that, viewProviders are also only available in components, not in directives. That’s simply because a directive doesn’t have its own view.


Restricting dependency lookup

We'll go on with the example in Dependency visibility subject.

Now, look back again, in the example, todoItemComponent requires logSerivce, follow DI rules, it will receice superLogService which is provided by todoListComponent.

This's so cool, however this can be problematic. Just imagine someone uses our todoItemComponent with their customTodoListComponent which doesn't provide superLogService.

What will happen ? our todoItemComponent will receice logSerivce's instance from another parent injector instead. It's unexpected.


If we need to ensure that superLogService instance is always instatiated by our component’s host or an exception should be thrown. Host dependency is a solution for us.


{{hostDependency.sourceCode.name}}full code", directives: [ CODE_PANEL_DIRECTIVES, - HIGHLIGHT_DIRECTIVES + HIGHLIGHT_DIRECTIVES, + TABLE_CONTENT_DIRECTIVES ], + providers: [ TABLE_CONTENT_PROVIDERS ], host: { '[class.xblog-article-1474380939]': 'true' } }) -.Class(new _article1474380939Component()); +.Class({ + constructor: [ + DomSanitizationService, + cmsArticleService, + tableContentService, + + function (sanitizer, articleService, tableContentService){ + this.id = 1474380939; + this.sanitizer = sanitizer; + this.articleService = articleService; + this.tableContentService = tableContentService; + } + ], + + ngOnInit: function() { + this.tableContents = this.tableContentService + .getBuilder() + .addHeadings([ + { id: 'injector-providers', name: 'Injector providers' }, + { id: 'class-provider', name: 'Class provider' }, + { id: 'value-provider', name: 'Value provider' }, + { id: 'factory-provider', name: 'Factory provider' }, + { id: 'optional-dependencies', name: 'Optional dependencies' }, + { id: 'dependency-visibility', name: 'Dependency visibility' }, + { id: 'restricting-dependency-lookup', name: 'Restricting dependency lookup' }, + ]) + .build(); + + this.simpleDI = { + sourceCode: { + name: 'simple-di', + link: resourceUtils.getGithubArticleFileLink(this.id, 'simple-di') + }, + codeBlocks: { + 1: this.getCodeBlock('simple-di.html') + }, + screenCaptures: { + 1: resourceUtils.getImg('simpleDI-example-1474380939.png') + } + }; + + this.classProvider = { + sourceCode: { + name: 'class-provider', + link: resourceUtils.getGithubArticleFileLink(this.id, 'class-provider') + }, + codeBlocks: { + 1: this.getCodeBlock('class-provider-1.html'), + 2: this.getCodeBlock('class-provider-2.html'), + 3: this.getCodeBlock('class-provider-3.html') + }, + screenCaptures: { + 1: resourceUtils.getImg('classProvider-example-1474380939.png') + } + }; + + this.valueProvider = { + sourceCode: { + name: 'value-provider', + link: resourceUtils.getGithubArticleFileLink(this.id, 'value-provider') + }, + codeBlocks: { + 1: this.getCodeBlock('value-provider-1.html'), + 2: this.getCodeBlock('value-provider-2.html') + } + }; + + this.factoryProvider = { + sourceCode: { + name: 'factory-provider', + link: resourceUtils.getGithubArticleFileLink(this.id, 'factory-provider') + }, + codeBlocks: { + 1: this.getCodeBlock('factory-provider.html') + } + }; + + this.optionalDependency = { + sourceCode: { + name: 'optional-dependency', + link: resourceUtils.getGithubArticleFileLink(this.id, 'optional-dependency') + }, + codeBlocks: { + 1: this.getCodeBlock('optional-dependency.html') + } + }; + + this.hostDependency = { + sourceCode: { + name: 'host-dependency', + link: resourceUtils.getGithubArticleFileLink(this.id, 'host-dependency') + }, + codeBlocks: { + 1: this.getCodeBlock('host-dependency.html') + } + }; + + this.dependencyVisibility = { + sourceCode: { + name: 'dependency-visibility', + link: resourceUtils.getGithubArticleFileLink(this.id, 'dependency-visibility') + }, + codeBlocks: { + 1: this.getCodeBlock('dependency-visibility.html') + }, + screenCaptures: { + 1: resourceUtils.getImg('dependencyVisibility-example-1474380939.png') + } + }; + }, + + getCodeBlock: function(fileName, lang) { + var _langs = lang ? [ lang ] : ['javascript', 'html', 'css']; + + var _codeBlock = this.articleService.getCodeBlock(this.id, fileName); + _codeBlock = highlight.highlightAuto(_codeBlock, _langs).value; + + return this.sanitizer.bypassSecurityTrustHtml(_codeBlock); + } +}); diff --git a/cms/articles/1474380939/templates/article-1474380939.html b/cms/articles/1474380939/templates/article-1474380939.html index 3310013..1b4677f 100644 --- a/cms/articles/1474380939/templates/article-1474380939.html +++ b/cms/articles/1474380939/templates/article-1474380939.html @@ -1,10 +1,16 @@ + + +
Table of Contents
+
+
+

Angular ships with its own dependency injection framework and we really can't build an Angular application without it

An Angular application is a tree of components. Each component instance has its own injector. The tree of components parallels the tree of injectors.

We can re-configure the injectors at any level of that component tree with interesting and useful results.


Consider a simple example about TodosComponent


- + {{simpleDI.sourceCode.name}} full code @@ -24,7 +30,7 @@

-

Injector providers

+

Injector providers

A provider provides the concrete of a dependency value.

The injector relies on providers to create instances of the services that the injector injects into components and other services.


@@ -33,11 +39,11 @@

Injector providers


But there are many ways that we can configure the injector with alternative providers that can deliver an object that behaves like logSerivce. We'll expore them now.


-

Class Provider

+

Class Provider

We wrote the providers array like this: providers: [ logSerivce ]

This is actually a short-hand expression for a provider registration


- +
@@ -48,7 +54,7 @@

Class Provider

With this expression, it's easy for us specify another class to provide the service

For example we have another service is superLogService, We can register it for todoListComponent with logSerivce token instead of logSerivce class


- +
@@ -58,7 +64,7 @@

Class Provider


The solution for this case is you should use useExisting with rootLogService token for register in todosComponent


- + {{classProvider.sourceCode.name}} full code @@ -67,11 +73,11 @@

Class Provider



-

Value Provider

+

Value Provider

Sometimes it's easier to provide a object rather than ask the injector to create it from a class.

We can re-write superLogService as an object then registering it by using useValue like this


- +
@@ -79,7 +85,7 @@

Value Provider

Now, you have seen I used a class as the token such as logService, rootLogService for register, acttualy, there's another way for you to get the same result.

The way I'm mentioning is using OpaqueToken & ngCore.Inject


- + {{valueProvider.sourceCode.name}} full code @@ -88,13 +94,13 @@

Value Provider


OpaqueToken is a good solution for us to inject global variables such as window, localstorage into our component


-

Factory provider

+

Factory provider

Sometimes we need to create the dependent value dynamically, based on information we won't have until the last possible moment. This situation calls for a factory provider.


Let's illustrate, we want to implement a logic like that if user is authenticated, superLogService should be injected into our components, otherwise, logSerivce should be used.

Assume that we have userService which provide information about authentication. We re-write declaration for providers as below


- + {{factoryProvider.sourceCode.name}} full code @@ -103,26 +109,26 @@

Factory provider


The deps property is an array of provider tokens which our factory requires for injection


-

Optional dependencies

+

Optional dependencies

As you know, if Angular can't resolve injection for component, it'll throw an exception.

In fact, there're situations, we allow the constructor's arguments to be null. We can tell Angular that the dependency is optional by annotating the constructor argument with Optional

Of course, your code must be prepared to handle a null value.


- + {{optionalDependency.sourceCode.name}} full code

-

Dependency visibility

+

Dependency visibility

Well, as we learned, we can use the providers property to define providers for its injector.

However, it turns out that there’s another property viewProviders that basically allows us to do the same thing. What’s the difference between those two them ?


viewProviders allows us to define injector providers that are only available for a component’s view.

Let’s take a closer look at what that means by using our TodosComponent example.


- + {{dependencyVisibility.sourceCode.name}} full code @@ -144,7 +150,7 @@

Dependency visibility


Note that, viewProviders are also only available in components, not in directives. That’s simply because a directive doesn’t have its own view.


-

Restricting dependency lookup

+

Restricting dependency lookup

We'll go on with the example in Dependency visibility subject.

Now, look back again, in the example, todoItemComponent requires logSerivce, follow DI rules, it will receice superLogService which is provided by todoListComponent.

This's so cool, however this can be problematic. Just imagine someone uses our todoItemComponent with their customTodoListComponent which doesn't provide superLogService.

@@ -152,7 +158,7 @@

Restricting dependency lookup


If we need to ensure that superLogService instance is always instatiated by our component’s host or an exception should be thrown. Host dependency is a solution for us.


- + {{hostDependency.sourceCode.name}} full code From 5aacc9a8fe05ac87ea0db8d6fe417d67c97aa3a1 Mon Sep 17 00:00:00 2001 From: Minh Van Date: Sat, 8 Oct 2016 01:20:18 +0700 Subject: [PATCH 3/6] Changed code blocks to syntax ngCore.Component().Class() --- .../code-blocks/class-provider-2.html | 2 +- .../code-blocks/class-provider-3.html | 49 +++++++++---------- .../code-blocks/dependency-visibility.html | 37 ++++++-------- .../code-blocks/factory-provider.html | 34 ++++++------- .../code-blocks/host-dependency.html | 11 ++--- .../code-blocks/optional-dependency.html | 11 ++--- .../1474380939/code-blocks/simple-di.html | 46 ++++++++--------- .../code-blocks/value-provider-1.html | 2 +- .../code-blocks/value-provider-2.html | 22 ++++----- 9 files changed, 96 insertions(+), 118 deletions(-) diff --git a/cms/articles/1474380939/code-blocks/class-provider-2.html b/cms/articles/1474380939/code-blocks/class-provider-2.html index e48610b..880663b 100644 --- a/cms/articles/1474380939/code-blocks/class-provider-2.html +++ b/cms/articles/1474380939/code-blocks/class-provider-2.html @@ -4,4 +4,4 @@ { provide: logService, useClass: supperLogService } ] }) -.Class(new _todoListComponent()); \ No newline at end of file +.Class(.....); \ No newline at end of file diff --git a/cms/articles/1474380939/code-blocks/class-provider-3.html b/cms/articles/1474380939/code-blocks/class-provider-3.html index e886661..de5fdf3 100644 --- a/cms/articles/1474380939/code-blocks/class-provider-3.html +++ b/cms/articles/1474380939/code-blocks/class-provider-3.html @@ -1,38 +1,30 @@ import * as ngCore from '@angular/core'; -function _rootLogService(){ - this.constructor = function(){}; -} -export var rootLogService = ngCore.Class(new _rootLogService()); +export var rootLogService = ngCore.Class({ + constructor: function(){} +}); /*---------------------------------------------------------*/ -function _supperLogService(){ - this.constructor = function(){ +export var supperLogService = ngCore.Class({ + constructor: function(){ this.name = 'supperLogService'; - }; -} -export var supperLogService = ngCore.Class(new _supperLogService()); + } +}); /*---------------------------------------------------------*/ -function _todoItemComponent(){ - this.constructor = [rootLogService, function(logService){ - console.log('todoItemComponent', logService.name); - }]; -}; export var todoItemComponent = ngCore.Component({ ..... }) -.Class(new _todoItemComponent()); +.Class({ + constructor: [rootLogService, function(logService){ + console.log('todoItemComponent', logService.name); + }] +}); /*---------------------------------------------------------*/ -function _todoListComponent(){ - this.constructor = [logService, function(logService){ - console.log('todoListComponent', logService.name + ' is hosted by todoListComponent'); - }]; -}; export var todoListComponent = ngCore.Component({ ..... directives: [ todoItemComponent ], @@ -40,15 +32,14 @@ { provide: logService, useClass: supperLogService } ] }) -.Class(new _todoListComponent()); +.Class({ + constructor: [logService, function(logService){ + console.log('todoListComponent', logService.name + ' is hosted by todoListComponent'); + }] +}); /*---------------------------------------------------------*/ -function _todosComponent(){ - this.constructor = [logService, function(logService){ - logService.setName('logService is hosted by todosComponent'); - }]; -}; export var todosComponent = ngCore.Component({ ..... directives: [ todoListComponent, todoItemComponent ], @@ -57,4 +48,8 @@ { provide: rootLogService, useExisting: logService } ] }) -.Class(new _todosComponent()); +.Class({ + constructor: [logService, function(logService){ + logService.setName('logService is hosted by todosComponent'); + }] +}); diff --git a/cms/articles/1474380939/code-blocks/dependency-visibility.html b/cms/articles/1474380939/code-blocks/dependency-visibility.html index 309e0f3..dde2aa8 100644 --- a/cms/articles/1474380939/code-blocks/dependency-visibility.html +++ b/cms/articles/1474380939/code-blocks/dependency-visibility.html @@ -1,27 +1,21 @@ -function _todoTitleComponent(){ - this.constructor = [logService, function(logService){ - console.log('todoTitleComponent', logService.name); - }]; -} export var todoTitleComponent = ngCore.Component({.....}) -.Class(new _todoTitleComponent()); +.Class({ + constructor: [logService, function(logService){ + console.log('todoTitleComponent', logService.name); + }] +}); /*---------------------------------------------------------*/ -function _todoItemComponent(){ - this.constructor = [logService, function(logService){ - console.log('todoItemComponent', logService.name); - }]; -} export var todoItemComponent = ngCore.Component({.....}) -.Class(new _todoItemComponent()); +.Class({ + constructor: [logService, function(logService){ + console.log('todoItemComponent', logService.name); + }] +}); /*---------------------------------------------------------*/ -function _todoListComponent(){ - this.constructor = [logService, function(logService){}]; -} - export var todoListComponent = ngCore.Component({ ..... template: [ @@ -32,13 +26,12 @@ { provide: logService, useClass: supperLogService } ] }) -.Class(new _todoListComponent()); +.Class({ + constructor: [logService, function(logService){}] +}); /*---------------------------------------------------------*/ -function _todosComponent(){ - this.constructor = [logService, function(logService){}]; -} export var todosComponent = ngCore.Component({ ..... template: [ @@ -48,4 +41,6 @@ ].join(''), providers: [ logService ] }) -.Class(new _todosComponent()); \ No newline at end of file +.Class({ + constructor: [logService, function(logService){}] +}); \ No newline at end of file diff --git a/cms/articles/1474380939/code-blocks/factory-provider.html b/cms/articles/1474380939/code-blocks/factory-provider.html index df51139..9246a5b 100644 --- a/cms/articles/1474380939/code-blocks/factory-provider.html +++ b/cms/articles/1474380939/code-blocks/factory-provider.html @@ -1,19 +1,12 @@ -function _userService(){ - this.constructor = function(){}; - - this.setAuth = function(isAuth){ +export var userService = ngCore.Class({ + ..... + setAuth: function(isAuth){ this.isAuth = isAuth; - }; -} -export var userService = ngCore.Class(new _userService()); + } +}); /*---------------------------------------------------------*/ -function _todoListComponent(){ - this.constructor = [logService, function(logService){ - console.log('todoListComponent', logService.name); - }]; -} export var todoListComponent = ngCore.Component({ ..... providers: [ @@ -26,17 +19,20 @@ } ] }) -.Class(new _todoListComponent()); +.Class({ + constructor: [logService, function(logService){ + console.log('todoListComponent', logService.name); + }] +}); /*---------------------------------------------------------*/ -function _todosComponent(){ - this.constructor = [userService, function(userService){ - this.userService.setAuth(true); - }]; -} export var todosComponent = ngCore.Component({ ..... providers: [ userService ] }) -.Class(new _todosComponent()); \ No newline at end of file +.Class({ + constructor: [userService, function(userService){ + this.userService.setAuth(true); + }] +}); \ No newline at end of file diff --git a/cms/articles/1474380939/code-blocks/host-dependency.html b/cms/articles/1474380939/code-blocks/host-dependency.html index 2c3315b..b07941a 100644 --- a/cms/articles/1474380939/code-blocks/host-dependency.html +++ b/cms/articles/1474380939/code-blocks/host-dependency.html @@ -1,11 +1,10 @@ -function _todoItemComponent(){ - this.constructor = [ +export var todoItemComponent = ngCore.Component({.....}) +.Class({ + constructor: [ [ new ngCore.Host(), ngCore.Inject(logService) ], function(logService){ console.log('todoItemComponent', logService.name); } - ]; -} -export var todoItemComponent = ngCore.Component({.....}) -.Class(new _todoItemComponent()); \ No newline at end of file + ] +}); \ No newline at end of file diff --git a/cms/articles/1474380939/code-blocks/optional-dependency.html b/cms/articles/1474380939/code-blocks/optional-dependency.html index 853e51a..5f13223 100644 --- a/cms/articles/1474380939/code-blocks/optional-dependency.html +++ b/cms/articles/1474380939/code-blocks/optional-dependency.html @@ -1,5 +1,6 @@ -function _todoListComponent(){ - this.constructor = [ +export var todoListComponent = ngCore.Component({.....}) +.Class({ + constructor: [ [ new ngCore.Optional(), ngCore.Inject(logService) ], function(logService){ @@ -7,7 +8,5 @@ console.log('todoListComponent', 'logService is null'); } } - ]; -} -export var todoListComponent = ngCore.Component({.....}) -.Class(new _todoListComponent()); \ No newline at end of file + ] +}); \ No newline at end of file diff --git a/cms/articles/1474380939/code-blocks/simple-di.html b/cms/articles/1474380939/code-blocks/simple-di.html index 1ea1e96..d1e1dc8 100644 --- a/cms/articles/1474380939/code-blocks/simple-di.html +++ b/cms/articles/1474380939/code-blocks/simple-di.html @@ -1,52 +1,48 @@ import * as ngCore from '@angular/core'; -function _logService(){ - this.constructor = function(){ +export var logService = ngCore.Class({ + constructor: function(){ this.name = 'logService'; - }; + }, - this.setName = function(name){ + setName: function(name){ this.name = name; - }; -}; -export var logService = ngCore.Class(new _logService()); + } +}); /*---------------------------------------------------------*/ -function _todoItemComponent(){ - this.constructor = [logService, function(logService){ - console.log('todoItemComponent', logService.name); - }]; -}; export var todoItemComponent = ngCore.Component({ ..... providers: [ logService ] }) -.Class(new _todoItemComponent()); +.Class({ + constructor: [logService, function(logService){ + console.log('todoItemComponent', logService.name); + }] +}); /*---------------------------------------------------------*/ -function _todoListComponent(){ - this.constructor = [logService, function(logService){ - console.log('todoListComponent', logService.name); - }]; -}; export var todoListComponent = ngCore.Component({ ..... directives: [ todoItemComponent ] }) -.Class(new _todoListComponent()); +.Class({ + constructor: [logService, function(logService){ + console.log('todoListComponent', logService.name); + }] +}); /*---------------------------------------------------------*/ -function _todosComponent(){ - this.constructor = [logService, function(logService){ - logService.setName('logService is hosted by todosComponent'); - }]; -}; export var todosComponent = ngCore.Component({ ..... providers: [ logService ], directives: [ todoListComponent, todoItemComponent ] }) -.Class(new _todosComponent()); +.Class({ + constructor: [logService, function(logService){ + logService.setName('logService is hosted by todosComponent'); + }] +}); diff --git a/cms/articles/1474380939/code-blocks/value-provider-1.html b/cms/articles/1474380939/code-blocks/value-provider-1.html index 29aeeab..a7403ce 100644 --- a/cms/articles/1474380939/code-blocks/value-provider-1.html +++ b/cms/articles/1474380939/code-blocks/value-provider-1.html @@ -10,4 +10,4 @@ { provide: logService, useValue: supperLogService } ] }) -.Class(new _todoListComponent()); \ No newline at end of file +.Class(.....); \ No newline at end of file diff --git a/cms/articles/1474380939/code-blocks/value-provider-2.html b/cms/articles/1474380939/code-blocks/value-provider-2.html index eb0b135..b28ff45 100644 --- a/cms/articles/1474380939/code-blocks/value-provider-2.html +++ b/cms/articles/1474380939/code-blocks/value-provider-2.html @@ -10,30 +10,24 @@ import { WINDOW } from './window.model'; -function _logService(){ - this.constructor = [ +export var logService = ngCore.Class({ + constructor: [ ngCore.Inject(WINDOW), function(window){ this.window = window; } - ]; + ], - this.log = function(text){ + log: function(text){ this.window.console.log(text); } -} -export var logService = ngCore.Class(new _logService()); +}); /*---------------------------------------------------------*/ import { WINDOW_PROVIDERS } from './window.model'; -function _todosComponent(){ - this.constructor = [logService, function(logService){ - logService.log('This message is logged by using window.console via DI'); - }]; -} export var todosComponent = ngCore.Component({ ..... providers: [ @@ -41,5 +35,9 @@ WINDOW_PROVIDERS ] }) -.Class(new _todosComponent()); +.Class({ + constructor: [logService, function(logService){ + logService.log('This message is logged by using window.console via DI'); + }] +}); From ab0832a82e5dbbe6a78c7e5308a769f5e2e9f199 Mon Sep 17 00:00:00 2001 From: Minh Van Date: Thu, 20 Oct 2016 23:14:30 +0700 Subject: [PATCH 4/6] Upgrade to @angular 2.0.2 --- .../_article-1474380939.component.js | 128 +----------------- .../article-1474380939.component.js | 128 +----------------- 2 files changed, 14 insertions(+), 242 deletions(-) diff --git a/cms/articles/1474380939/_article-1474380939.component.js b/cms/articles/1474380939/_article-1474380939.component.js index 3d2ae6c..41bd477 100644 --- a/cms/articles/1474380939/_article-1474380939.component.js +++ b/cms/articles/1474380939/_article-1474380939.component.js @@ -1,138 +1,24 @@ -import * as ngCore from '@angular/core'; -import { DomSanitizationService } from '@angular/platform-browser'; +import { Component } from '@angular/core'; +import { DomSanitizer } from '@angular/platform-browser'; import highlight from 'highlight.js'; -import { - CODE_PANEL_DIRECTIVES, - HIGHLIGHT_DIRECTIVES, - TABLE_CONTENT_DIRECTIVES, - TABLE_CONTENT_PROVIDERS, - tableContentService, -} from 'xblog-cores/components'; +import { xblogTableContentService } from 'xblog-cores/modules'; import { resourceUtils } from 'xblog-cores/utils'; -import { cmsArticleService } from '../../cores/services'; - -function _article1474380939Component(){ - this.constructor = [ - DomSanitizationService, - cmsArticleService, - - function article1474380939Component(sanitizer, articleService){ - this.id = 1474380939; - this.sanitizer = sanitizer; - this.articleService = articleService; - } - ]; - - this.ngOnInit = function() { - this.simpleDI = { - sourceCode: { - name: 'simple-di', - link: resourceUtils.getGithubArticleFileLink(this.id, 'simple-di') - }, - codeBlocks: { - 1: this.getCodeBlock('simple-di.html') - }, - screenCaptures: { - 1: resourceUtils.getImg('simpleDI-example-1474380939.png') - } - }; - - this.classProvider = { - sourceCode: { - name: 'class-provider', - link: resourceUtils.getGithubArticleFileLink(this.id, 'class-provider') - }, - codeBlocks: { - 1: this.getCodeBlock('class-provider-1.html'), - 2: this.getCodeBlock('class-provider-2.html'), - 3: this.getCodeBlock('class-provider-3.html') - }, - screenCaptures: { - 1: resourceUtils.getImg('classProvider-example-1474380939.png') - } - }; - - this.valueProvider = { - sourceCode: { - name: 'value-provider', - link: resourceUtils.getGithubArticleFileLink(this.id, 'value-provider') - }, - codeBlocks: { - 1: this.getCodeBlock('value-provider-1.html'), - 2: this.getCodeBlock('value-provider-2.html') - } - }; - this.factoryProvider = { - sourceCode: { - name: 'factory-provider', - link: resourceUtils.getGithubArticleFileLink(this.id, 'factory-provider') - }, - codeBlocks: { - 1: this.getCodeBlock('factory-provider.html') - } - }; - - this.optionalDependency = { - sourceCode: { - name: 'optional-dependency', - link: resourceUtils.getGithubArticleFileLink(this.id, 'optional-dependency') - }, - codeBlocks: { - 1: this.getCodeBlock('optional-dependency.html') - } - }; - - this.hostDependency = { - sourceCode: { - name: 'host-dependency', - link: resourceUtils.getGithubArticleFileLink(this.id, 'host-dependency') - }, - codeBlocks: { - 1: this.getCodeBlock('host-dependency.html') - } - }; - - this.dependencyVisibility = { - sourceCode: { - name: 'dependency-visibility', - link: resourceUtils.getGithubArticleFileLink(this.id, 'dependency-visibility') - }, - codeBlocks: { - 1: this.getCodeBlock('dependency-visibility.html') - }, - screenCaptures: { - 1: resourceUtils.getImg('dependencyVisibility-example-1474380939.png') - } - }; - }; - - this.getCodeBlock = function(fileName) { - var _codeBlock = this.articleService.getCodeBlock(this.id, fileName); - _codeBlock = highlight.highlightAuto(_codeBlock, ['javascript']).value; - return this.sanitizer.bypassSecurityTrustHtml(_codeBlock); - }; -} +import { cmsArticleService } from '../../cores/services'; -export var article1474380939Component = ngCore.Component({ +export var article1474380939Component = Component({ selector: 'article', templateUrl: './templates/article-1474380939.html', - directives: [ - CODE_PANEL_DIRECTIVES, - HIGHLIGHT_DIRECTIVES, - TABLE_CONTENT_DIRECTIVES - ], - providers: [ TABLE_CONTENT_PROVIDERS ], host: { '[class.xblog-article-1474380939]': 'true' } }) .Class({ constructor: [ - DomSanitizationService, + DomSanitizer, cmsArticleService, - tableContentService, + xblogTableContentService, function (sanitizer, articleService, tableContentService){ this.id = 1474380939; diff --git a/cms/articles/1474380939/article-1474380939.component.js b/cms/articles/1474380939/article-1474380939.component.js index 30d2508..c9a034e 100644 --- a/cms/articles/1474380939/article-1474380939.component.js +++ b/cms/articles/1474380939/article-1474380939.component.js @@ -1,138 +1,24 @@ -import * as ngCore from '@angular/core'; -import { DomSanitizationService } from '@angular/platform-browser'; +import { Component } from '@angular/core'; +import { DomSanitizer } from '@angular/platform-browser'; import highlight from 'highlight.js'; -import { - CODE_PANEL_DIRECTIVES, - HIGHLIGHT_DIRECTIVES, - TABLE_CONTENT_DIRECTIVES, - TABLE_CONTENT_PROVIDERS, - tableContentService, -} from 'xblog-cores/components'; +import { xblogTableContentService } from 'xblog-cores/modules'; import { resourceUtils } from 'xblog-cores/utils'; -import { cmsArticleService } from '../../cores/services'; - -function _article1474380939Component(){ - this.constructor = [ - DomSanitizationService, - cmsArticleService, - - function article1474380939Component(sanitizer, articleService){ - this.id = 1474380939; - this.sanitizer = sanitizer; - this.articleService = articleService; - } - ]; - - this.ngOnInit = function() { - this.simpleDI = { - sourceCode: { - name: 'simple-di', - link: resourceUtils.getGithubArticleFileLink(this.id, 'simple-di') - }, - codeBlocks: { - 1: this.getCodeBlock('simple-di.html') - }, - screenCaptures: { - 1: resourceUtils.getImg('simpleDI-example-1474380939.png') - } - }; - - this.classProvider = { - sourceCode: { - name: 'class-provider', - link: resourceUtils.getGithubArticleFileLink(this.id, 'class-provider') - }, - codeBlocks: { - 1: this.getCodeBlock('class-provider-1.html'), - 2: this.getCodeBlock('class-provider-2.html'), - 3: this.getCodeBlock('class-provider-3.html') - }, - screenCaptures: { - 1: resourceUtils.getImg('classProvider-example-1474380939.png') - } - }; - - this.valueProvider = { - sourceCode: { - name: 'value-provider', - link: resourceUtils.getGithubArticleFileLink(this.id, 'value-provider') - }, - codeBlocks: { - 1: this.getCodeBlock('value-provider-1.html'), - 2: this.getCodeBlock('value-provider-2.html') - } - }; - this.factoryProvider = { - sourceCode: { - name: 'factory-provider', - link: resourceUtils.getGithubArticleFileLink(this.id, 'factory-provider') - }, - codeBlocks: { - 1: this.getCodeBlock('factory-provider.html') - } - }; - - this.optionalDependency = { - sourceCode: { - name: 'optional-dependency', - link: resourceUtils.getGithubArticleFileLink(this.id, 'optional-dependency') - }, - codeBlocks: { - 1: this.getCodeBlock('optional-dependency.html') - } - }; - - this.hostDependency = { - sourceCode: { - name: 'host-dependency', - link: resourceUtils.getGithubArticleFileLink(this.id, 'host-dependency') - }, - codeBlocks: { - 1: this.getCodeBlock('host-dependency.html') - } - }; - - this.dependencyVisibility = { - sourceCode: { - name: 'dependency-visibility', - link: resourceUtils.getGithubArticleFileLink(this.id, 'dependency-visibility') - }, - codeBlocks: { - 1: this.getCodeBlock('dependency-visibility.html') - }, - screenCaptures: { - 1: resourceUtils.getImg('dependencyVisibility-example-1474380939.png') - } - }; - }; - - this.getCodeBlock = function(fileName) { - var _codeBlock = this.articleService.getCodeBlock(this.id, fileName); - _codeBlock = highlight.highlightAuto(_codeBlock, ['javascript']).value; - return this.sanitizer.bypassSecurityTrustHtml(_codeBlock); - }; -} +import { cmsArticleService } from '../../cores/services'; -export var article1474380939Component = ngCore.Component({ +export var article1474380939Component = Component({ selector: 'article', template: "
Table of Contents

Angular ships with its own dependency injection framework and we really can't build an Angular application without it

An Angular application is a tree of components. Each component instance has its own injector. The tree of components parallels the tree of injectors.

We can re-configure the injectors at any level of that component tree with interesting and useful results.


Consider a simple example about TodosComponent


{{simpleDI.sourceCode.name}}full code

Each component instance gets its own injector and an injector at one level is a child injector of the injector above it in the tree.


When a component at the bottom requests a dependency, Angular tries to satisfy that dependency with a provider registered in that component's own injector.

If the component's injector lacks the provider, it passes the request up to its parent component's injector. If that injector can't satisfy the request, it passes it along to its parent component's injector.

The requests keep bubbling up until we find an injector that can handle the request or run out of component ancestors. If we run out of ancestors, Angular throws an error.


Dependencies are singletons within the scope of an injector.


In our example, logSerivce are shared among todosComponent, todoListComponent, todoItemComponent. Because it is hosted by todosComponent which is parents of todoListComponent & todoItemComponent

todoListComponent can inject logSerivce from todosComponent via its constructor. However, nested injectors at todoItemComponent create their own service instances by using providers to host logService itself



Injector providers

A provider provides the concrete of a dependency value.

The injector relies on providers to create instances of the services that the injector injects into components and other services.


As you know, we can register service provider or directive provider by using providers & directives in component's declaration

Look back our example, you can see the way we registered logSerivce in TodosComponent


But there are many ways that we can configure the injector with alternative providers that can deliver an object that behaves like logSerivce. We'll expore them now.


Class Provider

We wrote the providers array like this: providers: [ logSerivce ]

This is actually a short-hand expression for a provider registration




The first is the token that serves as the key for both locating a dependency value and registering the provider.

The second is a provider definition object, which we can think of as a recipe for creating the dependency value


With this expression, it's easy for us specify another class to provide the service

For example we have another service is superLogService, We can register it for todoListComponent with logSerivce token instead of logSerivce class




However, lets look back the example that you registered logService in todosComponent then you used useClass to register superLogService in todoListComponent

So how can todoItemComponent inject logService from todoComponent instead of superLogService from todoListComponent ?


The solution for this case is you should use useExisting with rootLogService token for register in todosComponent


{{classProvider.sourceCode.name}}full code


Value Provider

Sometimes it's easier to provide a object rather than ask the injector to create it from a class.

We can re-write superLogService as an object then registering it by using useValue like this




Now, you have seen I used a class as the token such as logService, rootLogService for register, acttualy, there's another way for you to get the same result.

The way I'm mentioning is using OpaqueToken & ngCore.Inject


{{valueProvider.sourceCode.name}}full code

OpaqueToken is a good solution for us to inject global variables such as window, localstorage into our component


Factory provider

Sometimes we need to create the dependent value dynamically, based on information we won't have until the last possible moment. This situation calls for a factory provider.


Let's illustrate, we want to implement a logic like that if user is authenticated, superLogService should be injected into our components, otherwise, logSerivce should be used.

Assume that we have userService which provide information about authentication. We re-write declaration for providers as below


{{factoryProvider.sourceCode.name}}full code

The deps property is an array of provider tokens which our factory requires for injection


Optional dependencies

As you know, if Angular can't resolve injection for component, it'll throw an exception.

In fact, there're situations, we allow the constructor's arguments to be null. We can tell Angular that the dependency is optional by annotating the constructor argument with Optional

Of course, your code must be prepared to handle a null value.


{{optionalDependency.sourceCode.name}}full code

Dependency visibility

Well, as we learned, we can use the providers property to define providers for its injector.

However, it turns out that there’s another property viewProviders that basically allows us to do the same thing. What’s the difference between those two them ?


viewProviders allows us to define injector providers that are only available for a component’s view.

Let’s take a closer look at what that means by using our TodosComponent example.


{{dependencyVisibility.sourceCode.name}}full code

As you can see, todoTitleComponent is contentChild of TodoListComponent, todoItemComponent is viewChild of TodoListComponent

Both todoTitleComponent & todoItemComponent require an instance of the class which is provided via logSerivce token

How should we do if we expect that todoTitleComponent require logSerivce's instance, todoItemComponent require superLogService's instance ?


With viewProviders we can tell the DI system very specifically, which providers are available to which child injectors.

To make our code work as expected, all we have to do is to make the supperLogService provider of todoListComponent explicitly available only for its viewChild by using viewProviders instead of providers



Now, whenever a component of todoListComponent’s view asks for something of type logSerivce, it’ll get an instance of superLogService as expected.

Other child components from the outside world(contentChild) that ask for the same type, however, they won’t see this provider and will continue with the lookup in the injector tree.

Which means todoTitleComponent now gets an expected instance from another parent injector without even knowing that todoListComponent actually introduces its own provider.


Note that, viewProviders are also only available in components, not in directives. That’s simply because a directive doesn’t have its own view.


Restricting dependency lookup

We'll go on with the example in Dependency visibility subject.

Now, look back again, in the example, todoItemComponent requires logSerivce, follow DI rules, it will receice superLogService which is provided by todoListComponent.

This's so cool, however this can be problematic. Just imagine someone uses our todoItemComponent with their customTodoListComponent which doesn't provide superLogService.

What will happen ? our todoItemComponent will receice logSerivce's instance from another parent injector instead. It's unexpected.


If we need to ensure that superLogService instance is always instatiated by our component’s host or an exception should be thrown. Host dependency is a solution for us.


{{hostDependency.sourceCode.name}}full code", - directives: [ - CODE_PANEL_DIRECTIVES, - HIGHLIGHT_DIRECTIVES, - TABLE_CONTENT_DIRECTIVES - ], - providers: [ TABLE_CONTENT_PROVIDERS ], host: { '[class.xblog-article-1474380939]': 'true' } }) .Class({ constructor: [ - DomSanitizationService, + DomSanitizer, cmsArticleService, - tableContentService, + xblogTableContentService, function (sanitizer, articleService, tableContentService){ this.id = 1474380939; From 7b062598d80e848ba023923c283ae3a9e3c6094e Mon Sep 17 00:00:00 2001 From: Minh Van Date: Sat, 12 Nov 2016 12:29:18 +0700 Subject: [PATCH 5/6] Updated "Dependency Injection" article --- .../article-1474380939.component.js | 2 +- .../templates/article-1474380939.html | 57 ++++++++++--------- 2 files changed, 30 insertions(+), 29 deletions(-) diff --git a/cms/articles/1474380939/article-1474380939.component.js b/cms/articles/1474380939/article-1474380939.component.js index c9a034e..8de400e 100644 --- a/cms/articles/1474380939/article-1474380939.component.js +++ b/cms/articles/1474380939/article-1474380939.component.js @@ -9,7 +9,7 @@ import { cmsArticleService } from '../../cores/services'; export var article1474380939Component = Component({ selector: 'article', - template: "
Table of Contents

Angular ships with its own dependency injection framework and we really can't build an Angular application without it

An Angular application is a tree of components. Each component instance has its own injector. The tree of components parallels the tree of injectors.

We can re-configure the injectors at any level of that component tree with interesting and useful results.


Consider a simple example about TodosComponent


{{simpleDI.sourceCode.name}}full code

Each component instance gets its own injector and an injector at one level is a child injector of the injector above it in the tree.


When a component at the bottom requests a dependency, Angular tries to satisfy that dependency with a provider registered in that component's own injector.

If the component's injector lacks the provider, it passes the request up to its parent component's injector. If that injector can't satisfy the request, it passes it along to its parent component's injector.

The requests keep bubbling up until we find an injector that can handle the request or run out of component ancestors. If we run out of ancestors, Angular throws an error.


Dependencies are singletons within the scope of an injector.


In our example, logSerivce are shared among todosComponent, todoListComponent, todoItemComponent. Because it is hosted by todosComponent which is parents of todoListComponent & todoItemComponent

todoListComponent can inject logSerivce from todosComponent via its constructor. However, nested injectors at todoItemComponent create their own service instances by using providers to host logService itself



Injector providers

A provider provides the concrete of a dependency value.

The injector relies on providers to create instances of the services that the injector injects into components and other services.


As you know, we can register service provider or directive provider by using providers & directives in component's declaration

Look back our example, you can see the way we registered logSerivce in TodosComponent


But there are many ways that we can configure the injector with alternative providers that can deliver an object that behaves like logSerivce. We'll expore them now.


Class Provider

We wrote the providers array like this: providers: [ logSerivce ]

This is actually a short-hand expression for a provider registration




The first is the token that serves as the key for both locating a dependency value and registering the provider.

The second is a provider definition object, which we can think of as a recipe for creating the dependency value


With this expression, it's easy for us specify another class to provide the service

For example we have another service is superLogService, We can register it for todoListComponent with logSerivce token instead of logSerivce class




However, lets look back the example that you registered logService in todosComponent then you used useClass to register superLogService in todoListComponent

So how can todoItemComponent inject logService from todoComponent instead of superLogService from todoListComponent ?


The solution for this case is you should use useExisting with rootLogService token for register in todosComponent


{{classProvider.sourceCode.name}}full code


Value Provider

Sometimes it's easier to provide a object rather than ask the injector to create it from a class.

We can re-write superLogService as an object then registering it by using useValue like this




Now, you have seen I used a class as the token such as logService, rootLogService for register, acttualy, there's another way for you to get the same result.

The way I'm mentioning is using OpaqueToken & ngCore.Inject


{{valueProvider.sourceCode.name}}full code

OpaqueToken is a good solution for us to inject global variables such as window, localstorage into our component


Factory provider

Sometimes we need to create the dependent value dynamically, based on information we won't have until the last possible moment. This situation calls for a factory provider.


Let's illustrate, we want to implement a logic like that if user is authenticated, superLogService should be injected into our components, otherwise, logSerivce should be used.

Assume that we have userService which provide information about authentication. We re-write declaration for providers as below


{{factoryProvider.sourceCode.name}}full code

The deps property is an array of provider tokens which our factory requires for injection


Optional dependencies

As you know, if Angular can't resolve injection for component, it'll throw an exception.

In fact, there're situations, we allow the constructor's arguments to be null. We can tell Angular that the dependency is optional by annotating the constructor argument with Optional

Of course, your code must be prepared to handle a null value.


{{optionalDependency.sourceCode.name}}full code

Dependency visibility

Well, as we learned, we can use the providers property to define providers for its injector.

However, it turns out that there’s another property viewProviders that basically allows us to do the same thing. What’s the difference between those two them ?


viewProviders allows us to define injector providers that are only available for a component’s view.

Let’s take a closer look at what that means by using our TodosComponent example.


{{dependencyVisibility.sourceCode.name}}full code

As you can see, todoTitleComponent is contentChild of TodoListComponent, todoItemComponent is viewChild of TodoListComponent

Both todoTitleComponent & todoItemComponent require an instance of the class which is provided via logSerivce token

How should we do if we expect that todoTitleComponent require logSerivce's instance, todoItemComponent require superLogService's instance ?


With viewProviders we can tell the DI system very specifically, which providers are available to which child injectors.

To make our code work as expected, all we have to do is to make the supperLogService provider of todoListComponent explicitly available only for its viewChild by using viewProviders instead of providers



Now, whenever a component of todoListComponent’s view asks for something of type logSerivce, it’ll get an instance of superLogService as expected.

Other child components from the outside world(contentChild) that ask for the same type, however, they won’t see this provider and will continue with the lookup in the injector tree.

Which means todoTitleComponent now gets an expected instance from another parent injector without even knowing that todoListComponent actually introduces its own provider.


Note that, viewProviders are also only available in components, not in directives. That’s simply because a directive doesn’t have its own view.


Restricting dependency lookup

We'll go on with the example in Dependency visibility subject.

Now, look back again, in the example, todoItemComponent requires logSerivce, follow DI rules, it will receice superLogService which is provided by todoListComponent.

This's so cool, however this can be problematic. Just imagine someone uses our todoItemComponent with their customTodoListComponent which doesn't provide superLogService.

What will happen ? our todoItemComponent will receice logSerivce's instance from another parent injector instead. It's unexpected.


If we need to ensure that superLogService instance is always instatiated by our component’s host or an exception should be thrown. Host dependency is a solution for us.


{{hostDependency.sourceCode.name}}full code", + template: "
Table of Contents

Angular ships with its own dependency injection framework and we really can't build an Angular application without it.

An Angular application is a tree of components. Each component instance has its own injector. The tree of components parallels the tree of injectors.

We can re-configure the injectors at any level of that component tree with interesting and useful results.


Consider a simple example about TodosComponent


{{simpleDI.sourceCode.name}}full code

Each component instance gets its own injector and an injector at one level is a child injector of the injector above it in the tree.


When a component at the bottom requests a dependency, Angular tries to satisfy that dependency with a provider registered in that component's own injector.

If the component's injector lacks the provider, it passes the request up to its parent component's injector. If that injector can't satisfy the request, it passes it along to its parent component's injector.

The requests keep bubbling up until we find an injector that can handle the request or run out of component ancestors. If we run out of ancestors, Angular throws an error.


Dependencies are singletons within the scope of an injector.


In our example, logSerivce are shared among todosComponent, todoListComponent, todoItemComponent. Because it is hosted by todosComponent which is parents of todoListComponent & todoItemComponent.

todoListComponent can inject logSerivce from todosComponent via its constructor. However, nested injectors at todoItemComponent create their own service instances by using providers to host logService itself.



Injector providers

A provider provides the concrete of a dependency value.

The injector relies on providers to create instances of the services that the injector injects into components and other services.


As you know, we can register service provider or directive provider by using providers & directives in component's declaration.

Look back our example, you can see the way we registered logSerivce in TodosComponent


But there are many ways that we can configure the injector with alternative providers that can deliver an object that behaves like logSerivce. We'll expore them now.


Class Provider

We wrote the providers array like this: providers: [ logSerivce ]

This is actually a short-hand expression for a provider registration.




The first is the token that serves as the key for both locating a dependency value and registering the provider.

The second is a provider definition object, which we can think of as a recipe for creating the dependency value.


With this expression, it's easy for us specify another class to provide the service.

For example we have another service is superLogService, We can register it for todoListComponent with logSerivce token instead of logSerivce class.




However, lets look back the example that you registered logService in todosComponent then you used useClass to register superLogService in todoListComponent

So how can todoItemComponent inject logService from todoComponent instead of superLogService from todoListComponent ?


The solution for this case is you should use useExisting with rootLogService token for register in todosComponent.


{{classProvider.sourceCode.name}}full code


Value Provider

Sometimes it's easier to provide a object rather than ask the injector to create it from a class.

We can re-write superLogService as an object then registering it by using useValue like this.




Now, you have seen I used a class as the token such as logService, rootLogService for register, acttualy, there's another way for you to get the same result.

The way I'm mentioning is using OpaqueToken & ngCore.Inject


{{valueProvider.sourceCode.name}}full code

OpaqueToken is a good solution for us to inject global variables such as window, localstorage into our component.


Factory provider

Sometimes we need to create the dependent value dynamically, based on information we won't have until the last possible moment. This situation calls for a factory provider.


Let's illustrate, we want to implement a logic like that if user is authenticated, superLogService should be injected into our components, otherwise, logSerivce should be used.

Assume that we have userService which provide information about authentication. We re-write declaration for providers as below.


{{factoryProvider.sourceCode.name}}full code

The deps property is an array of provider tokens which our factory requires for injection.


Optional dependencies

As you know, if Angular can't resolve injection for component, it'll throw an exception.

In fact, there're situations, we allow the constructor's arguments to be null. We can tell Angular that the dependency is optional by annotating the constructor argument with Optional

Of course, your code must be prepared to handle a null value.


{{optionalDependency.sourceCode.name}}full code

Dependency visibility

Well, as we learned, we can use the providers property to define providers for its injector.

However, it turns out that there’s another property viewProviders that basically allows us to do the same thing. What’s the difference between those two them ?


viewProviders allows us to define injector providers that are only available for a component’s view.

Let’s take a closer look at what that means by using our TodosComponent example.


{{dependencyVisibility.sourceCode.name}}full code

As you can see, todoTitleComponent is contentChild of TodoListComponent, todoItemComponent is viewChild of TodoListComponent

Both todoTitleComponent & todoItemComponent require an instance of the class which is provided via logSerivce token

How should we do if we expect that todoTitleComponent require logSerivce's instance, todoItemComponent require superLogService's instance ?


With viewProviders we can tell the DI system very specifically, which providers are available to which child injectors.

To make our code work as expected, all we have to do is to make the supperLogService provider of todoListComponent explicitly available only for its viewChild by using viewProviders instead of providers



Now, whenever a component of todoListComponent's view asks for something of type logSerivce, it’ll get an instance of superLogService as expected.

Other child components from the outside world(contentChild) that ask for the same type, however, they won’t see this provider and will continue with the lookup in the injector tree.

Which means todoTitleComponent now gets an expected instance from another parent injector without even knowing that todoListComponent actually introduces its own provider.


Note that, viewProviders are also only available in components, not in directives. That’s simply because a directive doesn’t have its own view.


Restricting dependency lookup

We'll go on with the example in Dependency visibility subject.

Now, look back again, in the example, todoItemComponent requires logSerivce, follow DI rules, it will receice superLogService which is provided by todoListComponent.

This's so cool, however this can be problematic. Just imagine someone uses our todoItemComponent with their customTodoListComponent which doesn't provide superLogService

What will happen ? our todoItemComponent will receice logSerivce's instance from another parent injector instead. It's unexpected.


If we need to ensure that superLogService instance is always instatiated by our component’s host or an exception should be thrown. Host dependency is a solution for us.


{{hostDependency.sourceCode.name}}full code
", host: { '[class.xblog-article-1474380939]': 'true' } diff --git a/cms/articles/1474380939/templates/article-1474380939.html b/cms/articles/1474380939/templates/article-1474380939.html index 1b4677f..12aa94a 100644 --- a/cms/articles/1474380939/templates/article-1474380939.html +++ b/cms/articles/1474380939/templates/article-1474380939.html @@ -4,11 +4,11 @@
Table of Contents

-

Angular ships with its own dependency injection framework and we really can't build an Angular application without it

+

Angular ships with its own dependency injection framework and we really can't build an Angular application without it.

An Angular application is a tree of components. Each component instance has its own injector. The tree of components parallels the tree of injectors.

We can re-configure the injectors at any level of that component tree with interesting and useful results.


-

Consider a simple example about TodosComponent

+

Consider a simple example about TodosComponent


{{simpleDI.sourceCode.name}} @@ -25,8 +25,8 @@
Table of Contents

Dependencies are singletons within the scope of an injector.


-

In our example, logSerivce are shared among todosComponent, todoListComponent, todoItemComponent. Because it is hosted by todosComponent which is parents of todoListComponent & todoItemComponent

-

todoListComponent can inject logSerivce from todosComponent via its constructor. However, nested injectors at todoItemComponent create their own service instances by using providers to host logService itself

+

In our example, logSerivce are shared among todosComponent, todoListComponent, todoItemComponent. Because it is hosted by todosComponent which is parents of todoListComponent & todoItemComponent.

+

todoListComponent can inject logSerivce from todosComponent via its constructor. However, nested injectors at todoItemComponent create their own service instances by using providers to host logService itself.



@@ -34,14 +34,14 @@

Injector providers

A provider provides the concrete of a dependency value.

The injector relies on providers to create instances of the services that the injector injects into components and other services.


-

As you know, we can register service provider or directive provider by using providers & directives in component's declaration

-

Look back our example, you can see the way we registered logSerivce in TodosComponent

+

As you know, we can register service provider or directive provider by using providers & directives in component's declaration.

+

Look back our example, you can see the way we registered logSerivce in TodosComponent


But there are many ways that we can configure the injector with alternative providers that can deliver an object that behaves like logSerivce. We'll expore them now.


Class Provider

We wrote the providers array like this: providers: [ logSerivce ]

-

This is actually a short-hand expression for a provider registration

+

This is actually a short-hand expression for a provider registration.


@@ -49,20 +49,20 @@

Class Provider



The first is the token that serves as the key for both locating a dependency value and registering the provider.

-

The second is a provider definition object, which we can think of as a recipe for creating the dependency value

+

The second is a provider definition object, which we can think of as a recipe for creating the dependency value.


-

With this expression, it's easy for us specify another class to provide the service

-

For example we have another service is superLogService, We can register it for todoListComponent with logSerivce token instead of logSerivce class

+

With this expression, it's easy for us specify another class to provide the service.

+

For example we have another service is superLogService, We can register it for todoListComponent with logSerivce token instead of logSerivce class.




-

However, lets look back the example that you registered logService in todosComponent then you used useClass to register superLogService in todoListComponent

+

However, lets look back the example that you registered logService in todosComponent then you used useClass to register superLogService in todoListComponent

So how can todoItemComponent inject logService from todoComponent instead of superLogService from todoListComponent ?


-

The solution for this case is you should use useExisting with rootLogService token for register in todosComponent

+

The solution for this case is you should use useExisting with rootLogService token for register in todosComponent.


{{classProvider.sourceCode.name}} @@ -75,7 +75,7 @@

Class Provider


Value Provider

Sometimes it's easier to provide a object rather than ask the injector to create it from a class.

-

We can re-write superLogService as an object then registering it by using useValue like this

+

We can re-write superLogService as an object then registering it by using useValue like this.


@@ -92,13 +92,13 @@

Value Provider



-

OpaqueToken is a good solution for us to inject global variables such as window, localstorage into our component

+

OpaqueToken is a good solution for us to inject global variables such as window, localstorage into our component.


Factory provider

Sometimes we need to create the dependent value dynamically, based on information we won't have until the last possible moment. This situation calls for a factory provider.


-

Let's illustrate, we want to implement a logic like that if user is authenticated, superLogService should be injected into our components, otherwise, logSerivce should be used.

-

Assume that we have userService which provide information about authentication. We re-write declaration for providers as below

+

Let's illustrate, we want to implement a logic like that if user is authenticated, superLogService should be injected into our components, otherwise, logSerivce should be used.

+

Assume that we have userService which provide information about authentication. We re-write declaration for providers as below.


{{factoryProvider.sourceCode.name}} @@ -107,11 +107,11 @@

Factory provider



-

The deps property is an array of provider tokens which our factory requires for injection

+

The deps property is an array of provider tokens which our factory requires for injection.


Optional dependencies

As you know, if Angular can't resolve injection for component, it'll throw an exception.

-

In fact, there're situations, we allow the constructor's arguments to be null. We can tell Angular that the dependency is optional by annotating the constructor argument with Optional

+

In fact, there're situations, we allow the constructor's arguments to be null. We can tell Angular that the dependency is optional by annotating the constructor argument with Optional

Of course, your code must be prepared to handle a null value.


@@ -125,8 +125,8 @@

Dependency visibility

Well, as we learned, we can use the providers property to define providers for its injector.

However, it turns out that there’s another property viewProviders that basically allows us to do the same thing. What’s the difference between those two them ?


-

viewProviders allows us to define injector providers that are only available for a component’s view.

-

Let’s take a closer look at what that means by using our TodosComponent example.

+

viewProviders allows us to define injector providers that are only available for a component’s view.

+

Let’s take a closer look at what that means by using our TodosComponent example.


{{dependencyVisibility.sourceCode.name}} @@ -135,7 +135,7 @@

Dependency visibility



-

As you can see, todoTitleComponent is contentChild of TodoListComponent, todoItemComponent is viewChild of TodoListComponent

+

As you can see, todoTitleComponent is contentChild of TodoListComponent, todoItemComponent is viewChild of TodoListComponent.

Both todoTitleComponent & todoItemComponent require an instance of the class which is provided via logSerivce token

How should we do if we expect that todoTitleComponent require logSerivce's instance, todoItemComponent require superLogService's instance ?


@@ -144,22 +144,23 @@

Dependency visibility


-

Now, whenever a component of todoListComponent’s view asks for something of type logSerivce, it’ll get an instance of superLogService as expected.

+

Now, whenever a component of todoListComponent's view asks for something of type logSerivce, it’ll get an instance of superLogService as expected.

Other child components from the outside world(contentChild) that ask for the same type, however, they won’t see this provider and will continue with the lookup in the injector tree.

-

Which means todoTitleComponent now gets an expected instance from another parent injector without even knowing that todoListComponent actually introduces its own provider.

+

Which means todoTitleComponent now gets an expected instance from another parent injector without even knowing that todoListComponent actually introduces its own provider.


-

Note that, viewProviders are also only available in components, not in directives. That’s simply because a directive doesn’t have its own view.

+

Note that, viewProviders are also only available in components, not in directives. That’s simply because a directive doesn’t have its own view.


Restricting dependency lookup

We'll go on with the example in Dependency visibility subject.

Now, look back again, in the example, todoItemComponent requires logSerivce, follow DI rules, it will receice superLogService which is provided by todoListComponent.

-

This's so cool, however this can be problematic. Just imagine someone uses our todoItemComponent with their customTodoListComponent which doesn't provide superLogService.

-

What will happen ? our todoItemComponent will receice logSerivce's instance from another parent injector instead. It's unexpected.

+

This's so cool, however this can be problematic. Just imagine someone uses our todoItemComponent with their customTodoListComponent which doesn't provide superLogService

+

What will happen ? our todoItemComponent will receice logSerivce's instance from another parent injector instead. It's unexpected.


-

If we need to ensure that superLogService instance is always instatiated by our component’s host or an exception should be thrown. Host dependency is a solution for us.

+

If we need to ensure that superLogService instance is always instatiated by our component’s host or an exception should be thrown. Host dependency is a solution for us.


{{hostDependency.sourceCode.name}} full code - \ No newline at end of file +
+
\ No newline at end of file From 4bb1d6484b27b213d1e37ebc634f0c2d284f212b Mon Sep 17 00:00:00 2001 From: Minh Van Date: Wed, 16 Nov 2016 13:35:42 +0700 Subject: [PATCH 6/6] Updated "Dependency Injection" article --- .../_article-1474380939.component.js | 360 +++++++++++++++-- .../article-1474380939.component.js | 362 ++++++++++++++++-- .../code-blocks/class-provider-1.html | 5 - .../code-blocks/class-provider-2.html | 7 - .../code-blocks/class-provider-3.html | 55 --- .../code-blocks/dependency-visibility.html | 46 --- .../code-blocks/factory-provider.html | 38 -- .../code-blocks/host-dependency.html | 10 - .../code-blocks/optional-dependency.html | 12 - .../1474380939/code-blocks/simple-di.html | 48 --- .../code-blocks/value-provider-1.html | 13 - .../code-blocks/value-provider-2.html | 43 --- cms/articles/1474380939/index.js | 4 +- .../templates/article-1474380939.html | 17 +- 14 files changed, 684 insertions(+), 336 deletions(-) delete mode 100644 cms/articles/1474380939/code-blocks/class-provider-1.html delete mode 100644 cms/articles/1474380939/code-blocks/class-provider-2.html delete mode 100644 cms/articles/1474380939/code-blocks/class-provider-3.html delete mode 100644 cms/articles/1474380939/code-blocks/dependency-visibility.html delete mode 100644 cms/articles/1474380939/code-blocks/factory-provider.html delete mode 100644 cms/articles/1474380939/code-blocks/host-dependency.html delete mode 100644 cms/articles/1474380939/code-blocks/optional-dependency.html delete mode 100644 cms/articles/1474380939/code-blocks/simple-di.html delete mode 100644 cms/articles/1474380939/code-blocks/value-provider-1.html delete mode 100644 cms/articles/1474380939/code-blocks/value-provider-2.html diff --git a/cms/articles/1474380939/_article-1474380939.component.js b/cms/articles/1474380939/_article-1474380939.component.js index 41bd477..ae337b7 100644 --- a/cms/articles/1474380939/_article-1474380939.component.js +++ b/cms/articles/1474380939/_article-1474380939.component.js @@ -5,7 +5,6 @@ import highlight from 'highlight.js'; import { xblogTableContentService } from 'xblog-cores/modules'; import { resourceUtils } from 'xblog-cores/utils'; -import { cmsArticleService } from '../../cores/services'; export var article1474380939Component = Component({ selector: 'article', @@ -17,13 +16,11 @@ export var article1474380939Component = Component({ .Class({ constructor: [ DomSanitizer, - cmsArticleService, xblogTableContentService, - function (sanitizer, articleService, tableContentService){ + function (sanitizer, tableContentService){ this.id = 1474380939; this.sanitizer = sanitizer; - this.articleService = articleService; this.tableContentService = tableContentService; } ], @@ -44,11 +41,11 @@ export var article1474380939Component = Component({ this.simpleDI = { sourceCode: { - name: 'simple-di', + name: 'Simple DI', link: resourceUtils.getGithubArticleFileLink(this.id, 'simple-di') }, codeBlocks: { - 1: this.getCodeBlock('simple-di.html') + 1: this.getCodeBlock(getSimpleDI) }, screenCaptures: { 1: resourceUtils.getImg('simpleDI-example-1474380939.png') @@ -57,13 +54,13 @@ export var article1474380939Component = Component({ this.classProvider = { sourceCode: { - name: 'class-provider', + name: 'Class provider', link: resourceUtils.getGithubArticleFileLink(this.id, 'class-provider') }, codeBlocks: { - 1: this.getCodeBlock('class-provider-1.html'), - 2: this.getCodeBlock('class-provider-2.html'), - 3: this.getCodeBlock('class-provider-3.html') + 1: this.getCodeBlock(getClassProvider01), + 2: this.getCodeBlock(getClassProvider02), + 3: this.getCodeBlock(getClassProvider03) }, screenCaptures: { 1: resourceUtils.getImg('classProvider-example-1474380939.png') @@ -72,52 +69,52 @@ export var article1474380939Component = Component({ this.valueProvider = { sourceCode: { - name: 'value-provider', + name: 'Value provider', link: resourceUtils.getGithubArticleFileLink(this.id, 'value-provider') }, codeBlocks: { - 1: this.getCodeBlock('value-provider-1.html'), - 2: this.getCodeBlock('value-provider-2.html') + 1: this.getCodeBlock(getValueProvider01), + 2: this.getCodeBlock(getValueProvider02) } }; this.factoryProvider = { sourceCode: { - name: 'factory-provider', + name: 'Factory provider', link: resourceUtils.getGithubArticleFileLink(this.id, 'factory-provider') }, codeBlocks: { - 1: this.getCodeBlock('factory-provider.html') + 1: this.getCodeBlock(getFactoryProvider) } }; this.optionalDependency = { sourceCode: { - name: 'optional-dependency', + name: 'Optional dependency', link: resourceUtils.getGithubArticleFileLink(this.id, 'optional-dependency') }, codeBlocks: { - 1: this.getCodeBlock('optional-dependency.html') + 1: this.getCodeBlock(getOptionalDependency) } }; this.hostDependency = { sourceCode: { - name: 'host-dependency', + name: 'Host dependency', link: resourceUtils.getGithubArticleFileLink(this.id, 'host-dependency') }, codeBlocks: { - 1: this.getCodeBlock('host-dependency.html') + 1: this.getCodeBlock(getHostDependency) } }; this.dependencyVisibility = { sourceCode: { - name: 'dependency-visibility', + name: 'Dependency visibility', link: resourceUtils.getGithubArticleFileLink(this.id, 'dependency-visibility') }, codeBlocks: { - 1: this.getCodeBlock('dependency-visibility.html') + 1: this.getCodeBlock(getDependencyVisibility) }, screenCaptures: { 1: resourceUtils.getImg('dependencyVisibility-example-1474380939.png') @@ -125,12 +122,327 @@ export var article1474380939Component = Component({ }; }, - getCodeBlock: function(fileName, lang) { + getCodeBlock: function(getter, lang) { var _langs = lang ? [ lang ] : ['javascript', 'html', 'css']; - var _codeBlock = this.articleService.getCodeBlock(this.id, fileName); - _codeBlock = highlight.highlightAuto(_codeBlock, _langs).value; + var _codeBlock = highlight.highlightAuto(getter().replace('\n', '').replace(/^ /gm, ''), _langs).value; return this.sanitizer.bypassSecurityTrustHtml(_codeBlock); } }); + +function getSimpleDI(){ + return ` + import * as ngCore from '@angular/core'; + + export var logService = ngCore.Class({ + constructor: function(){ + this.name = 'logService'; + }, + + setName: function(name){ + this.name = name; + } + }); + + /*---------------------------------------------------------*/ + + export var todoItemComponent = ngCore.Component({ + ..... + providers: [ logService ] + }) + .Class({ + constructor: [logService, function(logService){ + console.log('todoItemComponent', logService.name); + }] + }); + + /*---------------------------------------------------------*/ + + export var todoListComponent = ngCore.Component({ + ..... + directives: [ todoItemComponent ] + }) + .Class({ + constructor: [logService, function(logService){ + console.log('todoListComponent', logService.name); + }] + }); + + /*---------------------------------------------------------*/ + + export var todosComponent = ngCore.Component({ + ..... + providers: [ logService ], + directives: [ todoListComponent, todoItemComponent ] + }) + .Class({ + constructor: [logService, function(logService){ + logService.setName('logService is hosted by todosComponent'); + }] + });`; +} + +function getClassProvider01(){ + return ` + ngCore.Component({ + ..... + providers: [{ provide: logSerivce, useClass: logSerivce }] + }) + .Class(.....);`; +} + +function getClassProvider02(){ + return ` + export var todoListComponent = ngCore.Component({ + ..... + providers: [ + { provide: logService, useClass: supperLogService } + ] + }) + .Class(.....);`; +} + +function getClassProvider03(){ + return ` + import * as ngCore from '@angular/core'; + + export var rootLogService = ngCore.Class({ + constructor: function(){} + }); + + /*---------------------------------------------------------*/ + + export var supperLogService = ngCore.Class({ + constructor: function(){ + this.name = 'supperLogService'; + } + }); + + /*---------------------------------------------------------*/ + + export var todoItemComponent = ngCore.Component({ + ..... + }) + .Class({ + constructor: [rootLogService, function(logService){ + console.log('todoItemComponent', logService.name); + }] + }); + + /*---------------------------------------------------------*/ + + export var todoListComponent = ngCore.Component({ + ..... + directives: [ todoItemComponent ], + providers: [ + { provide: logService, useClass: supperLogService } + ] + }) + .Class({ + constructor: [logService, function(logService){ + console.log('todoListComponent', logService.name + ' is hosted by todoListComponent'); + }] + }); + + /*---------------------------------------------------------*/ + + export var todosComponent = ngCore.Component({ + ..... + directives: [ todoListComponent, todoItemComponent ], + providers: [ + logService, + { provide: rootLogService, useExisting: logService } + ] + }) + .Class({ + constructor: [logService, function(logService){ + logService.setName('logService is hosted by todosComponent'); + }] + });`; +} + +function getValueProvider01(){ + return ` + export var supperLogService = { + name: 'supperLogService' + }; + + /*---------------------------------------------------------*/ + + export var todoListComponent = ngCore.Component({ + ..... + providers: [ + { provide: logService, useValue: supperLogService } + ] + }) + .Class(.....);`; +} + +function getValueProvider02(){ + return ` + import { OpaqueToken } from '@angular/core'; + + export var WINDOW = new OpaqueToken('window'); + + export var WINDOW_PROVIDERS = [ + { provide: WINDOW, useValue: window } + ]; + + /*---------------------------------------------------------*/ + + import { WINDOW } from './window.model'; + + export var logService = ngCore.Class({ + constructor: [ + ngCore.Inject(WINDOW), + + function(window){ + this.window = window; + } + ], + + log: function(text){ + this.window.console.log(text); + } + }); + + /*---------------------------------------------------------*/ + + import { WINDOW_PROVIDERS } from './window.model'; + + export var todosComponent = ngCore.Component({ + ..... + providers: [ + logService, + WINDOW_PROVIDERS + ] + }) + .Class({ + constructor: [logService, function(logService){ + logService.log('This message is logged by using window.console via DI'); + }] + });`; +} + +function getFactoryProvider(){ + return ` + export var userService = ngCore.Class({ + ..... + setAuth: function(isAuth){ + this.isAuth = isAuth; + } + }); + + /*---------------------------------------------------------*/ + + export var todoListComponent = ngCore.Component({ + ..... + providers: [ + { + provide: logService, + useFactory: function(userService){ + return userService.isAuth ? new supperLogService() : new logService(); + }, + deps: [userService] + } + ] + }) + .Class({ + constructor: [logService, function(logService){ + console.log('todoListComponent', logService.name); + }] + }); + + /*---------------------------------------------------------*/ + + export var todosComponent = ngCore.Component({ + ..... + providers: [ userService ] + }) + .Class({ + constructor: [userService, function(userService){ + this.userService.setAuth(true); + }] + });`; +} + +function getOptionalDependency(){ + return ` + export var todoListComponent = ngCore.Component({.....}) + .Class({ + constructor: [ + [ new ngCore.Optional(), ngCore.Inject(logService) ], + + function(logService){ + if(!logService) { + console.log('todoListComponent', 'logService is null'); + } + } + ] + });`; +} + +function getHostDependency(){ + return ` + export var todoItemComponent = ngCore.Component({.....}) + .Class({ + constructor: [ + [ new ngCore.Host(), ngCore.Inject(logService) ], + + function(logService){ + console.log('todoItemComponent', logService.name); + } + ] + });`; +} + +function getDependencyVisibility(){ + return ` + export var todoTitleComponent = ngCore.Component({.....}) + .Class({ + constructor: [logService, function(logService){ + console.log('todoTitleComponent', logService.name); + }] + }); + + /*---------------------------------------------------------*/ + + export var todoItemComponent = ngCore.Component({.....}) + .Class({ + constructor: [logService, function(logService){ + console.log('todoItemComponent', logService.name); + }] + }); + + /*---------------------------------------------------------*/ + + export var todoListComponent = ngCore.Component({ + ..... + template: [ + '', + '' + ].join(''), + viewProviders: [ + { provide: logService, useClass: supperLogService } + ] + }) + .Class({ + constructor: [logService, function(logService){}] + }); + + /*---------------------------------------------------------*/ + + export var todosComponent = ngCore.Component({ + ..... + template: [ + '', + '', + '' + ].join(''), + providers: [ logService ] + }) + .Class({ + constructor: [logService, function(logService){}] + });`; +} \ No newline at end of file diff --git a/cms/articles/1474380939/article-1474380939.component.js b/cms/articles/1474380939/article-1474380939.component.js index 8de400e..1baa57c 100644 --- a/cms/articles/1474380939/article-1474380939.component.js +++ b/cms/articles/1474380939/article-1474380939.component.js @@ -5,11 +5,10 @@ import highlight from 'highlight.js'; import { xblogTableContentService } from 'xblog-cores/modules'; import { resourceUtils } from 'xblog-cores/utils'; -import { cmsArticleService } from '../../cores/services'; export var article1474380939Component = Component({ selector: 'article', - template: "
Table of Contents

Angular ships with its own dependency injection framework and we really can't build an Angular application without it.

An Angular application is a tree of components. Each component instance has its own injector. The tree of components parallels the tree of injectors.

We can re-configure the injectors at any level of that component tree with interesting and useful results.


Consider a simple example about TodosComponent


{{simpleDI.sourceCode.name}}full code

Each component instance gets its own injector and an injector at one level is a child injector of the injector above it in the tree.


When a component at the bottom requests a dependency, Angular tries to satisfy that dependency with a provider registered in that component's own injector.

If the component's injector lacks the provider, it passes the request up to its parent component's injector. If that injector can't satisfy the request, it passes it along to its parent component's injector.

The requests keep bubbling up until we find an injector that can handle the request or run out of component ancestors. If we run out of ancestors, Angular throws an error.


Dependencies are singletons within the scope of an injector.


In our example, logSerivce are shared among todosComponent, todoListComponent, todoItemComponent. Because it is hosted by todosComponent which is parents of todoListComponent & todoItemComponent.

todoListComponent can inject logSerivce from todosComponent via its constructor. However, nested injectors at todoItemComponent create their own service instances by using providers to host logService itself.



Injector providers

A provider provides the concrete of a dependency value.

The injector relies on providers to create instances of the services that the injector injects into components and other services.


As you know, we can register service provider or directive provider by using providers & directives in component's declaration.

Look back our example, you can see the way we registered logSerivce in TodosComponent


But there are many ways that we can configure the injector with alternative providers that can deliver an object that behaves like logSerivce. We'll expore them now.


Class Provider

We wrote the providers array like this: providers: [ logSerivce ]

This is actually a short-hand expression for a provider registration.




The first is the token that serves as the key for both locating a dependency value and registering the provider.

The second is a provider definition object, which we can think of as a recipe for creating the dependency value.


With this expression, it's easy for us specify another class to provide the service.

For example we have another service is superLogService, We can register it for todoListComponent with logSerivce token instead of logSerivce class.




However, lets look back the example that you registered logService in todosComponent then you used useClass to register superLogService in todoListComponent

So how can todoItemComponent inject logService from todoComponent instead of superLogService from todoListComponent ?


The solution for this case is you should use useExisting with rootLogService token for register in todosComponent.


{{classProvider.sourceCode.name}}full code


Value Provider

Sometimes it's easier to provide a object rather than ask the injector to create it from a class.

We can re-write superLogService as an object then registering it by using useValue like this.




Now, you have seen I used a class as the token such as logService, rootLogService for register, acttualy, there's another way for you to get the same result.

The way I'm mentioning is using OpaqueToken & ngCore.Inject


{{valueProvider.sourceCode.name}}full code

OpaqueToken is a good solution for us to inject global variables such as window, localstorage into our component.


Factory provider

Sometimes we need to create the dependent value dynamically, based on information we won't have until the last possible moment. This situation calls for a factory provider.


Let's illustrate, we want to implement a logic like that if user is authenticated, superLogService should be injected into our components, otherwise, logSerivce should be used.

Assume that we have userService which provide information about authentication. We re-write declaration for providers as below.


{{factoryProvider.sourceCode.name}}full code

The deps property is an array of provider tokens which our factory requires for injection.


Optional dependencies

As you know, if Angular can't resolve injection for component, it'll throw an exception.

In fact, there're situations, we allow the constructor's arguments to be null. We can tell Angular that the dependency is optional by annotating the constructor argument with Optional

Of course, your code must be prepared to handle a null value.


{{optionalDependency.sourceCode.name}}full code

Dependency visibility

Well, as we learned, we can use the providers property to define providers for its injector.

However, it turns out that there’s another property viewProviders that basically allows us to do the same thing. What’s the difference between those two them ?


viewProviders allows us to define injector providers that are only available for a component’s view.

Let’s take a closer look at what that means by using our TodosComponent example.


{{dependencyVisibility.sourceCode.name}}full code

As you can see, todoTitleComponent is contentChild of TodoListComponent, todoItemComponent is viewChild of TodoListComponent

Both todoTitleComponent & todoItemComponent require an instance of the class which is provided via logSerivce token

How should we do if we expect that todoTitleComponent require logSerivce's instance, todoItemComponent require superLogService's instance ?


With viewProviders we can tell the DI system very specifically, which providers are available to which child injectors.

To make our code work as expected, all we have to do is to make the supperLogService provider of todoListComponent explicitly available only for its viewChild by using viewProviders instead of providers



Now, whenever a component of todoListComponent's view asks for something of type logSerivce, it’ll get an instance of superLogService as expected.

Other child components from the outside world(contentChild) that ask for the same type, however, they won’t see this provider and will continue with the lookup in the injector tree.

Which means todoTitleComponent now gets an expected instance from another parent injector without even knowing that todoListComponent actually introduces its own provider.


Note that, viewProviders are also only available in components, not in directives. That’s simply because a directive doesn’t have its own view.


Restricting dependency lookup

We'll go on with the example in Dependency visibility subject.

Now, look back again, in the example, todoItemComponent requires logSerivce, follow DI rules, it will receice superLogService which is provided by todoListComponent.

This's so cool, however this can be problematic. Just imagine someone uses our todoItemComponent with their customTodoListComponent which doesn't provide superLogService

What will happen ? our todoItemComponent will receice logSerivce's instance from another parent injector instead. It's unexpected.


If we need to ensure that superLogService instance is always instatiated by our component’s host or an exception should be thrown. Host dependency is a solution for us.


{{hostDependency.sourceCode.name}}full code
", + template: "
Table of Contents

Angular ships with its own dependency injection framework and we really can't build an Angular application without it.

An Angular application is a tree of components. Each component instance has its own injector. The tree of components parallels the tree of injectors.

We can re-configure the injectors at any level of that component tree with interesting and useful results.


Consider a simple example about TodosComponent.


{{simpleDI.sourceCode.name}}full code

Each component instance gets its own injector and an injector at one level is a child injector of the injector above it in the tree.


When a component at the bottom requests a dependency, Angular tries to satisfy that dependency with a provider registered in that component's own injector.

If the component's injector lacks the provider, it passes the request up to its parent component's injector. If that injector can't satisfy the request, it passes it along to its parent component's injector.

The requests keep bubbling up until we find an injector that can handle the request or run out of component ancestors. If we run out of ancestors, Angular throws an error.


Dependencies are singletons within the scope of an injector.


In our example, logSerivce are shared among todosComponent, todoListComponent, todoItemComponent. Because it is hosted by todosComponent which is parents of todoListComponent & todoItemComponent.

todoListComponent can inject logSerivce from todosComponent via its constructor. However, nested injectors at todoItemComponent create their own service instances by using providers to host logService itself.



Injector providers

A provider provides the concrete of a dependency value.

The injector relies on providers to create instances of the services that the injector injects into components and other services.


As you know, we can register service provider or directive provider by using providers & directives in component's declaration.

Look back our example, you can see the way we registered logSerivce in TodosComponent.


But there are many ways that we can configure the injector with alternative providers that can deliver an object that behaves like logSerivce. We'll expore them now.


Class Provider

We wrote the providers array like this: providers: [ logSerivce ]

This is actually a short-hand expression for a provider registration.




The first is the token that serves as the key for both locating a dependency value and registering the provider.

The second is a provider definition object, which we can think of as a recipe for creating the dependency value.


With this expression, it's easy for us specify another class to provide the service.

For example we have another service is superLogService, We can register it for todoListComponent with logSerivce token instead of logSerivce class.




However, lets look back the example that you registered logService in todosComponent then you used useClass to register superLogService in todoListComponent.

So how can todoItemComponent inject logService from todoComponent instead of superLogService from todoListComponent ?


The solution for this case is you should use useExisting with rootLogService token for register in todosComponent.


{{classProvider.sourceCode.name}}full code


Value Provider

Sometimes it's easier to provide a object rather than ask the injector to create it from a class.

We can re-write superLogService as an object then registering it by using useValue like this.




Now, you have seen I used a class as the token such as logService, rootLogService for register, acttualy, there's another way for you to get the same result.

The way I'm mentioning is using OpaqueToken & ngCore.Inject.


{{valueProvider.sourceCode.name}}full code

OpaqueToken is a good solution for us to inject global variables such as window, localstorage into our component.


Factory provider

Sometimes we need to create the dependent value dynamically, based on information we won't have until the last possible moment. This situation calls for a factory provider.


Let's illustrate, we want to implement a logic like that if user is authenticated, superLogService should be injected into our components, otherwise, logSerivce should be used.

Assume that we have userService which provide information about authentication. We re-write declaration for providers as below.


{{factoryProvider.sourceCode.name}}full code

The deps property is an array of provider tokens which our factory requires for injection.


Optional dependencies

As you know, if Angular can't resolve injection for component, it'll throw an exception.

In fact, there're situations, we allow the constructor's arguments to be null. We can tell Angular that the dependency is optional by annotating the constructor argument with Optional.

Of course, your code must be prepared to handle a null value.


{{optionalDependency.sourceCode.name}}full code

Dependency visibility

Well, as we learned, we can use the providers property to define providers for its injector.

However, it turns out that there’s another property viewProviders that basically allows us to do the same thing. What’s the difference between those two them ?


viewProviders allows us to define injector providers that are only available for a component’s view.

Let’s take a closer look at what that means by using our TodosComponent example.


{{dependencyVisibility.sourceCode.name}}full code

As you can see, todoTitleComponent is contentChild of TodoListComponent, todoItemComponent is viewChild of TodoListComponent.

Both todoTitleComponent & todoItemComponent require an instance of the class which is provided via logSerivce token.

How should we do if we expect that todoTitleComponent require logSerivce's instance, todoItemComponent require superLogService's instance ?


With viewProviders we can tell the DI system very specifically, which providers are available to which child injectors.

To make our code work as expected, all we have to do is to make the supperLogService provider of todoListComponent explicitly available only for its viewChild by using viewProviders instead of providers.



Now, whenever a component of todoListComponent's view asks for something of type logSerivce, it’ll get an instance of superLogService as expected.

Other child components from the outside world(contentChild) that ask for the same type, however, they won’t see this provider and will continue with the lookup in the injector tree.

Which means todoTitleComponent now gets an expected instance from another parent injector without even knowing that todoListComponent actually introduces its own provider.


Note that, viewProviders are also only available in components, not in directives. That’s simply because a directive doesn’t have its own view.


Restricting dependency lookup

We'll go on with the example in Dependency visibility subject.

Now, look back again, in the example, todoItemComponent requires logSerivce, follow DI rules, it will receice superLogService which is provided by todoListComponent.

This's so cool, however this can be problematic. Just imagine someone uses our todoItemComponent with their customTodoListComponent which doesn't provide superLogService.

What will happen ? our todoItemComponent will receice logSerivce's instance from another parent injector instead. It's unexpected.


If we need to ensure that superLogService instance is always instatiated by our component’s host or an exception should be thrown. Host dependency is a solution for us.


{{hostDependency.sourceCode.name}}full code

", host: { '[class.xblog-article-1474380939]': 'true' } @@ -17,13 +16,11 @@ export var article1474380939Component = Component({ .Class({ constructor: [ DomSanitizer, - cmsArticleService, xblogTableContentService, - function (sanitizer, articleService, tableContentService){ + function (sanitizer, tableContentService){ this.id = 1474380939; this.sanitizer = sanitizer; - this.articleService = articleService; this.tableContentService = tableContentService; } ], @@ -44,11 +41,11 @@ export var article1474380939Component = Component({ this.simpleDI = { sourceCode: { - name: 'simple-di', + name: 'Simple DI', link: resourceUtils.getGithubArticleFileLink(this.id, 'simple-di') }, codeBlocks: { - 1: this.getCodeBlock('simple-di.html') + 1: this.getCodeBlock(getSimpleDI) }, screenCaptures: { 1: resourceUtils.getImg('simpleDI-example-1474380939.png') @@ -57,13 +54,13 @@ export var article1474380939Component = Component({ this.classProvider = { sourceCode: { - name: 'class-provider', + name: 'Class provider', link: resourceUtils.getGithubArticleFileLink(this.id, 'class-provider') }, codeBlocks: { - 1: this.getCodeBlock('class-provider-1.html'), - 2: this.getCodeBlock('class-provider-2.html'), - 3: this.getCodeBlock('class-provider-3.html') + 1: this.getCodeBlock(getClassProvider01), + 2: this.getCodeBlock(getClassProvider02), + 3: this.getCodeBlock(getClassProvider03) }, screenCaptures: { 1: resourceUtils.getImg('classProvider-example-1474380939.png') @@ -72,52 +69,52 @@ export var article1474380939Component = Component({ this.valueProvider = { sourceCode: { - name: 'value-provider', + name: 'Value provider', link: resourceUtils.getGithubArticleFileLink(this.id, 'value-provider') }, codeBlocks: { - 1: this.getCodeBlock('value-provider-1.html'), - 2: this.getCodeBlock('value-provider-2.html') + 1: this.getCodeBlock(getValueProvider01), + 2: this.getCodeBlock(getValueProvider02) } }; this.factoryProvider = { sourceCode: { - name: 'factory-provider', + name: 'Factory provider', link: resourceUtils.getGithubArticleFileLink(this.id, 'factory-provider') }, codeBlocks: { - 1: this.getCodeBlock('factory-provider.html') + 1: this.getCodeBlock(getFactoryProvider) } }; this.optionalDependency = { sourceCode: { - name: 'optional-dependency', + name: 'Optional dependency', link: resourceUtils.getGithubArticleFileLink(this.id, 'optional-dependency') }, codeBlocks: { - 1: this.getCodeBlock('optional-dependency.html') + 1: this.getCodeBlock(getOptionalDependency) } }; this.hostDependency = { sourceCode: { - name: 'host-dependency', + name: 'Host dependency', link: resourceUtils.getGithubArticleFileLink(this.id, 'host-dependency') }, codeBlocks: { - 1: this.getCodeBlock('host-dependency.html') + 1: this.getCodeBlock(getHostDependency) } }; this.dependencyVisibility = { sourceCode: { - name: 'dependency-visibility', + name: 'Dependency visibility', link: resourceUtils.getGithubArticleFileLink(this.id, 'dependency-visibility') }, codeBlocks: { - 1: this.getCodeBlock('dependency-visibility.html') + 1: this.getCodeBlock(getDependencyVisibility) }, screenCaptures: { 1: resourceUtils.getImg('dependencyVisibility-example-1474380939.png') @@ -125,12 +122,327 @@ export var article1474380939Component = Component({ }; }, - getCodeBlock: function(fileName, lang) { + getCodeBlock: function(getter, lang) { var _langs = lang ? [ lang ] : ['javascript', 'html', 'css']; - var _codeBlock = this.articleService.getCodeBlock(this.id, fileName); - _codeBlock = highlight.highlightAuto(_codeBlock, _langs).value; + var _codeBlock = highlight.highlightAuto(getter().replace('\n', '').replace(/^ /gm, ''), _langs).value; return this.sanitizer.bypassSecurityTrustHtml(_codeBlock); } }); + +function getSimpleDI(){ + return ` + import * as ngCore from '@angular/core'; + + export var logService = ngCore.Class({ + constructor: function(){ + this.name = 'logService'; + }, + + setName: function(name){ + this.name = name; + } + }); + + /*---------------------------------------------------------*/ + + export var todoItemComponent = ngCore.Component({ + ..... + providers: [ logService ] + }) + .Class({ + constructor: [logService, function(logService){ + console.log('todoItemComponent', logService.name); + }] + }); + + /*---------------------------------------------------------*/ + + export var todoListComponent = ngCore.Component({ + ..... + directives: [ todoItemComponent ] + }) + .Class({ + constructor: [logService, function(logService){ + console.log('todoListComponent', logService.name); + }] + }); + + /*---------------------------------------------------------*/ + + export var todosComponent = ngCore.Component({ + ..... + providers: [ logService ], + directives: [ todoListComponent, todoItemComponent ] + }) + .Class({ + constructor: [logService, function(logService){ + logService.setName('logService is hosted by todosComponent'); + }] + });`; +} + +function getClassProvider01(){ + return ` + ngCore.Component({ + ..... + providers: [{ provide: logSerivce, useClass: logSerivce }] + }) + .Class(.....);`; +} + +function getClassProvider02(){ + return ` + export var todoListComponent = ngCore.Component({ + ..... + providers: [ + { provide: logService, useClass: supperLogService } + ] + }) + .Class(.....);`; +} + +function getClassProvider03(){ + return ` + import * as ngCore from '@angular/core'; + + export var rootLogService = ngCore.Class({ + constructor: function(){} + }); + + /*---------------------------------------------------------*/ + + export var supperLogService = ngCore.Class({ + constructor: function(){ + this.name = 'supperLogService'; + } + }); + + /*---------------------------------------------------------*/ + + export var todoItemComponent = ngCore.Component({ + ..... + }) + .Class({ + constructor: [rootLogService, function(logService){ + console.log('todoItemComponent', logService.name); + }] + }); + + /*---------------------------------------------------------*/ + + export var todoListComponent = ngCore.Component({ + ..... + directives: [ todoItemComponent ], + providers: [ + { provide: logService, useClass: supperLogService } + ] + }) + .Class({ + constructor: [logService, function(logService){ + console.log('todoListComponent', logService.name + ' is hosted by todoListComponent'); + }] + }); + + /*---------------------------------------------------------*/ + + export var todosComponent = ngCore.Component({ + ..... + directives: [ todoListComponent, todoItemComponent ], + providers: [ + logService, + { provide: rootLogService, useExisting: logService } + ] + }) + .Class({ + constructor: [logService, function(logService){ + logService.setName('logService is hosted by todosComponent'); + }] + });`; +} + +function getValueProvider01(){ + return ` + export var supperLogService = { + name: 'supperLogService' + }; + + /*---------------------------------------------------------*/ + + export var todoListComponent = ngCore.Component({ + ..... + providers: [ + { provide: logService, useValue: supperLogService } + ] + }) + .Class(.....);`; +} + +function getValueProvider02(){ + return ` + import { OpaqueToken } from '@angular/core'; + + export var WINDOW = new OpaqueToken('window'); + + export var WINDOW_PROVIDERS = [ + { provide: WINDOW, useValue: window } + ]; + + /*---------------------------------------------------------*/ + + import { WINDOW } from './window.model'; + + export var logService = ngCore.Class({ + constructor: [ + ngCore.Inject(WINDOW), + + function(window){ + this.window = window; + } + ], + + log: function(text){ + this.window.console.log(text); + } + }); + + /*---------------------------------------------------------*/ + + import { WINDOW_PROVIDERS } from './window.model'; + + export var todosComponent = ngCore.Component({ + ..... + providers: [ + logService, + WINDOW_PROVIDERS + ] + }) + .Class({ + constructor: [logService, function(logService){ + logService.log('This message is logged by using window.console via DI'); + }] + });`; +} + +function getFactoryProvider(){ + return ` + export var userService = ngCore.Class({ + ..... + setAuth: function(isAuth){ + this.isAuth = isAuth; + } + }); + + /*---------------------------------------------------------*/ + + export var todoListComponent = ngCore.Component({ + ..... + providers: [ + { + provide: logService, + useFactory: function(userService){ + return userService.isAuth ? new supperLogService() : new logService(); + }, + deps: [userService] + } + ] + }) + .Class({ + constructor: [logService, function(logService){ + console.log('todoListComponent', logService.name); + }] + }); + + /*---------------------------------------------------------*/ + + export var todosComponent = ngCore.Component({ + ..... + providers: [ userService ] + }) + .Class({ + constructor: [userService, function(userService){ + this.userService.setAuth(true); + }] + });`; +} + +function getOptionalDependency(){ + return ` + export var todoListComponent = ngCore.Component({.....}) + .Class({ + constructor: [ + [ new ngCore.Optional(), ngCore.Inject(logService) ], + + function(logService){ + if(!logService) { + console.log('todoListComponent', 'logService is null'); + } + } + ] + });`; +} + +function getHostDependency(){ + return ` + export var todoItemComponent = ngCore.Component({.....}) + .Class({ + constructor: [ + [ new ngCore.Host(), ngCore.Inject(logService) ], + + function(logService){ + console.log('todoItemComponent', logService.name); + } + ] + });`; +} + +function getDependencyVisibility(){ + return ` + export var todoTitleComponent = ngCore.Component({.....}) + .Class({ + constructor: [logService, function(logService){ + console.log('todoTitleComponent', logService.name); + }] + }); + + /*---------------------------------------------------------*/ + + export var todoItemComponent = ngCore.Component({.....}) + .Class({ + constructor: [logService, function(logService){ + console.log('todoItemComponent', logService.name); + }] + }); + + /*---------------------------------------------------------*/ + + export var todoListComponent = ngCore.Component({ + ..... + template: [ + '', + '' + ].join(''), + viewProviders: [ + { provide: logService, useClass: supperLogService } + ] + }) + .Class({ + constructor: [logService, function(logService){}] + }); + + /*---------------------------------------------------------*/ + + export var todosComponent = ngCore.Component({ + ..... + template: [ + '', + '', + '' + ].join(''), + providers: [ logService ] + }) + .Class({ + constructor: [logService, function(logService){}] + });`; +} \ No newline at end of file diff --git a/cms/articles/1474380939/code-blocks/class-provider-1.html b/cms/articles/1474380939/code-blocks/class-provider-1.html deleted file mode 100644 index 05b98d3..0000000 --- a/cms/articles/1474380939/code-blocks/class-provider-1.html +++ /dev/null @@ -1,5 +0,0 @@ -ngCore.Component({ - ..... - providers: [{ provide: logSerivce, useClass: logSerivce }] -}) -.Class(.....); \ No newline at end of file diff --git a/cms/articles/1474380939/code-blocks/class-provider-2.html b/cms/articles/1474380939/code-blocks/class-provider-2.html deleted file mode 100644 index 880663b..0000000 --- a/cms/articles/1474380939/code-blocks/class-provider-2.html +++ /dev/null @@ -1,7 +0,0 @@ -export var todoListComponent = ngCore.Component({ - ..... - providers: [ - { provide: logService, useClass: supperLogService } - ] -}) -.Class(.....); \ No newline at end of file diff --git a/cms/articles/1474380939/code-blocks/class-provider-3.html b/cms/articles/1474380939/code-blocks/class-provider-3.html deleted file mode 100644 index de5fdf3..0000000 --- a/cms/articles/1474380939/code-blocks/class-provider-3.html +++ /dev/null @@ -1,55 +0,0 @@ -import * as ngCore from '@angular/core'; - -export var rootLogService = ngCore.Class({ - constructor: function(){} -}); - -/*---------------------------------------------------------*/ - -export var supperLogService = ngCore.Class({ - constructor: function(){ - this.name = 'supperLogService'; - } -}); - -/*---------------------------------------------------------*/ - -export var todoItemComponent = ngCore.Component({ - ..... -}) -.Class({ - constructor: [rootLogService, function(logService){ - console.log('todoItemComponent', logService.name); - }] -}); - -/*---------------------------------------------------------*/ - -export var todoListComponent = ngCore.Component({ - ..... - directives: [ todoItemComponent ], - providers: [ - { provide: logService, useClass: supperLogService } - ] -}) -.Class({ - constructor: [logService, function(logService){ - console.log('todoListComponent', logService.name + ' is hosted by todoListComponent'); - }] -}); - -/*---------------------------------------------------------*/ - -export var todosComponent = ngCore.Component({ - ..... - directives: [ todoListComponent, todoItemComponent ], - providers: [ - logService, - { provide: rootLogService, useExisting: logService } - ] -}) -.Class({ - constructor: [logService, function(logService){ - logService.setName('logService is hosted by todosComponent'); - }] -}); diff --git a/cms/articles/1474380939/code-blocks/dependency-visibility.html b/cms/articles/1474380939/code-blocks/dependency-visibility.html deleted file mode 100644 index dde2aa8..0000000 --- a/cms/articles/1474380939/code-blocks/dependency-visibility.html +++ /dev/null @@ -1,46 +0,0 @@ -export var todoTitleComponent = ngCore.Component({.....}) -.Class({ - constructor: [logService, function(logService){ - console.log('todoTitleComponent', logService.name); - }] -}); - -/*---------------------------------------------------------*/ - -export var todoItemComponent = ngCore.Component({.....}) -.Class({ - constructor: [logService, function(logService){ - console.log('todoItemComponent', logService.name); - }] -}); - -/*---------------------------------------------------------*/ - -export var todoListComponent = ngCore.Component({ - ..... - template: [ - '', - '' - ].join(''), - viewProviders: [ - { provide: logService, useClass: supperLogService } - ] -}) -.Class({ - constructor: [logService, function(logService){}] -}); - -/*---------------------------------------------------------*/ - -export var todosComponent = ngCore.Component({ - ..... - template: [ - '', - '', - '' - ].join(''), - providers: [ logService ] -}) -.Class({ - constructor: [logService, function(logService){}] -}); \ No newline at end of file diff --git a/cms/articles/1474380939/code-blocks/factory-provider.html b/cms/articles/1474380939/code-blocks/factory-provider.html deleted file mode 100644 index 9246a5b..0000000 --- a/cms/articles/1474380939/code-blocks/factory-provider.html +++ /dev/null @@ -1,38 +0,0 @@ -export var userService = ngCore.Class({ - ..... - setAuth: function(isAuth){ - this.isAuth = isAuth; - } -}); - -/*---------------------------------------------------------*/ - -export var todoListComponent = ngCore.Component({ - ..... - providers: [ - { - provide: logService, - useFactory: function(userService){ - return userService.isAuth ? new supperLogService() : new logService(); - }, - deps: [userService] - } - ] -}) -.Class({ - constructor: [logService, function(logService){ - console.log('todoListComponent', logService.name); - }] -}); - -/*---------------------------------------------------------*/ - -export var todosComponent = ngCore.Component({ - ..... - providers: [ userService ] -}) -.Class({ - constructor: [userService, function(userService){ - this.userService.setAuth(true); - }] -}); \ No newline at end of file diff --git a/cms/articles/1474380939/code-blocks/host-dependency.html b/cms/articles/1474380939/code-blocks/host-dependency.html deleted file mode 100644 index b07941a..0000000 --- a/cms/articles/1474380939/code-blocks/host-dependency.html +++ /dev/null @@ -1,10 +0,0 @@ -export var todoItemComponent = ngCore.Component({.....}) -.Class({ - constructor: [ - [ new ngCore.Host(), ngCore.Inject(logService) ], - - function(logService){ - console.log('todoItemComponent', logService.name); - } - ] -}); \ No newline at end of file diff --git a/cms/articles/1474380939/code-blocks/optional-dependency.html b/cms/articles/1474380939/code-blocks/optional-dependency.html deleted file mode 100644 index 5f13223..0000000 --- a/cms/articles/1474380939/code-blocks/optional-dependency.html +++ /dev/null @@ -1,12 +0,0 @@ -export var todoListComponent = ngCore.Component({.....}) -.Class({ - constructor: [ - [ new ngCore.Optional(), ngCore.Inject(logService) ], - - function(logService){ - if(!logService) { - console.log('todoListComponent', 'logService is null'); - } - } - ] -}); \ No newline at end of file diff --git a/cms/articles/1474380939/code-blocks/simple-di.html b/cms/articles/1474380939/code-blocks/simple-di.html deleted file mode 100644 index d1e1dc8..0000000 --- a/cms/articles/1474380939/code-blocks/simple-di.html +++ /dev/null @@ -1,48 +0,0 @@ -import * as ngCore from '@angular/core'; - -export var logService = ngCore.Class({ - constructor: function(){ - this.name = 'logService'; - }, - - setName: function(name){ - this.name = name; - } -}); - -/*---------------------------------------------------------*/ - -export var todoItemComponent = ngCore.Component({ - ..... - providers: [ logService ] -}) -.Class({ - constructor: [logService, function(logService){ - console.log('todoItemComponent', logService.name); - }] -}); - -/*---------------------------------------------------------*/ - -export var todoListComponent = ngCore.Component({ - ..... - directives: [ todoItemComponent ] -}) -.Class({ - constructor: [logService, function(logService){ - console.log('todoListComponent', logService.name); - }] -}); - -/*---------------------------------------------------------*/ - -export var todosComponent = ngCore.Component({ - ..... - providers: [ logService ], - directives: [ todoListComponent, todoItemComponent ] -}) -.Class({ - constructor: [logService, function(logService){ - logService.setName('logService is hosted by todosComponent'); - }] -}); diff --git a/cms/articles/1474380939/code-blocks/value-provider-1.html b/cms/articles/1474380939/code-blocks/value-provider-1.html deleted file mode 100644 index a7403ce..0000000 --- a/cms/articles/1474380939/code-blocks/value-provider-1.html +++ /dev/null @@ -1,13 +0,0 @@ -export var supperLogService = { - name: 'supperLogService' -}; - -/*---------------------------------------------------------*/ - -export var todoListComponent = ngCore.Component({ - ..... - providers: [ - { provide: logService, useValue: supperLogService } - ] -}) -.Class(.....); \ No newline at end of file diff --git a/cms/articles/1474380939/code-blocks/value-provider-2.html b/cms/articles/1474380939/code-blocks/value-provider-2.html deleted file mode 100644 index b28ff45..0000000 --- a/cms/articles/1474380939/code-blocks/value-provider-2.html +++ /dev/null @@ -1,43 +0,0 @@ -import { OpaqueToken } from '@angular/core'; - -export var WINDOW = new OpaqueToken('window'); - -export var WINDOW_PROVIDERS = [ - { provide: WINDOW, useValue: window } -]; - -/*---------------------------------------------------------*/ - -import { WINDOW } from './window.model'; - -export var logService = ngCore.Class({ - constructor: [ - ngCore.Inject(WINDOW), - - function(window){ - this.window = window; - } - ], - - log: function(text){ - this.window.console.log(text); - } -}); - -/*---------------------------------------------------------*/ - -import { WINDOW_PROVIDERS } from './window.model'; - -export var todosComponent = ngCore.Component({ - ..... - providers: [ - logService, - WINDOW_PROVIDERS - ] -}) -.Class({ - constructor: [logService, function(logService){ - logService.log('This message is logged by using window.console via DI'); - }] -}); - diff --git a/cms/articles/1474380939/index.js b/cms/articles/1474380939/index.js index 17767a6..8bf664b 100644 --- a/cms/articles/1474380939/index.js +++ b/cms/articles/1474380939/index.js @@ -3,11 +3,11 @@ import { article1474380939Component } from './article-1474380939.component'; export var article1474380939 = { id: 1474380939, - title: 'Dependency Injection', + title: 'Dependency Injection In Angular 2', postedDate: 'Tue Sep 20 2016 21:15:38 GMT+0700 (SE Asia Standard Time)', author: 'Minh Van', cover: resourceUtils.getImg('xblog-home-cover.jpg'), - routeLink: resourceUtils.getArticleRouteLink('dependency-injection-1474380939.html'), + routeLink: resourceUtils.getArticleRouteLink('dependency-injection-in-angular-2-1474380939.html'), relatedArticles: [], tags: [], description: 'An Angular application is a tree of components. Each component instance has its own injector! The tree of components parallels the tree of injectors. We can re-configure the injectors at any level of that component tree with interesting and useful results', diff --git a/cms/articles/1474380939/templates/article-1474380939.html b/cms/articles/1474380939/templates/article-1474380939.html index 12aa94a..403262f 100644 --- a/cms/articles/1474380939/templates/article-1474380939.html +++ b/cms/articles/1474380939/templates/article-1474380939.html @@ -8,7 +8,7 @@
Table of Contents

An Angular application is a tree of components. Each component instance has its own injector. The tree of components parallels the tree of injectors.

We can re-configure the injectors at any level of that component tree with interesting and useful results.


-

Consider a simple example about TodosComponent

+

Consider a simple example about TodosComponent.


{{simpleDI.sourceCode.name}} @@ -35,7 +35,7 @@

Injector providers

The injector relies on providers to create instances of the services that the injector injects into components and other services.


As you know, we can register service provider or directive provider by using providers & directives in component's declaration.

-

Look back our example, you can see the way we registered logSerivce in TodosComponent

+

Look back our example, you can see the way we registered logSerivce in TodosComponent.


But there are many ways that we can configure the injector with alternative providers that can deliver an object that behaves like logSerivce. We'll expore them now.


@@ -59,7 +59,7 @@

Class Provider



-

However, lets look back the example that you registered logService in todosComponent then you used useClass to register superLogService in todoListComponent

+

However, lets look back the example that you registered logService in todosComponent then you used useClass to register superLogService in todoListComponent.

So how can todoItemComponent inject logService from todoComponent instead of superLogService from todoListComponent ?


The solution for this case is you should use useExisting with rootLogService token for register in todosComponent.

@@ -83,7 +83,7 @@

Value Provider



Now, you have seen I used a class as the token such as logService, rootLogService for register, acttualy, there's another way for you to get the same result.

-

The way I'm mentioning is using OpaqueToken & ngCore.Inject

+

The way I'm mentioning is using OpaqueToken & ngCore.Inject.


{{valueProvider.sourceCode.name}} @@ -111,7 +111,7 @@

Factory provider


Optional dependencies

As you know, if Angular can't resolve injection for component, it'll throw an exception.

-

In fact, there're situations, we allow the constructor's arguments to be null. We can tell Angular that the dependency is optional by annotating the constructor argument with Optional

+

In fact, there're situations, we allow the constructor's arguments to be null. We can tell Angular that the dependency is optional by annotating the constructor argument with Optional.

Of course, your code must be prepared to handle a null value.


@@ -136,11 +136,11 @@

Dependency visibility


As you can see, todoTitleComponent is contentChild of TodoListComponent, todoItemComponent is viewChild of TodoListComponent.

-

Both todoTitleComponent & todoItemComponent require an instance of the class which is provided via logSerivce token

+

Both todoTitleComponent & todoItemComponent require an instance of the class which is provided via logSerivce token.

How should we do if we expect that todoTitleComponent require logSerivce's instance, todoItemComponent require superLogService's instance ?


With viewProviders we can tell the DI system very specifically, which providers are available to which child injectors.

-

To make our code work as expected, all we have to do is to make the supperLogService provider of todoListComponent explicitly available only for its viewChild by using viewProviders instead of providers

+

To make our code work as expected, all we have to do is to make the supperLogService provider of todoListComponent explicitly available only for its viewChild by using viewProviders instead of providers.



@@ -153,7 +153,7 @@

Dependency visibility

Restricting dependency lookup

We'll go on with the example in Dependency visibility subject.

Now, look back again, in the example, todoItemComponent requires logSerivce, follow DI rules, it will receice superLogService which is provided by todoListComponent.

-

This's so cool, however this can be problematic. Just imagine someone uses our todoItemComponent with their customTodoListComponent which doesn't provide superLogService

+

This's so cool, however this can be problematic. Just imagine someone uses our todoItemComponent with their customTodoListComponent which doesn't provide superLogService.

What will happen ? our todoItemComponent will receice logSerivce's instance from another parent injector instead. It's unexpected.


If we need to ensure that superLogService instance is always instatiated by our component’s host or an exception should be thrown. Host dependency is a solution for us.

@@ -163,4 +163,5 @@

Restricting depen full code +

\ No newline at end of file