Skip to content

Commit c8724d5

Browse files
Merge pull request #2220 from IDEMSInternational/feat/data-items-eval-context
feat: add data-items eval context fields
2 parents 2aa5284 + 5ceadad commit c8724d5

File tree

4 files changed

+67
-24
lines changed

4 files changed

+67
-24
lines changed

packages/data-models/flowTypes.ts

+11-1
Original file line numberDiff line numberDiff line change
@@ -337,11 +337,21 @@ export namespace FlowTypes {
337337
/** Keep a list of dynamic dependencies used within a template, by reference (e.g. {@local.var1 : ["text_1"]}) */
338338
_dynamicDependencies?: { [reference: string]: string[] };
339339
_translatedFields?: { [field: string]: any };
340-
_evalContext?: { itemContext: any }; // force specific context variables when calculating eval statements (such as loop items)
340+
_evalContext?: { itemContext: TemplateRowItemEvalContext }; // force specific context variables when calculating eval statements (such as loop items)
341341
__EMPTY?: any; // empty cells (can be removed after pr 679 merged)
342342
}
343343
export type IDynamicField = { [key: string]: IDynamicField | TemplateRowDynamicEvaluator[] };
344344

345+
export interface TemplateRowItemEvalContext {
346+
// item metadata
347+
_id: string;
348+
_index: number;
349+
_first: boolean;
350+
_last: boolean;
351+
// item data
352+
[key: string]: any;
353+
}
354+
345355
type IDynamicPrefix = IAppConfig["DYNAMIC_PREFIXES"][number];
346356

347357
/** Data passed back from regex match, e.g. expression @local.someField => type:local, fieldName: someField */

src/app/shared/components/template/components/data-items/data-items.component.ts

+30-16
Original file line numberDiff line numberDiff line change
@@ -74,34 +74,48 @@ export class TmplDataItemsComponent extends TemplateBaseComponent implements OnD
7474
parameterList: any
7575
) {
7676
const parsedItemDataList = await this.parseDataList(itemDataList);
77-
const itemRows = new ItemProcessor(parsedItemDataList, parameterList).process(rows);
78-
const parsedItemRows = await this.hackProcessRows(itemRows);
79-
const replacedActionRows = this.setActionListMeta(parsedItemRows, parsedItemDataList);
77+
const { itemRows, itemData } = new ItemProcessor(parsedItemDataList, parameterList).process(
78+
rows
79+
);
80+
const itemRowsWithMeta = this.setItemMeta(itemRows, itemData);
81+
82+
const parsedItemRows = await this.hackProcessRows(itemRowsWithMeta);
8083
// TODO - deep diff and only update changed
81-
this.itemRows = replacedActionRows;
84+
this.itemRows = parsedItemRows;
8285
this.cdr.markForCheck();
8386
}
8487

8588
/**
86-
* Update any action list set_item args to contain name of current data list and item id
87-
* and set_items action to include all currently displayed rows
89+
* Update item dynamic evaluation context and action lists to include relevant
90+
* item data
91+
* @param templateRows List of template rows generated from itemData by item processor
92+
* @param itemData List of original item data used to create item rows (post operations such as filter/sort)
8893
* */
89-
private setActionListMeta(
90-
rows: FlowTypes.TemplateRow[],
91-
dataList: {
92-
[index: string]: any;
93-
}
94-
) {
95-
return rows.map((r) => {
94+
private setItemMeta(templateRows: FlowTypes.TemplateRow[], itemData: FlowTypes.Data_listRow[]) {
95+
const lastItemIndex = itemData.length - 1;
96+
const itemDataIDs = itemData.map((item) => item.id);
97+
// Reassign metadata fields previously assigned by item as rendered row count may have changed
98+
return templateRows.map((r) => {
99+
// Map the row item context to the original list of items rendered to know position in item list.
100+
const itemIndex = itemDataIDs.indexOf(r._evalContext.itemContext._id);
101+
// Update metadata fields as _first, _last and index may have changed based on dynamic updates
102+
r._evalContext.itemContext = {
103+
...r._evalContext.itemContext,
104+
_index: itemIndex,
105+
_first: itemIndex === 0,
106+
_last: itemIndex === lastItemIndex,
107+
};
108+
// Update any action list set_item args to contain name of current data list and item id
109+
// and set_items action to include all currently displayed rows
96110
if (r.action_list) {
97111
r.action_list = r.action_list.map((a) => {
98112
if (a.action_id === "set_item") {
99-
a.args = [this.dataListName, r._evalContext.itemContext.id];
113+
a.args = [this.dataListName, r._evalContext.itemContext._id];
100114
}
101115
if (a.action_id === "set_items") {
102116
// TODO - add a check for @item refs and replace parameter list with correct values
103117
// for each individual item (default will be just to pick the first)
104-
a.args = [this.dataListName, Object.values(dataList).map((v) => v.id)];
118+
a.args = [this.dataListName, itemDataIDs];
105119
}
106120
return a;
107121
});
@@ -114,7 +128,7 @@ export class TmplDataItemsComponent extends TemplateBaseComponent implements OnD
114128
* Ordinarily rows would be processed as part of the regular template processing,
115129
* however this must be bypassed to allow multiple reprocessing on item updates
116130
*/
117-
private async hackProcessRows(rows) {
131+
private async hackProcessRows(rows: FlowTypes.TemplateRow[]) {
118132
const processor = new TemplateRowService(this.injector, {
119133
name: "",
120134
template: {

src/app/shared/components/template/processors/item.ts

+25-6
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ export class ItemProcessor {
1515
const pipedData = this.pipeData(data, this.parameterList);
1616
const itemRows = this.generateLoopItemRows(templateRows, pipedData);
1717
const parsedItemRows = this.hackSetNestedName(itemRows);
18-
return parsedItemRows;
18+
// Return both rows for rendering and list of itemData used (post pipe operations)
19+
return { itemRows: parsedItemRows, itemData: pipedData };
1920
}
2021

2122
private pipeData(data: any[], parameter_list: any) {
@@ -32,13 +33,31 @@ export class ItemProcessor {
3233
/**
3334
* Takes a row and list of items to iterate over, creating a new entry for each item with
3435
* the same row values but a unique evaluation context for populating dynamic variables from the item
35-
* @param items - list of items to iterate over
36+
* @param templateRows - list of template rows to iterate over for each item
37+
* @param itemData - list of items to iterate over
3638
*/
37-
private generateLoopItemRows(templateRows: FlowTypes.TemplateRow[], items: any[]) {
39+
private generateLoopItemRows(
40+
templateRows: FlowTypes.TemplateRow[],
41+
itemData: FlowTypes.Data_listRow[]
42+
) {
3843
const loopItemRows: FlowTypes.TemplateRow[] = [];
39-
for (const [index, item] of Object.entries(items)) {
40-
item._index = index;
41-
const evalContext = { itemContext: item };
44+
const lastItemIndex = itemData.length - 1;
45+
for (const [indexKey, item] of Object.entries(itemData)) {
46+
const _index = Number(indexKey);
47+
const itemContextMeta: FlowTypes.TemplateRowItemEvalContext = {
48+
_index,
49+
_id: item["id"],
50+
_first: _index === 0,
51+
_last: _index === lastItemIndex,
52+
};
53+
const evalContext: FlowTypes.TemplateRow["_evalContext"] = {
54+
itemContext: {
55+
...item,
56+
...itemContextMeta,
57+
// Assign row dynamic context to allow reference to rendered row metadata, including
58+
// item index, id, and whether first or last item in list
59+
},
60+
};
4261
for (const r of templateRows) {
4362
const itemRow = this.setRecursiveRowEvalContext(r, evalContext);
4463
loopItemRows.push(itemRow);

src/app/shared/components/template/services/instance/template-row.service.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,7 @@ export class TemplateRowService extends SyncServiceBase {
284284
const itemDataList: { [id: string]: any } = row.value;
285285
const parameterList = this.hackUnparseItemParameterList(row);
286286
const parsedItemDataList = await this.parseDataList(itemDataList);
287-
const itemRows = new ItemProcessor(parsedItemDataList, parameterList).process(row.rows);
287+
const { itemRows } = new ItemProcessor(parsedItemDataList, parameterList).process(row.rows);
288288
const parsedItemRows = await this.processRows(itemRows, isNestedTemplate, row.name);
289289
return parsedItemRows;
290290
}

0 commit comments

Comments
 (0)