【问题标题】:Angular - @ViewChild from My ModuleAngular - 我的模块中的@ViewChild
【发布时间】:2018-06-05 02:44:35
【问题描述】:

我的问题是关于 Angular 2/4/5 模块。

在模块中使用 @ViewChild 时无法正常工作,子级未定义。在我将它用作简单组件之前,它运行良好。 *尝试过@ViewChildren 也...相同

代码示例 -

app.module.ts -

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { MyNewModule} from './modules/MyNewModule/MyNewModule.module';

import { AppComponent } from './app.component';


@NgModule({
  declarations: [
    AppComponent,
  ],
  imports: [
    BrowserModule,
    MyNewModule,
  ],
  providers: [],
  bootstrap: [AppComponent],
})
export class AppModule { }

app.component.ts -

import { Component, OnInit } from '@angular/core';
import { MyNewModule} from './modules/MyNewModule/MyNewModule.module';
@Component({
  selector: 'app-root',
  template: `<button (click)="Print()">Print child</button>
             <my-new-module></my-new-module>
            `,
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {

  constructor(private MyModule:MyNewModule){}

  ngOnInit(){}

  Print(){
   this.MyModule.Print();
  }

}

modules/MyNewModule/MyNewModule.module -

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { MyNewModule} from './MyNewModule.component';

@NgModule({
  imports: [
    CommonModule,
  ],
  declarations: [MyNewModule],
  providers: [MyNewModule],
  exports: [MyNewModule],
})
export class MyNewModule{ }

modules/MyNewModule/MyNewModule.ts-

import { Component, OnInit, ViewChild, ViewContainerRef, ComponentFactoryResolver } from '@angular/core';

@Component({
  selector: 'my-new-module',
  template:`<ng-template #Container></ng-template>`
})
export class MyNewModule implements OnInit {

@ViewChild('Container', {read: ViewContainerRef}) private container: ViewContainerRef;

constructor(){}

ngOnInit(){}

Print(){
  console.log(this.container); => undefined
}



}

当尝试在线搜索答案时,我发现的唯一解决方案是尝试@ViewChildren,或者它可能会发生,因为视图尚未初始化。所以我什至尝试在 5 秒的超时时间内完成它......结果相同。 再次使用相同的代码,但作为一个简单的应用程序而不是模块工作正常。

感谢阅读! :)

【问题讨论】:

  • 你在哪里打电话Print()
  • 为什么你的组件命名为MyNewModule而不是MyNewComponent?我认为这给您带来了一些问题。此外,您不能将组件放入providers 数组中。
  • @Und3rTow 已修复,已添加到 app.component.ts 模板中:)
  • @BunyaminCoskuner 我不是,它只是为了这个演示。将其从提供程序数组中删除会给我一个错误 - StaticInjectorError
  • 你为什么还要尝试将 Angular 模块注入到组件中?

标签: javascript angular dom module viewchild


【解决方案1】:

您需要一个 ViewChild 来为您的模板引用 TemplateRef 和 ViewContainerRef。使用ComponentResolverFactory 创建组件,然后使用组件 viewRef 创建嵌入视图。

@Component({
    selector: 'widget',
    template: '<ng-template #view></ng-template>'
})

export class WidgetComponent implements OnInit {
    @ViewChild('view', { read: ViewContainerRef }) view: ViewContainerRef;
    @ViewChild('view') template: TemplateRef<any>;

    constructor(private factory: ComponentResolverFactory, private viewRef: ViewContainerRef) { }

    ngOnInit() { 
         let component = ... some Type<any>...
         let componentFactory = this.factory.resolveComponentFactory(component);
         let ref:ComponentRef<any> = view.createComponent(componentFactory);
         this.factory.create(this.view, this.message.component);
         this.viewRef.createEmbeddedView(this.template);

    }
}

【讨论】:

  • 为什么模板需要 ViewContainerRef?为什么我需要为它生成一个组件?将 添加到 app.component 模板中还不够吗?
【解决方案2】:

正如我从 cmets 中了解到的,您希望为组件创建一个功能模块并在您的项目中重用它。

我建议你看看这个组件库PrimeNg 和他们的Github 页面。它们具有精心设计的架构,即组件的功能模块。

让我们从头开始构建我们的可重用组件。

我用 angular-cli 创建了一个新应用

ng new my-proj

然后,我为稍后将开发的组件创建了一个功能模块。我们就叫它MyComponent

ng generate module my-component

然后创建了一个同名的组件

ng generate component my-component

然后我编辑MyComponent如下

我的组件.component.ts

@Component({
    selector: 'my-component',
    template: `
        <h1>My Component</h1>
        <div #container>
            <ng-content></ng-content>
        </div>
    `,
    styleUrls: ['./my-component.component.css']
})
export class MyComponentComponent implements OnInit, AfterContentInit {

    @ViewChild('container') container: ElementRef;

    constructor() { }

    ngOnInit() {
        console.log(this.container);
    }

    // this life cycle method is called after projected content is initialized.
    ngAfterContentInit() {
        console.log(this.container);
    }

    someMethod() {
    // do something ...
    }
}

然后我从my-component.module.ts导出如下

@NgModule({
    imports: [CommonModule],
    declarations: [MyComponentComponent],
    exports: [MyComponentComponent]
})
export class MyComponentModule { }

然后,在我的app.module.ts 中导入这个模块并在app.component 中使用这个组件

另外,如果你想在app.component中访问my-component,你可以使用ViewChild

app.component.ts

@Component({
    selector: 'app-root',
    template: `
        <button (click)="onButtonClick()">Click me</button>
        <my-component>
            <div>This is from app component</div>
        </my-component>
    `,
})
export class AppComponent {

    @ViewChild(MyComponentComponent) myComponent: MyComponentComponent;

    onButtonClick() {
        this.myComponent.someMethod();
    }
}

我希望这能为你澄清它

编辑

要发布您的图书馆,您可以查看这篇文章:

Building an Angular 4 Component Library with the Angular CLI and ng-packagr

此外,对于将使用您的库从同一文件中导入您的组件和模块的人,您可以将其从您的模块中导出,如下所示

我的组件.module.ts

export {MyComponentComponent} from './my-component.component.ts';

@NgModule({
    ...
})
export class MyComponentModule {}

要将其导入您的app.component

app.component.ts

import {MyComponentComponent} from 'your-library/my-component.module';

您可以从同一位置导入模块

app.module.ts

import {MyComponentModule} from 'your-library/my-component.module';

【讨论】:

  • 太棒了,这正是我所需要的! MyComponentComponent 的@ViewChild 的想法是我所缺少的,现在我只需要构建我的模块并将其发布到npm。非常感谢您提供的信息丰富的答案
  • @Ben 很高兴你喜欢我的回答。我更新了它并添加了一个链接。您可以为此使用 ng-packagr。
  • 我有另一个问题如果可以...显然 MyComponentComponent 需要在 app.component.ts 中导入才能使用它。整个想法不是我将它添加到模块导出数组中吗?如何在不从其他位置单独导入的情况下使用它?
  • 嗯,是的,您必须添加import {MyComponentComponent} from '../my-component/my-component.component.ts,因为您在代码中使用了它的类型。 Typescript 需要知道它来自哪里。但它与 Angular 导入不同。这只是 ES6 模块导入。
  • 为简单起见,我省略了 import 语句,但您需要它们。
猜你喜欢
  • 1970-01-01
  • 2020-06-02
  • 2019-06-23
  • 1970-01-01
  • 2016-06-21
  • 2021-10-04
  • 1970-01-01
  • 2020-02-20
  • 1970-01-01
相关资源
最近更新 更多