Прикрепить инъекцию зависимостей в компоненте к уже прикрепленным инъекциям

Я прикрепляю компонент кнопки ( AddButtonComponent ) динамически к DOM другого компонента ( ParentComponent ), используя Angular Material для стиля. Если я обычно создаю кнопки в шаблоне с помощью <button matButton>A button</button> , кнопка будет идеально стилизована. Если я создаю его динамически, он тоже становится стилизованным.

Теперь мне нужно ввести строку, чтобы прикрепить имя класса к моей кнопке, но он теряет все стили, если я использую пользовательский Injector . Я думаю, что когда я внедряю свою строку, она перекрывает текущие инъекции приложения этим инжектором.

Я попытался добавить инжектор ParentComponent к атрибуту parent , но он также не работал.

Что я делаю неправильно?

(Очевидно, я могу вызвать instance ElementRef и установить значение атрибута, но это ужасно. Я считаю, что этого можно достичь.)

Вот пример кода:

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...>
    }

}

Всего 1 ответ


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

matButton назначит CSS-классы при его создании, но используемая привязка [class] заменит все существующие CSS-классы. Поэтому CSS-стили Material Design теряются. Если вы загляните в инспектор Chrome, то увидите, что они были удалены.

Если вы знаете, что будут использоваться только SECTION и MODULE , используйте [class.style] для выборочного добавления или удаления определенного стиля.

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

Если вы не знаете, какими будут стили CSS, вам придется добавить их вручную. Это можно сделать, @ViewChild элемент <button> через @ViewChild а затем вручную добавив стиль 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.


Есть идеи?

10000