如何设置角度组件的动态“id”HTML 属性?

aeg*_*ger 4 javascript dependency-injection angular

我的问题与在同一页面上放置具有不同参数的相同组件有关。在这种情况下,它是一个包含来自第三方 Javascript 库 ( D3JS )的图表的组件,它需要一个 HTMLid属性来定位和修改组件的 HTML 内容。

现在这个id属性应该包含放置在页面上的每个图表的唯一字符串,如果我直接将它设置为来自父组件的字符串,它就可以正常工作:

<my-chart id="gaugeChart0"></my-chart>

我猜它工作的原因是,因为该id属性在组件创建时就存在,并且任何试图访问它的代码都可以立即完成。

然而,该图表又嵌入到引导程序 4 卡布局中,如下所示:

<div class="row">
    <div class="col-6">
        <div class="card">
            <div class="card-body">
                <div class="row">
                    <div class="col-5">
                        <my-chart id="gaugeChart0"></my-chart>
                    </div>
                    <div class="col-7">
                        ... Some other widgets ...
                    </div>
                </div>
            </div>
        </div>
    </div>
    <div class="col-6">
        <div class="card">
            <div class="card-body">
                <div class="row">
                    <div class="col-5">
                        <my-chart id="gaugeChart1"></my-chart>
                    </div>
                    <div class="col-7">
                        ... Some other widgets ...
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>
Run Code Online (Sandbox Code Playgroud)

现在为了使它更方便(并轻松地将单击事件绑定到整个块等),我想将整个部分提取<div class="card">到一个新组件中。

假设我将这个新组件称为 WidgetContainerComponent,它包含图表以及引导卡布局,包括在那里定义的其他小部件。

使用此包装器组件时的结果代码将是:

<div class="row">
    <div class="col-6">
        <widget-container chartId="gaugeChart0"></widget-container>
    </div>
    <div class="col-6">
        <widget-container chartId="gaugeChart1"></widget-container>
    </div>
</div>
Run Code Online (Sandbox Code Playgroud)

为了使其工作,WidgetContainerComponent有一个输入字段

@Input() chartId: string;

可以设置。

我想要做的是idMyChartComponent的属性设置为已设置为的字符串chartId

<div class="card">
    <div class="card-body">
        <div class="row">
            <div class="col-5">
                <my-chart [id]="chartId"></my-chart>
            </div>
            <div class="col-7">
                ... Some other widgets ...
            </div>
        </div>
    </div>
</div>
Run Code Online (Sandbox Code Playgroud)

但这不起作用,因为 angular 为id属性添加了一个前缀,导致类似ng-reflect-id.

我还尝试[attr.id]按照此处此处的描述设置属性:

<div class="card">
    <div class="card-body">
        <div class="row">
            <div class="col-5">
                <my-chart [attr.id]="chartId"></my-chart>
            </div>
            <div class="col-7">
                ... Some other widgets ...
            </div>
        </div>
    </div>
</div>
Run Code Online (Sandbox Code Playgroud)

这导致MyChartComponent具有直接id属性,但它似乎只在组件生命周期的后期添加。

我还尝试仅在和 中初始化MyChartComponent 中的图表,但这不起作用。ngOnInitngAfterContentInit

非常欢迎任何建议或想法!

aeg*_*ger 7

所以我找到了解决这个问题的方法。问题是双重的:

  1. 第一个问题与具有真实id属性的要求有关,而不ng-reflect-是以 angular为前缀的属性名称。

    我不知道的是,从 Angular 4 开始,这个前缀被添加到任何@Input在开发模式下声明为组件变量的属性(有关深入解释,请参阅这篇文章)。

    这个问题的解决方案是编写[attr.id]=chartId而不是[id]=chartId. 原因是在这种情况下我需要设置一个HTML 属性,但是使用方括号表示法创建了一个属性绑定。为了通过属性绑定语法动态设置 HTML 属性,您必须将前缀添加attr.到属性名称。

    有关所有有效绑定语法的完整概述,请参阅Angular 文档。具体复习如何做属性绑定见本节

  2. 第二个问题是我试图访问id尚未创建的组件的属性。这个问题与Angular的生命周期钩子有关,这里有不同的阶段。要全面了解 Angular 的生命周期挂钩,请参阅此页面

    因为我自己也不是很了解,这里我就简单的说一下。

    Angular 带有一组固定的生命周期钩子,每次设置组件时都会调用这些钩子,并且也会以预定义的顺序调用。钩子定义如下:

    1. 构造函数
    2. ngOnChanges
    3. 初始化
    4. ngDoCheck
      1. 内容初始化后
      2. ngAfterContentChecked
      3. ngAfterViewInit
      4. ngAfterViewChecked
    5. 销毁时

    _

    需要注意的是,在一个步骤中创建或准备的元素只能在任何后续步骤中访问。就我而言,我将图表初始化的所有代码都放入ngAfterContentInit钩子中,但是该组件仅在ngAfterViewInit被调用时才完全加载。

    最后的解决方案是将预初始化代码放入构造函数中,并将图表初始化代码放入ngAfterViewInit方法中。在此阶段,id属性已正确创建并可被图表访问。