88
99import { _IdGenerator } from '@angular/cdk/a11y' ;
1010import {
11+ afterRenderEffect ,
1112 booleanAttribute ,
1213 computed ,
1314 contentChildren ,
@@ -17,6 +18,7 @@ import {
1718 input ,
1819 model ,
1920 Signal ,
21+ Renderer2 ,
2022} from '@angular/core' ;
2123import { Directionality } from '@angular/cdk/bidi' ;
2224import { GridCellPattern } from '../private' ;
@@ -41,26 +43,11 @@ import {GRID_CELL, GRID_ROW} from './grid-tokens';
4143@Directive ( {
4244 selector : '[ngGridCell]' ,
4345 exportAs : 'ngGridCell' ,
44- host : {
45- '[attr.role]' : 'role()' ,
46- '[attr.id]' : '_pattern.id()' ,
47- '[attr.rowspan]' : '_pattern.rowSpan()' ,
48- '[attr.colspan]' : '_pattern.colSpan()' ,
49- '[attr.data-active]' : 'active()' ,
50- '[attr.data-anchor]' : '_pattern.anchor()' ,
51- '[attr.aria-disabled]' : '_pattern.disabled()' ,
52- '[attr.aria-rowspan]' : '_pattern.rowSpan()' ,
53- '[attr.aria-colspan]' : '_pattern.colSpan()' ,
54- '[attr.aria-rowindex]' : '_pattern.ariaRowIndex()' ,
55- '[attr.aria-colindex]' : '_pattern.ariaColIndex()' ,
56- '[attr.aria-selected]' : '_pattern.ariaSelected()' ,
57- '[tabindex]' : '_tabIndex()' ,
58- } ,
5946 providers : [ { provide : GRID_CELL , useExisting : GridCell } ] ,
6047} )
6148export class GridCell {
62- /** A reference to the host element. */
6349 private readonly _elementRef = inject ( ElementRef ) ;
50+ private readonly _renderer = inject ( Renderer2 ) ;
6451
6552 /** A reference to the host element. */
6653 readonly element = this . _elementRef . nativeElement as HTMLElement ;
@@ -136,7 +123,39 @@ export class GridCell {
136123 element : ( ) => this . element ,
137124 } ) ;
138125
139- constructor ( ) { }
126+ constructor ( ) {
127+ // Note: we don't go through host bindings for these, because the
128+ // effect allows us to batch the reads together which drastically
129+ // improves rendering performance in large grids (see #32759).
130+ afterRenderEffect ( {
131+ write : ( ) => {
132+ const { _pattern : pattern , _toggleAttribute : toggle } = this ;
133+ const rowSpan = pattern . rowSpan ( ) ;
134+ const colSpan = pattern . colSpan ( ) ;
135+ toggle ( 'role' , this . role ( ) ) ;
136+ toggle ( 'id' , pattern . id ( ) ) ;
137+ toggle ( 'rowspan' , rowSpan ) ;
138+ toggle ( 'colspan' , rowSpan ) ;
139+ toggle ( 'aria-rowspan' , rowSpan ) ;
140+ toggle ( 'aria-colspan' , colSpan ) ;
141+ toggle ( 'data-active' , this . active ( ) ) ;
142+ toggle ( 'data-anchor' , pattern . anchor ( ) ) ;
143+ toggle ( 'aria-disabled' , pattern . disabled ( ) ) ;
144+ toggle ( 'aria-rowindex' , pattern . ariaRowIndex ( ) ) ;
145+ toggle ( 'aria-colindex' , pattern . ariaColIndex ( ) ) ;
146+ toggle ( 'aria-selected' , pattern . ariaSelected ( ) ) ;
147+ toggle ( 'tabindex' , this . _tabIndex ( ) ) ;
148+ } ,
149+ } ) ;
150+ }
151+
152+ private _toggleAttribute = ( name : string , value : unknown ) => {
153+ if ( value == null ) {
154+ this . _renderer . removeAttribute ( this . element , name ) ;
155+ } else {
156+ this . _renderer . setAttribute ( this . element , name , value as string ) ;
157+ }
158+ } ;
140159
141160 /** Gets the cell widget pattern for a given element. */
142161 private _getWidget ( element : Element | null | undefined ) : any | undefined {
0 commit comments