Skip to content
This repository was archived by the owner on Dec 4, 2017. It is now read-only.

Commit 969f169

Browse files
thelgevoldjuleskremer
authored andcommitted
docs(cb-dynamic-component-loading): add dynamic component loading cookbook (#2896)
s s s s s s s s s s s s s s s
1 parent f0388b5 commit 969f169

File tree

17 files changed

+392
-0
lines changed

17 files changed

+392
-0
lines changed
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
'use strict'; // necessary for es6 output in node
2+
3+
import { browser, element, by } from 'protractor';
4+
5+
/* tslint:disable:quotemark */
6+
describe('Dynamic Component Loader', function () {
7+
8+
beforeEach(function () {
9+
browser.get('');
10+
});
11+
12+
it('should load ad banner', function () {
13+
let headline = element(by.xpath("//h4[text()='Featured Hero Profile']"));
14+
let name = element(by.xpath("//h3[text()='Bombasto']"));
15+
let bio = element(by.xpath("//p[text()='Brave as they come']"));
16+
17+
expect(name).toBeDefined();
18+
expect(headline).toBeDefined();
19+
expect(bio).toBeDefined();
20+
});
21+
});
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// #docregion
2+
import { Component, Input, AfterViewInit, ViewChild, ComponentFactoryResolver, OnDestroy } from '@angular/core';
3+
4+
import { AdDirective } from './ad.directive';
5+
import { AdItem } from './ad-item';
6+
import { AdComponent } from './ad.component';
7+
8+
@Component({
9+
selector: 'add-banner',
10+
// #docregion ad-host
11+
template: `
12+
<div class="ad-banner">
13+
<h3>Advertisements</h3>
14+
<template ad-host></template>
15+
</div>
16+
`
17+
// #enddocregion ad-host
18+
})
19+
export class AdBannerComponent implements AfterViewInit, OnDestroy {
20+
@Input() ads: AdItem[];
21+
currentAddIndex: number = -1;
22+
@ViewChild(AdDirective) adHost: AdDirective;
23+
subscription: any;
24+
interval: any;
25+
26+
constructor(private _componentFactoryResolver: ComponentFactoryResolver) { }
27+
28+
ngAfterViewInit() {
29+
this.loadComponent();
30+
this.getAds();
31+
}
32+
33+
ngOnDestroy() {
34+
clearInterval(this.interval);
35+
}
36+
37+
loadComponent() {
38+
this.currentAddIndex = (this.currentAddIndex + 1) % this.ads.length;
39+
let adItem = this.ads[this.currentAddIndex];
40+
41+
let componentFactory = this._componentFactoryResolver.resolveComponentFactory(adItem.component);
42+
43+
let viewContainerRef = this.adHost.viewContainerRef;
44+
viewContainerRef.clear();
45+
46+
let componentRef = viewContainerRef.createComponent(componentFactory);
47+
(<AdComponent>componentRef.instance).data = adItem.data;
48+
}
49+
50+
getAds() {
51+
this.interval = setInterval(() => {
52+
this.loadComponent();
53+
}, 3000);
54+
}
55+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// #docregion
2+
import { Type } from '@angular/core';
3+
4+
export class AdItem {
5+
constructor(public component: Type<any>, public data: any) {}
6+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// #docregion
2+
export interface AdComponent {
3+
data: any;
4+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// #docregion
2+
import { Directive, ViewContainerRef } from '@angular/core';
3+
4+
@Directive({
5+
selector: '[ad-host]',
6+
})
7+
export class AdDirective {
8+
constructor(public viewContainerRef: ViewContainerRef) { }
9+
}
10+
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// #docregion
2+
import { Injectable } from '@angular/core';
3+
4+
import { HeroJobAdComponent } from './hero-job-ad.component';
5+
import { HeroProfileComponent } from './hero-profile.component';
6+
import { AdItem } from './ad-item';
7+
8+
@Injectable()
9+
export class AdService {
10+
getAds() {
11+
return [
12+
new AdItem(HeroProfileComponent, {name: 'Bombasto', bio: 'Brave as they come'}),
13+
14+
new AdItem(HeroProfileComponent, {name: 'Dr IQ', bio: 'Smart as they come'}),
15+
16+
new AdItem(HeroJobAdComponent, {headline: 'Hiring for several positions',
17+
body: 'Submit your resume today!'}),
18+
19+
new AdItem(HeroJobAdComponent, {headline: 'Openings in all departments',
20+
body: 'Apply today'}),
21+
];
22+
}
23+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// #docregion
2+
import { Component, OnInit } from '@angular/core';
3+
4+
import { AdService } from './ad.service';
5+
import { AdItem } from './ad-item';
6+
7+
@Component({
8+
selector: 'my-app',
9+
template: `
10+
<div>
11+
<add-banner [ads]="ads"></add-banner>
12+
</div>
13+
`
14+
})
15+
export class AppComponent implements OnInit {
16+
ads: AdItem[];
17+
18+
constructor(private adService: AdService) {}
19+
20+
ngOnInit() {
21+
this.ads = this.adService.getAds();
22+
}
23+
}
24+
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// #docregion
2+
import { BrowserModule } from '@angular/platform-browser';
3+
import { NgModule } from '@angular/core';
4+
import { AppComponent } from './app.component';
5+
import { HeroJobAdComponent } from './hero-job-ad.component';
6+
import { AdBannerComponent } from './ad-banner.component';
7+
import { HeroProfileComponent } from './hero-profile.component';
8+
import { AdDirective } from './ad.directive';
9+
import { AdService } from './ad.service';
10+
11+
@NgModule({
12+
imports: [ BrowserModule ],
13+
providers: [AdService],
14+
declarations: [ AppComponent,
15+
AdBannerComponent,
16+
HeroJobAdComponent,
17+
HeroProfileComponent,
18+
AdDirective ],
19+
// #docregion entry-components
20+
entryComponents: [ HeroJobAdComponent, HeroProfileComponent ],
21+
// #enddocregion entry-components
22+
bootstrap: [ AppComponent ]
23+
})
24+
export class AppModule {
25+
constructor() {}
26+
}
27+
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// #docregion
2+
import { Component, Input } from '@angular/core';
3+
4+
import { AdComponent } from './ad.component';
5+
6+
@Component({
7+
template: `
8+
<div class="job-ad">
9+
<h4>{{data.headline}}</h4>
10+
11+
{{data.body}}
12+
</div>
13+
`
14+
})
15+
export class HeroJobAdComponent implements AdComponent {
16+
@Input() data: any;
17+
18+
}
19+
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// #docregion
2+
import { Component, Input } from '@angular/core';
3+
4+
import { AdComponent } from './ad.component';
5+
6+
@Component({
7+
template: `
8+
<div class="hero-profile">
9+
<h3>Featured Hero Profile</h3>
10+
<h4>{{data.name}}</h4>
11+
12+
<p>{{data.bio}}</p>
13+
14+
<strong>Hire this hero today!</strong>
15+
</div>
16+
`
17+
})
18+
export class HeroProfileComponent implements AdComponent {
19+
@Input() data: any;
20+
}
21+
22+
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// #docregion
2+
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
3+
import { AppModule } from './app.module';
4+
5+
platformBrowserDynamic().bootstrapModule(AppModule);
6+

public/docs/_examples/cb-dynamic-component-loader/ts/example-config.json

Whitespace-only changes.
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta charset="UTF-8">
5+
<base href="/">
6+
<title>Dynamic Component Loader</title>
7+
<meta name="viewport" content="width=device-width, initial-scale=1">
8+
<link rel="stylesheet" href="styles.css">
9+
<link rel="stylesheet" href="sample.css">
10+
11+
<script src="node_modules/core-js/client/shim.min.js"></script>
12+
13+
<script src="node_modules/zone.js/dist/zone.js"></script>
14+
<script src="node_modules/reflect-metadata/Reflect.js"></script>
15+
<script src="node_modules/systemjs/dist/system.src.js"></script>
16+
17+
<script src="systemjs.config.js"></script>
18+
<script>
19+
System.import('app').catch(function(err){ console.error(err); });
20+
</script>
21+
</head>
22+
<body>
23+
<my-app>Loading app...</my-app>
24+
</body>
25+
26+
</html>
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
.hero-profile {
2+
border: 1px solid gray;
3+
padding: 5px;
4+
padding-bottom: 20px;
5+
padding-left: 20px;
6+
border-radius: 10px;
7+
background-color: lightgreen;
8+
color: black;
9+
}
10+
11+
.job-ad {
12+
border: 1px solid gray;
13+
padding: 5px;
14+
padding-bottom: 20px;
15+
padding-left: 20px;
16+
border-radius: 10px;
17+
background-color: lightblue;
18+
color: black;
19+
}
20+
21+
.ad-banner {
22+
width: 400px;
23+
}

public/docs/ts/latest/cookbook/_data.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,11 @@
3636
"intro": "Techniques for Dependency Injection"
3737
},
3838

39+
"dynamic-component-loader": {
40+
"title": "Dynamic Component Loader",
41+
"intro": "Load components dynamically"
42+
},
43+
3944
"dynamic-form": {
4045
"title": "Dynamic Forms",
4146
"intro": "Render dynamic forms with FormGroup"

0 commit comments

Comments
 (0)