Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit d58cafc

Browse filesBrowse files
committed
Add recursive ng-template example in Angular 6.1.10.
1 parent a990de6 commit d58cafc
Copy full SHA for d58cafc
Expand file treeCollapse file tree

20 files changed

+9571
-0
lines changed
Open diff view settings
Collapse file
+4Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
2+
# Now that we're using Webpack, we can install modules locally and just ignore
3+
# them since the assets are baked into the compiled modules.
4+
node_modules/
Collapse file
+43Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
2+
<!-- Define the recursive template. -->
3+
<ng-template #nodeTemplateRef let-node="node">
4+
5+
<div class="node" [class.node--selected]="( node === selectedTreeNode )">
6+
7+
<a (click)="selectNode( node )" class="node__label">
8+
{{ node.label }}
9+
</a>
10+
11+
<div *ngIf="node.children.length" class="node__children">
12+
13+
<ng-template ngFor let-child [ngForOf]="node.children">
14+
15+
<!-- Invoke the recursive template. -->
16+
<ng-template
17+
[ngTemplateOutlet]="nodeTemplateRef"
18+
[ngTemplateOutletContext]="{ node: child }">
19+
<!--
20+
Because we are using nested ngTemplates (rather than the template
21+
input of the ngFor directive), we have more control over how the
22+
data is made available to the recursive template. In this case,
23+
we're passing "child" through as "node".
24+
-->
25+
</ng-template>
26+
27+
</ng-template>
28+
29+
</div>
30+
31+
</div>
32+
33+
</ng-template>
34+
35+
<!-- Initiate the recursive template rendering. -->
36+
<ng-template
37+
[ngTemplateOutlet]="nodeTemplateRef"
38+
[ngTemplateOutletContext]="{ node: data.root }">
39+
</ng-template>
40+
41+
<p class="note">
42+
<em>(alternative) Ng-Template Template Rendering</em>
43+
</p>
Collapse file
+46Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
2+
<!-- Define the recursive template. -->
3+
<ng-template #nodeTemplateRef let-node>
4+
5+
<div class="node" [class.node--selected]="( node === selectedTreeNode )">
6+
7+
<a (click)="selectNode( node )" class="node__label">
8+
{{ node.label }}
9+
</a>
10+
11+
<div *ngIf="node.children.length" class="node__children">
12+
13+
<!-- Invoke the recursive template. -->
14+
<ng-template
15+
ngFor
16+
[ngForOf]="node.children"
17+
[ngForTemplate]="nodeTemplateRef">
18+
<!--
19+
NOTE: The "$implicit" property of the ngFor context is what will
20+
be made available to the template ref's implicit let-node binding.
21+
-->
22+
</ng-template>
23+
24+
</div>
25+
26+
</div>
27+
28+
</ng-template>
29+
30+
<!--
31+
Initiate the recursive template rendering. Because our recursive template is going to
32+
be using the ngFor directive to render recursively, the "context" in the recursive
33+
instances is going to be the ngForContext. As such, we have to "mock" the initial
34+
context to look like the context that the ngFor directive will expose internally.
35+
36+
NOTE: If we used ngContainer or ngTemplate to invoke the recursion internally, we'd
37+
have more control over which values were made available at each level.
38+
-->
39+
<ng-template
40+
[ngTemplateOutlet]="nodeTemplateRef"
41+
[ngTemplateOutletContext]="{ $implicit: data.root }">
42+
</ng-template>
43+
44+
<p class="note">
45+
<em>Ng-For Template Rendering</em>
46+
</p>
Collapse file
+35Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
2+
:host {
3+
display: block ;
4+
font-size: 18px ;
5+
}
6+
7+
.node {
8+
&__label {
9+
color: red ;
10+
cursor: pointer ;
11+
text-decoration: underline ;
12+
}
13+
14+
&__children {
15+
border-left: 3px solid #CCCCCC ;
16+
margin: 5px 0px 5px 30px ;
17+
padding-left: 10px ;
18+
}
19+
20+
&--selected {
21+
> .node {
22+
&__label {
23+
background-color: red ;
24+
color: white ;
25+
font-weight: bold ;
26+
}
27+
}
28+
}
29+
}
30+
31+
.note {
32+
color: #999999 ;
33+
font-size: 15px ;
34+
font-style: italic ;
35+
}
Collapse file
+85Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
2+
// Import the core angular services.
3+
import { Component } from "@angular/core";
4+
5+
// ----------------------------------------------------------------------------------- //
6+
// ----------------------------------------------------------------------------------- //
7+
8+
interface Tree {
9+
root: TreeNode;
10+
}
11+
12+
interface TreeNode {
13+
label: string;
14+
children: TreeNode[];
15+
}
16+
17+
@Component({
18+
selector: "my-app",
19+
styleUrls: [ "./app.component.less" ],
20+
templateUrl: "./app.component.htm"
21+
})
22+
export class AppComponent {
23+
24+
public data: Tree;
25+
public selectedTreeNode: TreeNode | null;
26+
27+
// I initialize the app component.
28+
constructor() {
29+
30+
this.selectedTreeNode = null;
31+
this.data = {
32+
root: {
33+
label: "first",
34+
children: [
35+
{
36+
label: "second-a",
37+
children: [
38+
{
39+
label: "third-first",
40+
children: [
41+
{
42+
label: "ferth",
43+
children: [
44+
{
45+
label: "fiver",
46+
children: []
47+
}
48+
]
49+
}
50+
]
51+
}
52+
]
53+
},
54+
{
55+
label: "second-b",
56+
children: [
57+
{
58+
label: "third",
59+
children: []
60+
}
61+
]
62+
}
63+
]
64+
}
65+
}
66+
67+
}
68+
69+
// ---
70+
// PUBLIC METHODS.
71+
// ---
72+
73+
// I select the given tree node, and log it to the console.
74+
public selectNode( node: TreeNode ) : void {
75+
76+
this.selectedTreeNode = node;
77+
78+
console.group( "Selected Tree Node" );
79+
console.log( "Label:", node.label );
80+
console.log( "Children:", node.children.length );
81+
console.groupEnd();
82+
83+
}
84+
85+
}
Collapse file
+25Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
2+
// Import the core angular services.
3+
import { BrowserModule } from "@angular/platform-browser";
4+
import { NgModule } from "@angular/core";
5+
6+
// Import the application components and services.
7+
import { AppComponent } from "./app.component";
8+
9+
// ----------------------------------------------------------------------------------- //
10+
// ----------------------------------------------------------------------------------- //
11+
12+
@NgModule({
13+
imports: [
14+
BrowserModule
15+
],
16+
declarations: [
17+
AppComponent
18+
],
19+
bootstrap: [
20+
AppComponent
21+
]
22+
})
23+
export class AppModule {
24+
// ...
25+
}
Collapse file
+36Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8" />
5+
6+
<title>
7+
Playing With Recursive Ng-Template References In Angular 6.1.10
8+
</title>
9+
</head>
10+
<body>
11+
12+
<h1>
13+
Playing With Recursive Ng-Template References In Angular 6.1.10
14+
</h1>
15+
16+
<my-app>
17+
<p>
18+
<em>Loading files...</em>
19+
</p>
20+
21+
<p>
22+
npm Run Scripts:
23+
</p>
24+
25+
<ul>
26+
<li>
27+
<strong>npm run build</strong> &mdash; Compiles the .ts file into bundles.
28+
</li>
29+
<li>
30+
<strong>npm run watch</strong> &mdash; Compiles the .ts file into bundles and then watches files for changes.
31+
</li>
32+
</ul>
33+
</my-app>
34+
35+
</body>
36+
</html>
Collapse file
+4Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
2+
// Import these libraries for their side-effects.
3+
import "core-js/client/shim.min.js";
4+
import "zone.js/dist/zone.js";
Collapse file
+20Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
2+
// Import for side effects - we have to import this first so that the polyfills will
3+
// be available for the rest of the code.
4+
// --
5+
// NOTE: I would normally include this as an Entry bundle; but, I couldn't get the
6+
// HtmlWebpackPlugin to work properly if I did that (since I don't think it could
7+
// implicitly determine the dependency order). In the future, I might be able to make
8+
// this more dynamic (ie, use Webpack's import() syntax).
9+
import "./main.polyfill";
10+
11+
// ----------------------------------------------------------------------------------- //
12+
// ----------------------------------------------------------------------------------- //
13+
14+
// Import the core angular services.
15+
import { platformBrowserDynamic } from "@angular/platform-browser-dynamic";
16+
17+
// Import the root module for bootstrapping.
18+
import { AppModule } from "./app.module";
19+
20+
platformBrowserDynamic().bootstrapModule( AppModule );
Collapse file

‎demos/recursive-templates-angular6/build/main.5939930d7f117f3fe9d5.js‎

Copy file name to clipboardExpand all lines: demos/recursive-templates-angular6/build/main.5939930d7f117f3fe9d5.js
+2Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.