PrimeNG 更改了 ui 组件的图标机制。我想要我的自定义复选框图标。
触摸 html 不是一个选项,而是使用指令。
我想通过指令插入复选框的图标模板
我正在尝试这样的事情
<p-checkbox checkboxIcon>
<!-- this is not an OPTION
<ng-template pTemplate="icon">
<custom-icon></custom-icon>
</ng-template>
-->
</p-checkbox>
我不知何故想要在指令中创建TemplateRef并插入它。
@Directive({
selector: '[checkboxIcon]',
})
export class IconDirective implements OnInit {
constructor(
private element: ElementRef,
@Self() private checkbox: Checkbox
) {}
@HostListener('click', ['$event']) onModelChange(event): void {
this.appendIconTemplate();
}
appendIconTemplate(): void {
const iconTemplate = document.createElement('ng-template');
iconTemplate.setAttribute('pTemplate', 'icon');
iconTemplate.innerHTML = '<custom-icon></custom-icon>';
this.element.nativeElement.appendChild(iconTemplate);
}
}
我有一个问题的最小重现这里
发现了带有
@Self()
和 ComponentFactoryResolver
的东西。但从来没有这样做过,有人可以帮忙吗?
因此,根据您的需求需要考虑一些事情,首先,没有简单干净的方法使用指令添加子组件,我们可以使用
TemplateRef
和 ViewContainerRef
但该组件将作为同级组件添加.
在我们的例子中,我们也无法使用 HostListener,因为在结构指令上使用它时,它不会具有预期的行为。
所以我们必须采取不同的方法,因为你分享的 StackBlitz 是在 Angular 17 中,我使用了信号。
首先,我们需要一个新的
Component
来封装自定义图标。
@Component({
selector: 'appCustomIcon',
template: `
<custom-icon></custom-icon>
`,
})
export class CustomIconContainer {}
然后我们可以修改指令以便能够在其嵌入视图中创建我们的
CustomIconContainer
:
@Directive({
selector: '[checkboxIcon]',
})
export class IconDirective {
// We will now us an input to know if the icon must be shown
checkboxIcon = input<boolean>(false);
constructor(
private templateRef: TemplateRef<any>,
private viewContainer: ViewContainerRef
) {
// This effect will listen on the changes in our input.
effect(() => {
// Using the signal will mark it to be used by the effect.
const showIcon = this.checkboxIcon();
// We run the rest of the logic in the untracked function to avoid
// side effects
untracked(() => {
if (showIcon) this.appendIconTemplate();
else this.resetView();
});
});
}
appendIconTemplate(): void {
this.viewContainer.clear();
const embeddedView = this.viewContainer.createEmbeddedView(
this.templateRef
);
const component = this.viewContainer.createComponent(CustomIconContainer);
// This is the "hack" that allows us to create the component
// as a child of the element
embeddedView.rootNodes[0].appendChild(component.location.nativeElement);
}
resetView(): void {
this.viewContainer.clear();
this.viewContainer.createEmbeddedView(this.templateRef);
}
}
为了避免依赖
HostListener
,我们将监听复选框本身的点击,这是新的 ChboxDemo
类:
export class ChboxDemo {
protected showCustomIcon = false;
// The checked boolean is used to keep the state of the checkbox
// between the view container refreshes
protected checked = false;
protected onClick() {
this.showCustomIcon = !this.showCustomIcon;
}
}
<div class="card">
<p-checkbox
binary="true"
label="label"
(click)="onClick()"
*checkboxIcon="showCustomIcon"
[(ngModel)]="checked"
>
</p-checkbox>
</div>
还有一个小问题,图标无法显示,为了解决这个问题,我简单地为 svg 元素添加了一个宽度:
<svg style="width: 20px" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path
d="M14.83,12,18,8.82A1,1,0,0,0,18,7.4L16.6,6a1,1,0,0,0-1.42,0L12,9.17,8.82,6A1,1,0,0,0,7.4,6L6,7.4A1,1,0,0,0,6,8.82L9.17,12,6,15.18A1,1,0,0,0,6,16.6L7.4,18a1,1,0,0,0,1.42,0L12,14.83,15.18,18a1,1,0,0,0,1.42,0L18,16.6a1,1,0,0,0,0-1.42Z"
/>
</svg>
这是您的分叉 StackBlitz 及其工作解决方案:
https://stackblitz.com/edit/btpn8a-as1ppw?file=src%2Fapp%2Fdemo%2Fchbox-demo.html
我希望这对您有所帮助,如果有任何其他问题,我可以回答。