6 years later, it looks like these suggestions here are still valid.
For my edge case, a combination of these solutions worked out: I am just interested if in my custom component the developer used the default provided buttons, or custom buttons.
So I am using the code as mentioned before
(cdkObserveContent)="onContentChange($event)"
to get informed whenever the node changes and also the
@ViewChild('templateRef') templateRef: ElementRef;
to see actually, if the ng-content is used at all (contains anything). The benefit is, it even works with some attribute/content in the ng-content changes <3
Here comes a full example with signals and flow-control, ready for the PushStrategy (tested with angular18)
Together it looks like this in the .html part
<div class="my-wrapper"> @if (!numberOfCustomButtons()) { <span class="default-buttons"> <button (click)="cancelAction.emit()">Cancel</button> <button (click)="saveAction.emit()">Save</button> </span> } <span #customButtonsWrapper (cdkObserveContent)="onContentChange()" [class.hidden]="!numberOfCustomButtons()"> <ng-content/> </span> </div>
Here comes the .ts part
@Component({ selector: "myButtonBar", templateUrl: "./myButtonBar.component.html", styleUrls: ["./myButtonBar.component.scss"], standalone: true, imports: [ ObserversModule, ... ], changeDetection: ChangeDetectionStrategy.OnPush, }) export class MyButtonBarComponent { private myCustomButtonsWrapper: Signal<ElementRef> = viewChild<ElementRef>("customButtonsWrapper"); protected numberOfCustomButtons: WritableSignal<number> = signal<number>(0); cancelAction: OutputEmitterRef<void> = output<void>(); saveAction: OutputEmitterRef<void> = output<void>(); onContentChange(): void { this.numberOfCustomButtons.set(this.myCustomButtonsWrapper().nativeElement.children.length); } // Also initialize the default number of custom buttons to get rid of initialization issues, when custom buttons should be used ngOnInit(): void { this.numberOfCustomButtons.set(this.myCustomButtonsWrapper().nativeElement.children.length); } }
As you don't wanted style issues in the default case, just hide the wrapper via display:none in your .scss/.css part
.hidden: { display: none;}
elementsarray always points to the same object in memory, regardless whether its contents change, so you cannot just useonChange(). UseIterableDiffers()as explained in the linked answer.