Reputation: 570
This is start-page:
<!DOCTYPE html>
<html>
<head>
<script>document.write('<base href="/app/" />');</script>
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>App</title>
</head>
<body>
<my-app>
Loading...
</my-app>
<!-- 1. Load libraries -->
<!-- IE required polyfills, in this exact order -->
<script src="/cp/node_modules/es6-shim/es6-shim.min.js"></script>
<script src="/cp/node_modules/systemjs/dist/system-polyfills.js"></script>
<script src="/cp/node_modules/angular2/es6/dev/src/testing/shims_for_IE.js"></script>
<script src="/cp/node_modules/angular2/bundles/angular2-polyfills.js"></script>
<script src="/cp/node_modules/systemjs/dist/system.src.js"></script>
<script src="/cp/node_modules/rxjs/bundles/Rx.js"></script>
<script src="/cp/node_modules/angular2/bundles/angular2.dev.js"></script>
<script src="/cp/node_modules/angular2/bundles/router.dev.js"></script>
<script src="/cp/node_modules/angular2/bundles/http.dev.js"></script>
<!-- 2. Configure SystemJS -->
<script>
System.config({
packages: {
app: {
format: 'register',
defaultExtension: 'js'
}
}
});
System.import('app/main')
.then(null, console.error.bind(console));
</script>
</body>
</html>
This component (startComponent
) loads the root page of the application:
@Component({
selector: 'my-app',
templateUrl: 'app/mainPage.html',
directives: [RouterOutlet,RouterLink,ROUTER_DIRECTIVES],
providers: [
ROUTER_PROVIDERS,
HTTP_PROVIDERS
]
})
The page mainPage.html
contains:
<div id="content">
<a [routerLink]="['NextPage']">NextPage</a>
<my-content></my-content>
</div>
When we go to the link NextPage
, init this component:
@Component({
selector: 'my-content',
templateUrl: 'app/nextPage.html'
})
export class NextPageComponent implements OnInit {
public str = "";
constructor() {}
ngOnInit() {
this.getStr();
}
getStr(){
this.str = "abc";
}
}
NextPageComponent
should insert a line "abc" to the selector my-content
which was created by a component of startComponent
.
But somehow, he inserts abc
line at the end of the selector my-app
, not my-content
.
That is, in the end we get the following page:
<my-app>
<div id="content">
<a [routerLink]="['NextPage']">NextPage</a>
<my-content></my-content>
</div>
<my-content _ngcontent-quv-2=""><div>abc</div></my-content>
</my-app>
But, I want get such a page in result:
<my-app>
<div id="content">
<a [routerLink]="['NextPage']">NextPage</a>
<my-content><div>abc</div></my-content>
</div>
</my-app>
Why this is happening? What am I doing wrong?
Upvotes: 2
Views: 404
Reputation: 31777
Router internally uses DynamicComponentLoader (see Router's source code) to instantiate Components dynamically (the name pretty much says it).
It uses specifically loadNextToLocation
and the docs state
loadNextToLocation(...)
Creates an instance of a Component and attaches it to the View Container found at the location specified as ElementRef.
As you see it attaches the Component into the view. It doesn't check the view to see if it matches something inside of it, so whether you have some element that matches the selector it won't work because, again, Router it's not looking for anything on the view, it's attaching the Component in the view, in other words it's pushing it.
Let's try that behavior ourselves. Let's put in some component's view some elements that matches some dynamic component selector
@Component({
selector : 'dynamic-cmp',
template : 'Dynamic template'
})
class DynamicCmp {}
@Component({
selector: 'my-app',
template : `
<dynamic-cmp></dynamic-cmp> <!-- Element matching DynamicCmp selector -->
<dynamic-cmp></dynamic-cmp> <!-- Element matching DynamicCmp selector -->
`
})
export class App {
constructor(private _dcl: DynamicComponentLoader, private _eRef: ElementRef) {}
ngOnInit() {
this._dcl.loadNextToLocation(DynamicCmp, this._eRef);
}
}
Plnkr with the example above
Note : I'm not adding DynamicCmp in directives property
When you run that example and see the DOM you'll see this
<my-app>
<dynamic-cmp></dynamic-cmp>
<dynamic-cmp></dynamic-cmp>
</my-app>
<dynamic-cmp _ngcontent-ybo-2="">Dynamic template</dynamic-cmp>
There are two empty dynamic-cmp
elements even when they match the dynamic component's selector.
This is exactly what Router does, and that's why you see this behavior. Router doesn't rely on the view (it doesn't look for matching selectors) nor in directives, it loads components dynamically (push them) into the view specified.
I hope this clarifies a little bit what's happening.
Upvotes: 1