我的问题与在同一页面上放置具有不同参数的相同组件有关。在这种情况下,它是一个组件,其中包含来自第三方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>
现在,为了使其更加方便(并轻松将单击事件绑定到整个块等),我想将以<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>
为了使其正常工作, WidgetContainerComponent 具有一个输入字段
@Input() chartId: string;
。
然后我要做的是将 MyChartComponent 的id
属性设置为已设置为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
的情况。
我还尝试按照here和here所述,使用[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>
这会导致 MyChartComponent 具有直接的id
属性,但似乎仅在组件生命周期的稍后阶段添加。
我还尝试仅在ngOnInit
和ngAfterContentInit
中的 MyChartComponent 中初始化图表,但这并不起作用。
任何建议或想法都非常欢迎!
答案 0 :(得分:1)
因此,我找到了解决此问题的方法。问题是双重的:
第一个问题与具有真实id
属性的要求有关,而属性名称以ng-reflect-
前缀有角。
我不知道的是,从Angular 4开始,此前缀被添加到在开发模式下被声明为该组件的@Input
变量的任何属性中(有关详细说明,请参见{{3 }})。
解决此问题的方法是写[attr.id]=chartId
而不是[id]=chartId
。原因是在这种情况下,我需要设置一个 HTML属性,但是使用方括号符号创建了一个属性绑定。为了通过属性绑定语法动态设置HTML属性,您必须在属性名称上添加前缀attr.
。
有关所有有效绑定语法的完整概述,请参见this post。 专门回顾如何进行属性绑定,请参见Angular Docs。
第二个问题是,当尚未创建组件的id
属性时,我尝试访问它。此问题与Angular的生命周期挂钩有关,该阶段有不同的阶段。有关Angular生命周期挂钩的完整概述,请参见this section。
由于我本人并不十分了解它,因此我将在此处详细说明。
Angular带有一组固定的生命周期钩子,每次安装组件时都会调用它们,它们也以预定义的顺序被调用。挂钩的定义如下:
_
重要的是,在一个步骤中创建或准备的元素只能在任何后续步骤中访问。在我的情况下,我将用于图表初始化的所有代码都放入了ngAfterContentInit
钩子中,但是只有在调用ngAfterViewInit
时该组件才完全加载。
最后,解决方案是将预初始化代码放入构造函数中,并将图表初始化代码放入ngAfterViewInit
方法中。在此阶段,id
属性已正确创建,可以由图表访问。