将组件中的依赖注入附加到已经附加的注入

Attach dependency injection in component to the already attached injections

我使用 Angular Material 将按钮组件 (AddButtonComponent) 动态附加到另一个组件 (ParentComponent) 的 DOM。如果我通常在模板中使用 <button matButton>A button</button> 创建按钮,按钮的样式就会完美。如果我动态创建它,它也会有样式。

现在,我需要注入一个字符串以将类名附加到我的按钮,但如果我使用自定义 Injector,它会丢失所有样式。我认为当我注入我的字符串时,它会用那个注入器覆盖当前的应用程序注入。

我尝试将 ParentComponent 注入器添加到 parent 属性,但它也没有用。

我做错了什么?

(明明可以调用ElementRefinstance,设置属性值,但是太丑了,相信可以实现。)

这是一个代码示例:

import {
    Component,
    OnInit,
    Optional,
    Inject,
    Injector,
    InjectionToken,
    ElementRef,
    ViewContainerRef,
    ComponentFactoryResolver,
} from '@angular/core';

export const CLASS_INJECTION: InjectionToken<string> = new InjectionToken<string>('ClassInjection');

@Component({
    selector: 'app-add-button`,
    template: '<button matButton [class]="classInjection">A button</button>',
    styles: []
})
export class AddButtonComponent implements OnInit {

    constructor(@Optional() @Inject(CLASS_INJECTION) public classInjection: string) { }

}

@Component({
    selector: 'app-parent-component',
    template: '<button matButton>Button styled</button>',
    styles: []
})
export class ParentComponent implements OnInit {

    constructor(
        private _injector: Injector,
        private componentFactoryResolver: ComponentFactoryResolver,
        private viewContainerRef: ViewContainerRef
    ) { }

    ngOnInit() {
        const addButtonComponentFactory = this.componentFactoryResolver.resolveComponentFactory(AddButtonComponent);
        const addButtonComponentRef = this.viewContainerRef.createComponent(addButtonComponentFactory, undefined, Injector.create({
            providers: [{provide: ELEMENT_TYPE, useValue: widget.type === 'column' ? 'SECTION' : 'MODULE'}],
            parent: this._injector
        }));
        // <Code to add element into DOM...>
    }

}
<button matButton [class]="classInjection">A button</button>

matButton 将在创建时分配 CSS 类,但您使用的 [class] 绑定将 替换 所有现有 CSS 类。所以 Material 设计 CSS 样式丢失了。如果您查看 Chrome 检查器,您会发现它们已被删除。

如果您知道只会使用 SECTIONMODULE,则使用 [class.style] 绑定有选择地添加或删除特定样式。

<button matButton [class.SECTION]="classInjection === 'SECTION'"
                  [class.MODULE]="classInjection === 'MODULE'">A button</button>

如果您不知道 CSS 样式是什么,则必须手动添加它们。这可以通过 @ViewChild 访问 <button> 元素然后手动添加 CSS 样式来完成。

@Component({
    selector: 'app-add-button',
    template: '<button matButton>A button</button>',
    styles: []
})
export class AddButtonComponent implements OnInit {

    @ViewChild(MatButton, {read: ElementRef})
    public btn: ElementRef<HTMLElement>;

    constructor(@Optional() @Inject(CLASS_INJECTION) public classInjection: string) {
    }

    public ngOnInit(): void {
        this.btn.nativeElement.classList.add(this.classInjection);
    }
}

过去使用 [class] 时我感到非常沮丧,因为它会覆盖所有样式,而且没有其他方法可供使用。 [class][ngClass] 具有相同的行为,如果您必须经常执行上述操作,您可以编写一个名为 [addClass] 的自定义指令,它仅附加 CSS 样式。