Прикрепить внедрение зависимостей в компоненте к уже прикрепленным инъекциям - PullRequest
1 голос
/ 17 мая 2019

Я подключаю компонент кнопки (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 Ответ

1 голос
/ 17 мая 2019
<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, вам придется добавить их вручную. Это можно сделать, обратившись к элементу <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.

...