Angular如何检测ng-content内组件数量并合并多列组件?
Merging into a Dynamic Column Row Component
Absolutely! You can combine your app-row-two and app-row-three components into a single dynamic component that automatically detects how many elements/components you've projected into it and wraps each in an x-col div. Here's how to do it:
Step 1: Create the Dynamic Component
First, generate a new component (let's call it app-dynamic-row). Replace its template and class with the following:
Component Template (dynamic-row.component.html)
<div #columnContainer> <ng-content></ng-content> </div>
Component Class (dynamic-row.component.ts)
import { Component, ViewChild, ElementRef, AfterContentInit, OnDestroy } from '@angular/core'; @Component({ selector: 'app-dynamic-row', templateUrl: './dynamic-row.component.html', styleUrls: ['./dynamic-row.component.css'] }) export class DynamicRowComponent implements AfterContentInit, OnDestroy { @ViewChild('columnContainer') private columnContainer!: ElementRef<HTMLDivElement>; private mutationObserver?: MutationObserver; ngAfterContentInit(): void { // Initial wrap of projected elements this.wrapElementsInColumns(); // Set up observer to handle dynamic changes (adding/removing elements) this.mutationObserver = new MutationObserver((mutations) => { if (mutations.some(m => m.addedNodes.length || m.removedNodes.length)) { this.wrapElementsInColumns(); } }); this.mutationObserver.observe(this.columnContainer.nativeElement, { childList: true, subtree: false }); } ngOnDestroy(): void { // Clean up observer to prevent memory leaks this.mutationObserver?.disconnect(); } private wrapElementsInColumns(): void { const container = this.columnContainer.nativeElement; // Get all elements that aren't already wrapped in x-col const unwrappedElements = Array.from(container.children).filter( el => !el.hasAttribute('x-col') ); // Remove unwrapped elements temporarily unwrappedElements.forEach(el => container.removeChild(el)); // Wrap each element in an x-col div and re-add to container unwrappedElements.forEach(el => { const colDiv = document.createElement('div'); colDiv.setAttribute('x-col', ''); colDiv.appendChild(el); container.appendChild(colDiv); }); } }
Step 2: Use the Component
Now you can use this component without any slot attributes—just place your elements/components directly inside it:
<!-- 2-column layout --> <app-dynamic-row> <div>Content for first column</div> <app-my-custom-component></app-my-custom-component> </app-dynamic-row> <!-- 3-column layout --> <app-dynamic-row> <p>Column 1</p> <div>Column 2 content</div> <app-another-component></app-another-component> </app-dynamic-row> <!-- Works with any number of columns! --> <app-dynamic-row> <span>Col 1</span> <span>Col 2</span> <span>Col 3</span> <span>Col 4</span> </app-dynamic-row>
How It Works
- Content Projection: The
<ng-content>tag captures all elements you place insideapp-dynamic-row. - Initial Setup: In
ngAfterContentInit, we first wrap all projected elements inx-coldivs. - Dynamic Updates: We use a
MutationObserverto watch for changes in the container's children (like adding or removing elements after initialization). When changes happen, we re-wrap any new unwrapped elements. - Avoid Duplicate Wrapping: We filter out elements that are already in an
x-coldiv to prevent nesting them multiple times.
This approach is flexible, works with both plain HTML elements and Angular components, and adapts automatically to the number of items you project.
内容的提问来源于stack exchange,提问作者Vla Mai
相关产品推荐
相关产品推荐

