为什么Angular 2看不到动态创建的选择器?

时间:2016-03-09 10:44:24

标签: javascript angular

这是开始页面:

<!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>

此组件(startComponent)加载应用程序的根页:

@Component({
    selector: 'my-app',
    templateUrl: 'app/mainPage.html',
    directives: [RouterOutlet,RouterLink,ROUTER_DIRECTIVES],
    providers: [
        ROUTER_PROVIDERS,
        HTTP_PROVIDERS
    ]
})

页面mainPage.html包含:

<div id="content">
    <a [routerLink]="['NextPage']">NextPage</a>
    <my-content></my-content>
</div>

当我们转到NextPage链接时,请启动此组件:

@Component({
    selector: 'my-content',
    templateUrl: 'app/nextPage.html'
})

export class NextPageComponent implements OnInit {
    public str = "";

    constructor() {}

    ngOnInit() {
        this.getStr();
    }

    getStr(){
        this.str = "abc";
    }
}

NextPageComponent应该在由my-content的组件创建的选择器startComponent中插入一行“abc”。 但不知何故,他在选择器abc的末尾插入了my-app行,而不是my-content

也就是说,最后我们得到以下页面:

<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>

但是,我想在结果中得到这样一个页面:

<my-app>
    <div id="content">
        <a [routerLink]="['NextPage']">NextPage</a>
        <my-content><div>abc</div></my-content>
    </div>
</my-app>

为什么会这样?我做错了什么?

1 个答案:

答案 0 :(得分:1)

Router在内部使用DynamicComponentLoader(请参阅Router's source code)动态实例化组件(这个名称几乎就是这么说的)。

它专门使用loadNextToLocation和文档状态

  

loadNextToLocation(...)

     

创建Component的实例并将其附加到在指定为ElementRef的位置找到的View容器。

如您所见,它将Component附加到视图中。它没有检查视图以查看它是否与其中的某些内容相匹配,因此,无论您是否有一些与选择器匹配的元素,它都会工作,因为再次,路由器它没有寻找任何东西在视图中,它在视图中附加了组件,换句话说就是它推动它。

让我们自己尝试这种行为。让我们在一些组件中查看一些与某些动态组件选择器匹配的元素

@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以及上面的示例

注意:我没有在指令属性中添加DynamicCmp

当您运行该示例并查看DOM时,您将看到此

<my-app>
    <dynamic-cmp></dynamic-cmp>
    <dynamic-cmp></dynamic-cmp>
</my-app>
<dynamic-cmp _ngcontent-ybo-2="">Dynamic template</dynamic-cmp>

有两个空的dynamic-cmp元素,即使它们与动态组件的选择器匹配。

这正是路由器的作用,这也是您看到此行为的原因。路由器不依赖于视图(它不会查找匹配的选择器),也不依赖于指令,它会动态地将组件(推送它们)加载到指定的视图中。

我希望这能澄清一下发生了什么。