理想情况下,我需要重新加载/重新呈现我的组件模板,但如果有更好的方法,我会很乐意实现它。
所需行为
所以,我有一个菜单元素的组件。当(在另一个组件中)我点击了一个IBO (某种&#39;客户端&#39;,按照说)点击了我需要添加< / em>(我使用*ngIf
)菜单中的新选项将是 IBO详细信息和子列表。
IBOsNavigationElement
组件(菜单组件):
@Component({
selector: '[ibos-navigation-element]',
template: `
<a href="#"><i class="fa fa-lg fa-fw fa-group"></i> <span
class="menu-item-parent">{{'IBOs' | i18n}}</span>
</a>
<ul>
<li routerLinkActive="active">
<a routerLink="/ibos/IBOsMain">{{'IBOs Main' | i18n}} {{id}}</a>
</li>
<li *ngIf="navigationList?.length > 0">
<a href="#">{{'IBO Details' | i18n}}</a>
<ul>
<li routerLinkActive="active" *ngFor="let navigatedIBO of navigationList">
<a href="#/ibos/IboDetails/{{navigatedIBO['id']}}">{{navigatedIBO['name']}}</a>
</li>
</ul>
</li>
</ul>
`
})
export class IBOsNavigationElement implements OnInit {
private navigationList = <any>[];
constructor(private navigationService: NavigationElementsService) {
this.navigationService.updateIBOsNavigation$.subscribe((navigationData) => {
this.navigationList.push(navigationData);
log.d('I received this Navigation Data:', JSON.stringify(this.navigationList));
}
);
}
ngOnInit() {
}
}
最初,navigationList
将为空[]
,因为用户没有点击任何IBO (客户端),但只要点击了IBO,列表将被填充,因此,我需要在菜单中显示新选项。
使用此代码,当我点击IBO时,会创建<li>
元素及其子元素,但是:我只看到<li>
元素。 < / p>
问题:
菜单选项已生成,但未由布局样式执行。需要使用所有元素进行初始化,以了解如何显示菜单选项。
我需要重新加载该组件的模板才能正确显示菜单。
注意:
如果我使用不带*ngIf
的模板,效果很好,但我会在第一时间看到一个没有意义的 IBO详细信息选项,因为初始化时没有点击过IBO
template: `
<a href="#"><i class="fa fa-lg fa-fw fa-group"></i> <span
class="menu-item-parent">{{'IBOs' | i18n}}</span>
</a>
<ul>
<li routerLinkActive="active">
<a routerLink="/ibos/IBOsMain">{{'IBOs Main' | i18n}} {{id}}</a>
</li>
<li>
<a href="#">{{'IBO Details' | i18n}}</a>
<ul>
<li routerLinkActive="active" *ngFor="let navigatedIBO of navigationList">
<a href="#/ibos/IboDetails/{{navigatedIBO['id']}}">{{navigatedIBO['name']}}</a>
</li>
</ul>
</li>
</ul>
`
期望输出:
在点击任何内容之前(在初始化时):
点击IBO (客户端)后:
更新1:
澄清我的意思:
菜单选项已生成,但未由布局样式
执行
如果,我的菜单组件初始化时没有*ngIf
:
<li>
<a href="#">{{'IBO Details' | i18n}}</a>
<ul>
<li routerLinkActive="active" *ngFor="let navigatedIBO of navigationList">
<a href="#/ibos/IboDetails/{{navigatedIBO['id']}}">{{navigatedIBO['name']}}</a>
</li>
</ul>
</li>
然后布局样式可以根据以下结构生成菜单输出(参见图像):
<li>
<a>
<ul>
<li *ngFor>
<a>
</li>
</ul>
</li>
因此添加+
符号和子菜单行为等
但是,如果它在没有所有元素的情况下进行了初始化(*ngIf
为false
时<li>
并且它的子节点未呈现,则布局不会将它们考虑在内以绘制/创建菜单)这些元素在>>渲染后添加,然后它们将存在于源代码中,但我们无法在菜单中看到它们这是因为:
+
答案 0 :(得分:4)
Angular有两种变化检测策略:
默认策略,自动检测模型中的更改并相应地重新渲染组件。
OnPush,只有在您明确告诉它时才会重新呈现该组件 所以。 另请参阅https://angular.io/docs/ts/latest/api/core/index/ChangeDetectionStrategy-enum.html
当您在页面上有多个元素或希望对渲染过程有更多控制权时,OnPush策略可以获得更好的性能。
要使用此策略,您必须在组件中声明它:
@Component({
selector: '[ibos-navigation-element]',
template: `...`,
changeDetection: ChangeDetectionStrategy.OnPush
})
并注入构造函数:
constructor(
private changeDetector: ChangeDetectorRef,
) {}
如果要触发更改检测,则可以重新呈现组件 (在您的情况下,在将新的IBO /客户端添加到模型之后),请致电:
this.changeDetector.markForCheck();
查看官方教程中的实时演示:http://plnkr.co/edit/GC512b?p=preview
如果问题不是关于更改检测,而是与CSS / SCSS样式有关, 请记住,在Angular 2中,每个组件都有自己的CSS类和 它们不是由“儿童”元素“继承”的。他们是完全孤立的 彼此。一种解决方案可能是创建全局CSS / SCSS样式。
答案 1 :(得分:2)
我终于开始工作了!
所以,我的问题是:
当生成新的HTML元素(使用*ngIf
)时,它们不会显示,因为它们没有处理相同其他菜单元素的方式。
所以我问如何使用所有'new'元素重新加载或重新呈现模板......但是我没有找到重新加载组件或组件模板的位置。相反,我将处理菜单的逻辑应用于我更新的模板。
(如果你想要短篇故事版,请在底部阅读摘要)
所以,我潜入了模板最深刻的逻辑并创建了一个指令来呈现菜单:
MenuDirective(指令)
@Directive({
selector: '[menuDirective]'
})
export class MenuDirective implements OnInit, AfterContentInit {
constructor(private menu: ElementRef,
private router: Router,
public layoutService: LayoutService) {
this.$menu = $(this.menu.nativeElement);
}
// A lot of boring rendering of layout
ngAfterContentInit() {
this.renderSubMenus(this.$menu);
}
renderSubMenus(menuElement) {
menuElement.find('li:has(> ul)').each((i, li) => {
let $menuItem = $(li);
let $a = $menuItem.find('>a');
let sign = $('<b class="collapse-sign"><em class="fa fa-plus-square-o"/></b>');
$a.on('click', (e) => {
this.toggle($menuItem);
e.stopPropagation();
return false;
}).append(sign);
});
}
}
所以在这里我创建了一个菜单指令,它根据现有的html元素呈现菜单的布局。而且,正如您所看到的,我隔离了处理菜单元素的行为添加+
图标,创建子菜单功能等......:renderSubMenus()
。
renderSubMenus()
的行为如何:
循环遍历作为参数传递的nativeElement
的DOM元素,并应用逻辑以正确的方式显示菜单。
<强> menu.html 强>
<ul menuDirective>
<li ibos-navigation-element></li>
<li>
<a href="#"><i class="fa fa-lg fa-fw fa-shopping-cart"></i> <span
class="menu-item-parent">{{'Orders' | i18n}}</span></a>
<ul>
<li routerLinkActive="active">
<a routerLink="/orders/ordersMain">{{'Orders' | i18n}}</a>
</li>
</ul>
</li>
</ul>
这就是我建立菜单的方式。
现在让我们看一下IBOsNavigationElement
组件,它包含在菜单中,其属性为[ibos-navigation-element]
。
IBOsNavigationElement(component)
@Component({
selector: '[ibos-navigation-element]',
template: `
<a href="#"><i class="fa fa-lg fa-fw fa-group"></i> <span
class="menu-item-parent">{{'IBOs' | i18n}}</span>
</a>
<ul class="renderMe">
<li routerLinkActive="active">
<a routerLink="/ibos/IBOsMain">{{'IBOs Main' | i18n}} {{id}}</a>
</li>
<li *ngIf="navigationList?.length > 0">
<a href="#">{{'IBO Details' | i18n}}</a>
<ul>
<li routerLinkActive="active" *ngFor="let navigatedIBO of navigationList">
<a href="#/ibos/IboDetails/{{navigatedIBO['id']}}">{{navigatedIBO['name']}}</a>
</li>
</ul>
</li>
</ul>
`
})
export class IBOsNavigationElement implements OnInit, DoCheck {
private $menuElement: any;
private navigationList = <any>[];
private menuRendered: boolean = false;
constructor(private navigationService: NavigationElementsService, private menuDirective: MenuDirective, private menuElement: ElementRef) {
this.$menuElement = $(this.menuElement.nativeElement);
this.navigationService.updateIBOsNavigation$.subscribe((navigationData) => {
this.navigationList.push(navigationData);
log.d('I received this Navigation Data:', JSON.stringify(this.navigationList));
}
);
}
ngOnInit() {
}
ngDoCheck() {
if (this.navigationList.length > 0 && !this.menuRendered) {
log.er('calling renderSubMenus()');
this.menuDirective.renderSubMenus(this.$menuElement.find('ul.renderMe'));
this.menuRendered = true;
}
}
}
好的,那我在这里做了什么不同?好几件事......
MenuDirective
,因此我可以调用其renderSubMenus()
方法。ElementRef
和find()
来选择我要发送给this.menuDirective.renderSubMenus()
的代码块。我通过class
找到它,请参阅:this.$menuElement.find('ul.renderMe')
。ngDoCheck()
方法,我在其中检查列表navigationList
是否已填充,以及我是否已经渲染了此代码块(我遇到了问题,因为渲染次数太多而且我喜欢6 {{ 1}}按钮:灾难)。<强>要点:强>
要'重新加载'模板:
+
我得到了我想要'重新加载'的模板部分。ElementRef
。您可以随时调用该方法。ngDoCheck()
隐藏元素对组件进行实例化。所以,从技术上讲,我没有重新加载组件。 我在组件的模板中应用了与我重新加载时相同的逻辑。
答案 2 :(得分:0)
尝试使用ChangeDetectorRef.detectChanges() - 它的工作原理与$ scope相同。来自Angular 1的$ digest()。
注意:必须将ChangeDetectorRef注入组件。