Angular - 单击时动态 ngDropdown 不展开
Angular - Dynamic ngDropdown not expanding when clicked
我的组件有 N 个过滤器,对于每个过滤器,有 M 个值。我正在尝试动态显示这两个,但它似乎不起作用。
我能够测试这些值,看看我是否使用了正确的语法来检索数据,代码是否能够从对象中获取数据。但是,当使用动态过滤器时,看起来 运行 下拉列表 <button>
标签之后没有任何内容。
您可以查看 here 我制作的 StackBlitz 项目作为我的应用程序的副本。
当我从 HTML 调用 getFilters
时,我已将过滤器对象以返回的形式打印到控制台。如您所见,它正在返回数据,但是当用户单击下拉列表时可以看到 none 的 filterValues。
我希望它显示每个 filterValues
,但当我单击下拉按钮时没有任何反应。如果我从中删除动态功能,我可以在下拉列表中看到值,但我希望它是动态的。任何帮助将不胜感激。
相关模板代码:
<div ngbDropdown class="d-inline-block" *ngFor="let filter of getFilters()">
<button class="btn btn-outline-primary" id="{{filter[0]-dropdown}}" ngbDropdownToggle>{{filter[1].displayName}}</button>
<div ngbDropdownMenu attr.aria-labelledby="{{filter[0]-dropdown}}">
<button ngbDropdownItem *ngFor="let val of filter[1].filterValues">{{val}}</button>
</div>
</div>
和相关的 TypeScript 代码:
getFilters() : [string, FilterItem][] {
...
return Array.from(this.filters.entries());
}
您遇到的问题是因为您的 getFilters()
函数不是幂等的。
Angular 期望如果它连续调用一个方法两次,而无需用户干预,它将 return 相同的值。如果你的函数 return 是一个数组,它需要 return 同一个数组两次。但是在您的代码中,您每次都 returning 一个不同的数组(即使它具有相同的内容,它仍然是一个不同的引用)。
为 getFilters()
方法尝试此实现,您会看到问题消失(我不建议您这样解决问题,但它说明了问题出在哪里):
private cached;
getFilters() : [string, FilterItem][] {
if (!this.cached)
this.cached = Array.from(this.filters.entries())
return this.cached;
}
我的推荐
我不建议像这样缓存值,相反,您应该将更改应用程序状态的代码放在与检索应用程序状态的代码不同的部分,如下所示:
constructor () {
this.filters = ...
this.filterEntries = Array.from(this.filters.entries());
}
然后在您的模板中:
<div ngbDropdown class="d-inline-block" *ngFor="let filter of filterEntries">
来自文档:
Angular docs 告诉您以下有关副作用的信息,我已将最相关的文字加粗:
No visible side effects
A template expression should not change any application state other than the value of the target property.
In Angular terms, an idempotent expression always returns exactly the same thing until one of its dependent values changes.
If an idempotent expression returns a string or a number, it returns the same string or number when called twice in a row. If the expression returns an object, including an array, it returns the same object reference when called twice in a row.
我的组件有 N 个过滤器,对于每个过滤器,有 M 个值。我正在尝试动态显示这两个,但它似乎不起作用。
我能够测试这些值,看看我是否使用了正确的语法来检索数据,代码是否能够从对象中获取数据。但是,当使用动态过滤器时,看起来 运行 下拉列表 <button>
标签之后没有任何内容。
您可以查看 here 我制作的 StackBlitz 项目作为我的应用程序的副本。
当我从 HTML 调用 getFilters
时,我已将过滤器对象以返回的形式打印到控制台。如您所见,它正在返回数据,但是当用户单击下拉列表时可以看到 none 的 filterValues。
我希望它显示每个 filterValues
,但当我单击下拉按钮时没有任何反应。如果我从中删除动态功能,我可以在下拉列表中看到值,但我希望它是动态的。任何帮助将不胜感激。
相关模板代码:
<div ngbDropdown class="d-inline-block" *ngFor="let filter of getFilters()">
<button class="btn btn-outline-primary" id="{{filter[0]-dropdown}}" ngbDropdownToggle>{{filter[1].displayName}}</button>
<div ngbDropdownMenu attr.aria-labelledby="{{filter[0]-dropdown}}">
<button ngbDropdownItem *ngFor="let val of filter[1].filterValues">{{val}}</button>
</div>
</div>
和相关的 TypeScript 代码:
getFilters() : [string, FilterItem][] {
...
return Array.from(this.filters.entries());
}
您遇到的问题是因为您的 getFilters()
函数不是幂等的。
Angular 期望如果它连续调用一个方法两次,而无需用户干预,它将 return 相同的值。如果你的函数 return 是一个数组,它需要 return 同一个数组两次。但是在您的代码中,您每次都 returning 一个不同的数组(即使它具有相同的内容,它仍然是一个不同的引用)。
为 getFilters()
方法尝试此实现,您会看到问题消失(我不建议您这样解决问题,但它说明了问题出在哪里):
private cached;
getFilters() : [string, FilterItem][] {
if (!this.cached)
this.cached = Array.from(this.filters.entries())
return this.cached;
}
我的推荐
我不建议像这样缓存值,相反,您应该将更改应用程序状态的代码放在与检索应用程序状态的代码不同的部分,如下所示:
constructor () {
this.filters = ...
this.filterEntries = Array.from(this.filters.entries());
}
然后在您的模板中:
<div ngbDropdown class="d-inline-block" *ngFor="let filter of filterEntries">
来自文档:
Angular docs 告诉您以下有关副作用的信息,我已将最相关的文字加粗:
No visible side effects
A template expression should not change any application state other than the value of the target property.
In Angular terms, an idempotent expression always returns exactly the same thing until one of its dependent values changes.
If an idempotent expression returns a string or a number, it returns the same string or number when called twice in a row. If the expression returns an object, including an array, it returns the same object reference when called twice in a row.