diff --git a/README.md b/README.md index 7c067d5..1dc704b 100644 --- a/README.md +++ b/README.md @@ -1,27 +1,34 @@ -# DynamicTabs +# Egghead Course: Create a Dynamic Tabs Component with Angular -This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 1.5.0. +by Juri Strumpflohner ([Twitter](https://twitter.com/juristr) - [Blog](https://juristr.com/blog)) -## Development server +This repository is organized in different branches, one branch for each video lesson. -Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files. +## Contents -## Code scaffolding +1. [Get to know our basic Angular TabsComponent](https://github.com/juristr/egghead-create-dynamic-tabs-component-angular/tree/master) +1. [Declare a template within a template using `ng-template` in Angular](https://github.com/juristr/egghead-create-dynamic-tabs-component-angular/tree/01-ng-template) +1. [Pass a reference of an ng-template to a component and render it in Angular](https://github.com/juristr/egghead-create-dynamic-tabs-component-angular/tree/02-ng-container-and-template-outlet) +1. [Pass data to be rendered in a dynamic ng-template using ngTemplateOutletContext in Angular](https://github.com/juristr/egghead-create-dynamic-tabs-component-angular/tree/03-ng-outlet-context) +1. Define an anchor point where to render dynamic components in Angular +1. [Dynamically instantiate an Angular component](https://github.com/juristr/egghead-create-dynamic-tabs-component-angular/tree/05-dynamically-instantiate-component) +1. [Destroy a dynamically instantiated Angular component](https://github.com/juristr/egghead-create-dynamic-tabs-component-angular/tree/06-destroy-dynamic-components) -Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`. -## Build +## Setup & Run -Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `-prod` flag for a production build. +Clone the repository and install all packages -## Running unit tests +``` +$ npm install +``` -Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). +Run the project by executing -## Running end-to-end tests +``` +$ npm start +``` -Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/). +## Questions? -## Further help - -To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md). +Feel free to reach out to me [on Twitter](https://twitter.com/juristr) or [open an issue](https://github.com/juristr/egghead-create-dynamic-tabs-component-angular/issues). diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 8177f80..92eced1 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -1,5 +1,6 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, OnInit, ViewChild, AfterViewInit } from '@angular/core'; import { PeopleService } from './people/people.service'; +import { TabsComponent } from './tabs/tabs.component'; @Component({ selector: 'app-root', @@ -7,14 +8,19 @@ import { PeopleService } from './people/people.service'; <h1>Angular tabs</h1> <ngx-tabs> <ngx-tab tabTitle="People List"> - <app-people-list [people]="people"></app-people-list> + <app-people-list [people]="people" (addPerson)="onAddPerson()"></app-people-list> </ngx-tab> - <ngx-tab tabTitle="Tab 2">Tab 2 Content</ngx-tab> + <ngx-tab tabTitle="Tab 2" [template]="personEdit" [dataContext]="people[0]"></ngx-tab> </ngx-tabs> + <ng-template let-person="data" #personEdit> + Hi, I'm {{ person?.name }}. + </ng-template> ` }) -export class AppComponent implements OnInit { +export class AppComponent implements OnInit, AfterViewInit { + @ViewChild('personEdit') personEditTemplate; + @ViewChild(TabsComponent) tabsComponent; people; constructor(private peopleService: PeopleService) {} @@ -24,4 +30,12 @@ export class AppComponent implements OnInit { this.people = data; }); } + + ngAfterViewInit() { + console.log(this.personEditTemplate); + } + + onAddPerson() { + this.tabsComponent.openTab(); + } } diff --git a/src/app/tabs/dynamic-tab-anchor.directive.ts b/src/app/tabs/dynamic-tab-anchor.directive.ts new file mode 100644 index 0000000..b5eb23b --- /dev/null +++ b/src/app/tabs/dynamic-tab-anchor.directive.ts @@ -0,0 +1,8 @@ +import { Directive, ViewContainerRef } from '@angular/core'; + +@Directive({ + selector: '[appDynamicTabAnchor]' +}) +export class DynamicTabAnchorDirective { + constructor(public viewContainer: ViewContainerRef) {} +} diff --git a/src/app/tabs/tab.component.ts b/src/app/tabs/tab.component.ts index 5515e8c..426eef1 100644 --- a/src/app/tabs/tab.component.ts +++ b/src/app/tabs/tab.component.ts @@ -11,11 +11,17 @@ import { Component, Input } from '@angular/core'; ], template: ` <div [hidden]="!active" class="pane"> - <ng-content></ng-content> + <ng-content *ngIf="!template"></ng-content> + <ng-container *ngIf="template" + [ngTemplateOutlet]="template" + [ngTemplateOutletContext]="{data: dataContext}"> + </ng-container> </div> ` }) export class TabComponent { @Input() tabTitle: string; @Input() active = false; + @Input() template; + @Input() dataContext; } diff --git a/src/app/tabs/tabs.component.ts b/src/app/tabs/tabs.component.ts index 06f494e..fdf8ef2 100644 --- a/src/app/tabs/tabs.component.ts +++ b/src/app/tabs/tabs.component.ts @@ -2,10 +2,14 @@ import { Component, ContentChildren, QueryList, - AfterContentInit + AfterContentInit, + ViewChild, + ViewContainerRef } from '@angular/core'; import { TabComponent } from './tab.component'; +import { DynamicTabAnchorDirective } from './dynamic-tab-anchor.directive'; + @Component({ selector: 'ngx-tabs', template: ` @@ -15,10 +19,18 @@ import { TabComponent } from './tab.component'; </li> </ul> <ng-content></ng-content> + <ng-template appDynamicTabAnchor #container></ng-template> ` }) export class TabsComponent implements AfterContentInit { @ContentChildren(TabComponent) tabs: QueryList<TabComponent>; + @ViewChild(DynamicTabAnchorDirective) + dynamicTabPlaceholder: DynamicTabAnchorDirective; + // @ViewChild('container', { read: ViewContainerRef }) placeholder; + + openTab() { + console.log(this.dynamicTabPlaceholder.viewContainer); + } // contentChildren are set ngAfterContentInit() { diff --git a/src/app/tabs/tabs.module.ts b/src/app/tabs/tabs.module.ts index d4528ee..736ed5d 100644 --- a/src/app/tabs/tabs.module.ts +++ b/src/app/tabs/tabs.module.ts @@ -2,10 +2,11 @@ import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { TabsComponent } from './tabs.component'; import { TabComponent } from './tab.component'; +import { DynamicTabAnchorDirective } from './dynamic-tab-anchor.directive'; @NgModule({ imports: [CommonModule], - declarations: [TabsComponent, TabComponent], + declarations: [TabsComponent, TabComponent, DynamicTabAnchorDirective], exports: [TabsComponent, TabComponent] }) export class TabsModule {}