@@ -117,23 +117,7 @@ export class DatatableComponent<TRow extends Row = any>
117117 /**
118118 * Rows that are displayed in the table.
119119 */
120- @Input ( ) set rows ( val : ( TRow | undefined ) [ ] | null | undefined ) {
121- this . _rows = val ?? [ ] ;
122- if ( val ) {
123- // This will ensure that datatable detects changes on doing like this rows = [...rows];
124- if ( val . length ) {
125- this . rowDiffer . diff ( [ ] ) ;
126- }
127- this . _internalRows = [ ...val ] ;
128- }
129- }
130-
131- /**
132- * Gets the rows.
133- */
134- get rows ( ) : ( TRow | undefined ) [ ] {
135- return this . _rows ;
136- }
120+ readonly rows = input < ( TRow | undefined ) [ ] | null | undefined > ( ) ;
137121
138122 /**
139123 * This attribute allows the user to set the name of the column to group the data with
@@ -143,7 +127,7 @@ export class DatatableComponent<TRow extends Row = any>
143127 this . _groupRowsBy = val ;
144128 if ( this . _groupRowsBy ) {
145129 // creates a new array with the data grouped
146- this . groupedRows = this . groupArrayBy ( this . _rows , this . _groupRowsBy ) ;
130+ this . groupedRows = this . groupArrayBy ( this . rows ( ) ?? [ ] , this . _groupRowsBy ) ;
147131 }
148132 }
149133 }
@@ -670,15 +654,15 @@ export class DatatableComponent<TRow extends Row = any>
670654 */
671655 get allRowsSelected ( ) : boolean {
672656 const selected = this . selected ( ) ;
673- let allRowsSelected = this . rows && selected && selected . length === this . rows . length ;
657+ let allRowsSelected = this . rows ( ) && selected && selected . length === this . rows ( ) ! . length ;
674658
675659 if ( this . bodyComponent && this . selectAllRowsOnPage ( ) ) {
676660 const indexes = this . bodyComponent . indexes ;
677661 const rowsOnPage = indexes ( ) . last - indexes ( ) . first ;
678662 allRowsSelected = selected . length === rowsOnPage ;
679663 }
680664
681- return selected && this . rows ?. length !== 0 && allRowsSelected ;
665+ return ! ! ( selected && this . rows ( ) ?. length !== 0 && allRowsSelected ) ;
682666 }
683667
684668 element = inject < ElementRef < HTMLElement > > ( ElementRef ) . nativeElement ;
@@ -687,12 +671,34 @@ export class DatatableComponent<TRow extends Row = any>
687671 bodyHeight ! : number ;
688672 rowCount = 0 ;
689673 rowDiffer : IterableDiffer < TRow | undefined > = inject ( IterableDiffers ) . find ( [ ] ) . create ( ) ;
674+ private readonly _rowDiffCount = signal ( 0 ) ;
690675
691676 _offsetX = 0 ;
692677 _offset = 0 ;
693- _rows : ( TRow | undefined ) [ ] = [ ] ;
694678 _groupRowsBy ?: keyof TRow ;
695- _internalRows : ( TRow | undefined ) [ ] = [ ] ;
679+ // TODO: should be a computed
680+ readonly _internalRows = linkedSignal ( ( ) => {
681+ this . _rowDiffCount ( ) ; // to trigger recalculation when row differ detects a change
682+ let rows = this . rows ( ) ?. slice ( ) ?? [ ] ;
683+
684+ const sorts = this . sorts ( ) ;
685+ if ( sorts . length && ! this . externalSorting ( ) ) {
686+ rows = sortRows ( rows , this . _internalColumns ( ) , this . sorts ( ) ) ;
687+ } else if ( this . treeFromRelation ( ) && this . treeToRelation ( ) ) {
688+ rows = groupRowsByParents (
689+ rows ,
690+ optionalGetterForProp ( this . treeFromRelation ( ) ) ,
691+ optionalGetterForProp ( this . treeToRelation ( ) )
692+ ) ;
693+ }
694+
695+ if ( this . ghostLoadingIndicator ( ) && this . scrollbarV ( ) && ! this . externalPaging ( ) ) {
696+ // in case where we don't have predefined total page length
697+ rows . push ( undefined ) ; // undefined row will render ghost cell row at the end of the page
698+ }
699+
700+ return rows ;
701+ } ) ;
696702 // TODO: consider removing internal modifications of the columns.
697703 // This requires a different strategy for certain properties like width.
698704 readonly _internalColumns = linkedSignal ( ( ) =>
@@ -721,26 +727,7 @@ export class DatatableComponent<TRow extends Row = any>
721727 private readonly _rowInitDone = signal ( false ) ;
722728
723729 constructor ( ) {
724- // Effect to handle column template changes
725730 // TODO: This should be a computed signal.
726- effect ( ( ) => {
727- const columns = this . columnTemplates ( ) . map ( c => c . column ( ) ) ;
728- // Ensure that we do not listen to other properties (yet).
729- untracked ( ( ) => this . translateColumns ( columns ) ) ;
730- } ) ;
731-
732- // Effect to handle ghost loading indicator changes
733- effect ( ( ) => {
734- const ghostLoading = this . ghostLoadingIndicator ( ) ;
735- // Use untracked to only subscribe to ghostLoadingIndicator changes
736- untracked ( ( ) => {
737- if ( ghostLoading && this . scrollbarV ( ) && ! this . externalPaging ( ) ) {
738- // in case where we don't have predefined total page length
739- this . rows = [ ...this . rows , undefined ] ; // undefined row will render ghost cell row at the end of the page
740- }
741- } ) ;
742- } ) ;
743-
744731 // Effect to handle recalculate when limit or count changes
745732 effect ( ( ) => {
746733 // Track limit and count changes
@@ -766,29 +753,21 @@ export class DatatableComponent<TRow extends Row = any>
766753 * Lifecycle hook that is called when Angular dirty checks a directive.
767754 */
768755 ngDoCheck ( ) : void {
769- const rowDiffers = this . rowDiffer . diff ( this . rows ) ;
756+ const rowDiffers = this . rowDiffer . diff ( this . rows ( ) ) ;
770757 if ( rowDiffers || this . disableRowCheck ( ) ) {
758+ this . _rowDiffCount . update ( count => count + 1 ) ;
771759 // we don't sort again when ghost loader adds a dummy row
772760 if (
773761 ! this . ghostLoadingIndicator ( ) &&
774762 ! this . externalSorting ( ) &&
775763 this . _internalColumns ( ) . length
776764 ) {
777765 this . sortInternalRows ( ) ;
778- } else {
779- this . _internalRows = [ ...this . rows ] ;
780766 }
781767
782- // auto group by parent on new update
783- this . _internalRows = groupRowsByParents (
784- this . _internalRows ,
785- optionalGetterForProp ( this . treeFromRelation ( ) ) ,
786- optionalGetterForProp ( this . treeToRelation ( ) )
787- ) ;
788-
789768 if ( this . _groupRowsBy && rowDiffers ) {
790769 // If a column has been specified in _groupRowsBy create a new array with the data grouped by that row
791- this . groupedRows = this . groupArrayBy ( this . _rows , this . _groupRowsBy ) ;
770+ this . groupedRows = this . groupArrayBy ( this . rows ( ) ?? [ ] , this . _groupRowsBy ) ;
792771 }
793772 if ( rowDiffers ) {
794773 queueMicrotask ( ( ) => {
@@ -846,18 +825,6 @@ export class DatatableComponent<TRow extends Row = any>
846825 }
847826 } ;
848827
849- /**
850- * Translates the templates to the column objects
851- */
852- translateColumns ( columns : TableColumn < TRow > [ ] ) {
853- if ( columns . length ) {
854- if ( ! this . externalSorting ( ) && this . rows ?. length ) {
855- this . sortInternalRows ( ) ;
856- }
857- this . cd . markForCheck ( ) ;
858- }
859- }
860-
861828 /**
862829 * Creates a map with the data grouped by the user choice of grouping index
863830 *
@@ -1059,12 +1026,7 @@ export class DatatableComponent<TRow extends Row = any>
10591026 }
10601027
10611028 // otherwise use row length
1062- if ( this . rows ) {
1063- return this . rows . length ;
1064- }
1065-
1066- // other empty :(
1067- return 0 ;
1029+ return this . rows ( ) ?. length ?? 0 ;
10681030 }
10691031
10701032 /**
@@ -1074,10 +1036,8 @@ export class DatatableComponent<TRow extends Row = any>
10741036 if ( ! this . externalPaging ( ) ) {
10751037 if ( this . groupedRows ) {
10761038 return this . groupedRows . length ;
1077- } else if ( this . treeFromRelation ( ) != null && this . treeToRelation ( ) != null ) {
1078- return this . _internalRows . length ;
10791039 } else {
1080- return this . rows . length ;
1040+ return this . _internalRows ( ) . length ;
10811041 }
10821042 }
10831043
@@ -1188,13 +1148,6 @@ export class DatatableComponent<TRow extends Row = any>
11881148 this . sortInternalRows ( ) ;
11891149 }
11901150
1191- // auto group by parent on new update
1192- this . _internalRows = groupRowsByParents (
1193- this . _internalRows ,
1194- optionalGetterForProp ( this . treeFromRelation ( ) ) ,
1195- optionalGetterForProp ( this . treeToRelation ( ) )
1196- ) ;
1197-
11981151 // Always go to first page when sorting to see the newly sorted data
11991152 this . offset = 0 ;
12001153 this . bodyComponent . updateOffsetY ( this . offset ) ;
@@ -1221,19 +1174,23 @@ export class DatatableComponent<TRow extends Row = any>
12211174
12221175 // do the opposite here
12231176 if ( ! allSelected ) {
1224- this . selected . set ( this . _internalRows . slice ( first , last ) . filter ( row => ! ! row ) as TRow [ ] ) ;
1177+ this . selected . set (
1178+ this . _internalRows ( )
1179+ . slice ( first , last )
1180+ . filter ( row => ! ! row ) as TRow [ ]
1181+ ) ;
12251182 } else {
12261183 this . selected . set ( [ ] ) ;
12271184 }
12281185 } else {
12291186 let relevantRows : TRow [ ] ;
12301187 const disableRowCheckFn = this . disableRowCheck ( ) ;
12311188 if ( disableRowCheckFn ) {
1232- relevantRows = this . rows . filter (
1189+ relevantRows = ( this . rows ( ) ?? [ ] ) . filter (
12331190 ( row => row && ! disableRowCheckFn ( row ) ) as ( row : TRow | undefined ) => row is TRow
12341191 ) ;
12351192 } else {
1236- relevantRows = this . rows . filter ( row => ! ! row ) ;
1193+ relevantRows = ( this . rows ( ) ?? [ ] ) . filter ( row => ! ! row ) ;
12371194 }
12381195 // before we splice, chk if we currently have all selected
12391196 const allSelected = this . selected ( ) . length === relevantRows . length ;
@@ -1264,7 +1221,9 @@ export class DatatableComponent<TRow extends Row = any>
12641221 const row = event . row ;
12651222 // TODO: For duplicated items this will not work
12661223 const treeToRel = this . treeToRelation ( ) ;
1267- const rowIndex = this . _rows . findIndex ( r => r && r [ treeToRel ! ] === event . row [ treeToRel ! ] ) ;
1224+ const rowIndex = ( this . rows ( ) ?? [ ] ) . findIndex (
1225+ r => r && r [ treeToRel ! ] === event . row [ treeToRel ! ]
1226+ ) ;
12681227 this . treeAction . emit ( { row, rowIndex } ) ;
12691228 }
12701229
@@ -1273,32 +1232,17 @@ export class DatatableComponent<TRow extends Row = any>
12731232 }
12741233
12751234 private sortInternalRows ( ) : void {
1276- // if there are no sort criteria we reset the rows with original rows
1277- if ( ! this . sorts ( ) ?. length ) {
1278- this . _internalRows = this . _rows ;
1279- // if there is any tree relation then re-group rows accordingly
1280- if ( this . treeFromRelation ( ) && this . treeToRelation ( ) ) {
1281- this . _internalRows = groupRowsByParents (
1282- this . _internalRows ,
1283- optionalGetterForProp ( this . treeFromRelation ( ) ) ,
1284- optionalGetterForProp ( this . treeToRelation ( ) )
1285- ) ;
1286- }
1287- }
12881235 if ( this . groupedRows ?. length ) {
12891236 const sortOnGroupHeader = this . sorts ( ) ?. find (
12901237 sortColumns => sortColumns . prop === this . _groupRowsBy
12911238 ) ;
1292- this . groupedRows = this . groupArrayBy ( this . _rows , this . _groupRowsBy ! ) ;
1239+ this . groupedRows = this . groupArrayBy ( this . rows ( ) ?? [ ] , this . _groupRowsBy ! ) ;
12931240 this . groupedRows = sortGroupedRows (
12941241 this . groupedRows ,
12951242 this . _internalColumns ( ) ,
12961243 this . sorts ( ) ,
12971244 sortOnGroupHeader
12981245 ) ;
1299- this . _internalRows = [ ...this . _internalRows ] ;
1300- } else {
1301- this . _internalRows = sortRows ( this . _internalRows , this . _internalColumns ( ) , this . sorts ( ) ) ;
13021246 }
13031247 }
13041248}
0 commit comments