0

I have this custom button:

Html template:

<button mat-button
        [color]="color"
        (cbClick)="onClick($event)"
        [disabled]="disabled"
        [ngClass]="isStroked ? 'mat-stroked-button' : 'mat-raised-button'">
    <ng-content></ng-content>
</button>

Typescript:

@Component({
    selector: 'cb-button',
    templateUrl: './button.component.html',
    styleUrls: ['./button.component.scss']
})
export class ButtonComponent {
    /**
     * Warning - calling this "click" causes bug due to naming conflict
     */
    @Output() public readonly clicked = new EventEmitter<boolean>();
    @Output() public readonly popupClick = new EventEmitter();
    @Input() public color = 'primary';
    @Input() public disabled = false;
    @Input() public isStroked = false;
    @Input() public popup?: Popup;

    constructor() { }

    public readonly onClick = (event: MouseEvent): void => {
        this.clicked.emit(true);
    };

    public readonly onPopupClick = (event: MouseEvent): void =>{
        this.popupClick?.emit(event);
    };
}

using it:

        <span fxFlex></span>
        <cb-button class="cb-margin"
                   (clicked)="generateUserSecurityReport()">
            User Security Report
        </cb-button>

For some reason in one area of my app, but not in other areas, it is displaying with 2 buttons. When I remove <ng-content> it doesn't create 2 buttons:

enter image description here

Why is it nesting a second button in some scenarios?

EDIT:

HTML produced:

<cb-button _ngcontent-wwl-c684="" class="cb-margin" _nghost-wwl-c681="" ng-version="11.0.7">
    <button _ngcontent-wwl-c681="" mat-button="" class="mat-focus-indicator mat-button mat-button-base mat-primary mat-raised-button" ng-reflect-color="primary" ng-reflect-disabled="false" ng-reflect-ng-class="mat-raised-button">
        <span class="mat-button-wrapper">
            <button
                _ngcontent-wwl-c681=""
                mat-button=""
                class="mat-focus-indicator mat-button mat-button-base mat-primary mat-raised-button ng-scope"
                ng-reflect-color="primary"
                ng-reflect-disabled="false"
                ng-reflect-ng-class="mat-raised-button"
            >
                <span class="mat-button-wrapper"> User Security Report </span>
                <span matripple="" class="mat-ripple mat-button-ripple" ng-reflect-disabled="false" ng-reflect-centered="false" ng-reflect-trigger="[object HTMLButtonElement]"></span><span class="mat-button-focus-overlay"></span>
            </button>
        </span>
        <span matripple="" class="mat-ripple mat-button-ripple" ng-reflect-disabled="false" ng-reflect-centered="false" ng-reflect-trigger="[object HTMLButtonElement]"></span><span class="mat-button-focus-overlay"></span>
    </button>
</cb-button>

EDIT:

When i remove the downgrade decorator from the module it works as expected:

@NgModule({
    declarations: ButtonComponent,
    imports: [
        CommonModule,
        FlexLayoutModule,
        MatIconModule,
        MatButtonModule,
        CbPopupTipModule,
        CbClickModule
    ],
    exports: ButtonComponent
})
@CbDowngrades({
    components: [
        { selector: 'cb-button', component: ButtonComponent }
    ]
})
export class CbButtonModule { }

The code used to do the downgrade:

import { downgradeComponent, downgradeInjectable } from '@angular/upgrade/static';
import { ClassCtor } from '../types/classctor.type';
import { NGJS_APP_NAME } from '../declarations/app.constants';
import { kebabCaseToCamelCase } from 'cb-hub-lib';

const DOWNGRADE_MODULE = angular.module(NGJS_APP_NAME);

function cbDowngradeComponent(ngJsSelector: string, componentClass: ClassCtor): void {
    DOWNGRADE_MODULE
        .directive(
            ngJsSelector,
            downgradeComponent({ component: componentClass })
        );
}

function cbDowngradeInjectable(ngJsInjectionToken: string, injectableClass: ClassCtor): void {
    DOWNGRADE_MODULE
        .factory(ngJsInjectionToken, downgradeInjectable(injectableClass));
}

function cbDowngradeComponents(components: CbDowngradeComponent[] = []): void {
    components.forEach((component) => {
        const camelCaseSelector = kebabCaseToCamelCase(component.selector);
        cbDowngradeComponent(camelCaseSelector, component.component);
    });
}

function cbDowngradeInjectables(injectables: (ClassCtor | CbDowngradeInjectable)[] = []): void {
    injectables.forEach((injectable) => {
        if ((injectable as ClassCtor).name) {
            const injectableCtor = (injectable as ClassCtor);
            cbDowngradeInjectable(injectableCtor.name, injectableCtor);
        } else {
            const injectableConfig = (injectable as CbDowngradeInjectable);
            cbDowngradeInjectable(injectableConfig.token, injectableConfig.injectable);
        }
    });
}
interface CbDowngrades {
    components?: CbDowngradeComponent[];
    injectables?: CbDowngradeInjectable[];
}

interface CbDowngradeInjectable {
    /** ThisShouldBePascalCase */
    token: string;
    injectable: ClassCtor;
}

interface CbDowngradeComponent {
    /** this-should-be-kebab-case */
    selector: string;
    component: ClassCtor;
}

/** Decorate your modules with this decorator to downgrade any components or injectables for usage in angularjs
 */
export function CbDowngrades(cbDowngrades: CbDowngrades): ClassDecorator {
    return (constructor: Function) => {
        cbDowngradeComponents(cbDowngrades.components);
        cbDowngradeInjectables(cbDowngrades.injectables);
    };
}
Ken White
  • 123,280
  • 14
  • 225
  • 444
BeniaminoBaggins
  • 11,202
  • 41
  • 152
  • 287
  • Hi @BeniaminoBaggins, you're using the "single-slot content projection": https://angular.io/guide/content-projection#single-slot-content-projection. I guess you're using your with a – Janos Vinceller Oct 03 '21 at 21:49
  • Hi @JanosVinceller, I have now added the produced html to the bottom of the question. Also see "using it:" to see what I am passing into the `ng-content`. Also I have simplified the html template which still produces the error, and yes the html template has – BeniaminoBaggins Oct 03 '21 at 21:57

0 Answers0