【问题标题】:How to set a dynamic "id" HTML attribute of an angular component?如何设置角度组件的动态“id”HTML属性?
【发布时间】:2023-03-26 19:23:01
【问题描述】:

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

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

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

我猜是它起作用的原因,因为id 属性在组件创建时就存在,并且任何尝试访问它的代码都可以立即执行此操作。

然而,这个图表又被嵌入到 bootstrap 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>

现在为了使它更方便(并轻松地将点击事件绑定到整个块等),我想以&lt;div class="card"&gt; 开头的整个部分提取到一个新组件中。

假设我称这个新组件为 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>

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

@Input() chartId: string;

可以设置。

然后我要做的就是将MyChartComponentid属性设置为已经设置为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>

但这不起作用,因为 Angular 为 id 属性添加了一个前缀,这会导致类似于 ng-reflect-id 的内容。

我还尝试使用[attr.id] 设置属性,如herehere 所述:

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

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

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

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

【问题讨论】:

  • 嗨,你的意思是写&lt;my-chart id="{{chartId}}"&gt;&lt;/my-chart&gt;而不是&lt;my-chart [id]="chartId"&gt;&lt;/my-chart&gt;?我之前已经尝试过,在这种情况下,id 属性名称也以ng-reflect- 字符串为前缀,这导致ng-reflect-id 属性不被识别为HTML id 属性。不过我想我已经想通了,我稍后会发布答案。

标签: javascript angular dependency-injection


【解决方案1】:

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

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

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

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

    有关所有有效绑定语法的详细概述,请参阅Angular Docs。 具体要查看如何进行属性绑定,请参阅this section

  2. 第二个问题是我在组件尚未创建时尝试访问组件的id 属性。这个问题与 Angular 的生命周期钩子有关,其中有不同的阶段。有关 Angular 生命周期钩子的详细概述,请参阅 this page

    因为我自己不是很了解,所以我会在此详细说明。

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

    1. 构造函数
    2. ngOnChanges
    3. ngOnInit
    4. ngDoCheck
      1. ngAfterContentInit
      2. ngAfterContentChecked
      3. ngAfterViewInit
      4. ngAfterViewChecked
    5. ngOnDestroy

    _

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

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

【讨论】:

  • 谢谢,这很有帮助!我在构造函数中设置 id 并在 ngOnInit 中执行 getElementById。显然组件没有完全初始化!
  • 太好了,很高兴它帮到了你!
猜你喜欢
相关资源
最近更新 更多
热门标签