Skip to content

feat(table): enable multiple data rows #11116

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/cdk/table/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ ng_module(
module_name = "@angular/cdk/table",
deps = [
"//src/cdk/collections",
"//src/cdk/coercion",
"@rxjs",
],
tsconfig = "//src/cdk:tsconfig-build.json",
Expand Down
51 changes: 51 additions & 0 deletions src/cdk/table/render-rows.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Rendering Data Rows

The table's primary responsibility is to render rows of cells. The types of rows that may be rendered are header,
footer, and data rows. This document focuses on how the table tries to efficienctly render the data rows.

## Background

Each table's template is defined as a set of row and column templates. The row template defines the template that should
be rendered for a header, footer, or data row. The column templates include the cell templates that will be inserted
into each rendered row.

Each data object may be rendered with one or more row templates. When new data in provided to the table, the table
determines which rows need to be rendered. In order to be efficient, the table attempts to understand how the new list
of rendered rows differs from the previous list of rendered rows so that it can re-use the current list of rendered rows
if possible.

## Rendering

Each time data is provided, the table needs to create the list of rows that will be rendered and keep track of which
data object will be provided as context for each row. For each item in the list, this pair is combined into an object
that uses the `RenderRow` interface. The interface also helps keep track of the data object's index in the provided
data array input.

```ts
export interface RenderRow<T> {
data: T;
dataIndex: number;
rowDef: CdkRowDef<T>;
}
```

When possible, `RenderRow` objects are re-used from the previous rendering. That is, if a particular data object and row
template pairing was previously rendered, it should be used for the new list as well. This makes sure that the
differ can use check-by-reference logic to find the changes between two lists. Note that if a `RenderRow` object is
reused, it should be updated with the correct data index, in case it has moved since last used.

Once the list of `RenderRow` objects has been created, it should be compared to the previous list of `RenderRow`
objects to find the difference in terms of inserts/deletions/moves. This is trivially done using the `IterableDiffer`
logic provided by Angular Core.

Finally, the table uses the list of operations and manipulates the rows through add/remove/move operations.

## Caching `RenderRow` objects

Each `RenderRow` should be cached such that it is a constant-time lookup and retrieval based on the data object and
row template pairing.

In order to achieve this, the cache is built as a map of maps where the key of the outer map is the data object and
the key of the inner map is the row template. The value of the inner map should be an array of the matching cached
`RenderRow` objects that were previously rendered.

35 changes: 33 additions & 2 deletions src/cdk/table/row.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,12 +130,12 @@ export class CdkRowDef<T> extends BaseRowDef {
}
}

/** Context provided to the row cells */
/** Context provided to the row cells when `multiTemplateDataRows` is false */
export interface CdkCellOutletRowContext<T> {
/** Data for the row that this cell is located within. */
$implicit?: T;

/** Index location of the row that this cell is located within. */
/** Index of the data object in the provided data array. */
index?: number;

/** Length of the number of total rows. */
Expand All @@ -154,6 +154,37 @@ export interface CdkCellOutletRowContext<T> {
odd?: boolean;
}

/**
* Context provided to the row cells when `multiTemplateDataRows` is true. This context is the same
* as CdkCellOutletRowContext except that the single `index` value is replaced by `dataIndex` and
* `renderIndex`.
*/
export interface CdkCellOutletMultiRowContext<T> {
/** Data for the row that this cell is located within. */
$implicit?: T;

/** Index of the data object in the provided data array. */
dataIndex?: number;

/** Index location of the rendered row that this cell is located within. */
renderIndex?: number;

/** Length of the number of total rows. */
count?: number;

/** True if this cell is contained in the first row. */
first?: boolean;

/** True if this cell is contained in the last row. */
last?: boolean;

/** True if this cell is contained in a row with an even-numbered index. */
even?: boolean;

/** True if this cell is contained in a row with an odd-numbered index. */
odd?: boolean;
}

/**
* Outlet for rendering cells inside of a row or header row.
* @docs-private
Expand Down
5 changes: 3 additions & 2 deletions src/cdk/table/table-errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,9 @@ export function getTableMultipleDefaultRowDefsError() {
* Returns an error to be thrown when there are no matching row defs for a particular set of data.
* @docs-private
*/
export function getTableMissingMatchingRowDefError() {
return Error(`Could not find a matching row definition for the provided row data.`);
export function getTableMissingMatchingRowDefError(data: any) {
return Error(`Could not find a matching row definition for the` +
`provided row data: ${JSON.stringify(data)}`);
}

/**
Expand Down
Loading