Browse Source

Allow nested collections

pull/6359/head
mohamedsalem401 1 year ago
parent
commit
09da4468fe
  1. 145
      packages/core/src/data_sources/model/collection_component/CollectionComponent.ts
  2. 31
      packages/core/src/dom_components/model/Component.ts

145
packages/core/src/data_sources/model/collection_component/CollectionComponent.ts

@ -23,26 +23,26 @@ interface CollectionConfig {
// Provides access to collection state variables during iteration. // Provides access to collection state variables during iteration.
interface CollectionStateVariables { interface CollectionStateVariables {
currentIndex: number; // Current collection index current_index: number; // Current collection index
firstIndex: number; // Start index first_index: number; // Start index
currentItem: any; // Current item in the iteration current_item: any; // Current item in the iteration
lastIndex: number; // End index last_index: number; // End index
collectionName?: string; // Optional name of the collection collection_name?: string; // Optional name of the collection
totalItems: number; // Total number of items in the collection total_items: number; // Total number of items in the collection
remainingItems: number; // Remaining items in the collection remaining_items: number; // Remaining items in the collection
} }
// Defines the complete structure for a collection, including configuration and state variables. // Defines the complete structure for a collection, including configuration and state variables.
interface CollectionDefinition { interface CollectionDefinition {
type: typeof CollectionVariableType; type: typeof CollectionVariableType;
collectionName?: string; // Optional collection name collection_name?: string; // Optional collection name
config: CollectionConfig; // Loop configuration details config: CollectionConfig; // Loop configuration details
block: ComponentDefinition; // Component definition for each iteration block: ComponentDefinition; // Component definition for each iteration
} }
export default class CollectionComponent extends Component { export default class CollectionComponent extends Component {
constructor(props: CollectionDefinition & ComponentProperties, opt: ComponentOptions) { constructor(props: CollectionDefinition & ComponentProperties, opt: ComponentOptions) {
const { block, config } = props.collectionDefinition; const { collection_name, block, config } = props.collectionDefinition;
const { dataSource } = config; const { dataSource } = config;
let items: CollectionStateVariables[] = []; let items: CollectionStateVariables[] = [];
switch (true) { switch (true) {
@ -68,16 +68,30 @@ export default class CollectionComponent extends Component {
default: default:
} }
const components: ComponentDefinitionDefined[] = items.map((item: CollectionStateVariables, index) => resolveBlockValue({ const components: ComponentDefinitionDefined[] = items.map((item: CollectionStateVariables, index) => {
currentIndex: index, const innerMostCollectionItem = {
firstIndex: config.startIndex, collection_name,
currentItem: item, current_index: index,
lastIndex: config.endIndex, first_index: config.startIndex,
collectionName: props.collectionName, current_item: item,
totalItems: items.length, last_index: config.endIndex,
remainingItems: items.length - index, total_items: items.length,
}, block) remaining_items: items.length - index,
); };
const allCollectionItems = {
...props.collectionsItems,
[innerMostCollectionItem.collection_name ? innerMostCollectionItem.collection_name : 'innerMostCollectionItem']:
innerMostCollectionItem,
innerMostCollectionItem
}
let components = resolveBlockValues(allCollectionItems, block);
components['collectionsItems'] = allCollectionItems;
return components;
});
const conditionalCmptDef = { const conditionalCmptDef = {
...props, ...props,
type: CollectionVariableType, type: CollectionVariableType,
@ -117,59 +131,41 @@ function deepCloneObject<T extends Record<string, any> | null | undefined>(obj:
return clonedObj as T; return clonedObj as T;
} }
function resolveBlockValue(item: any, block: any): any { function resolveBlockValues(context: any, block: any): any {
console.log("🚀 ~ resolveBlockValues ~ context:", context)
const { innerMostCollectionItem } = context;
const clonedBlock = deepCloneObject(block); const clonedBlock = deepCloneObject(block);
if (typeof clonedBlock === 'object' && clonedBlock !== null) { if (typeof clonedBlock === 'object' && clonedBlock !== null) {
const stringifiedItem = JSON.stringify(item.currentItem); const blockKeys = Object.keys(clonedBlock);
const keys = Object.keys(clonedBlock);
for (const key of blockKeys) {
for (let i = 0; i < keys.length; i++) { let blockValue = clonedBlock[key];
const key = keys[i];
let value = clonedBlock[key]; if (typeof blockValue === 'object' && blockValue !== null) {
if (blockValue.type === 'parent-collection-variable') {
if (typeof value === 'object') { const collectionItem = blockValue.collection_name
if (value.type === 'parent-collection-variable') { ? context[blockValue.collection_name]
if (value.variable_type === 'current_item') { : innerMostCollectionItem;
if (!value.path) { if (!collectionItem) continue;
clonedBlock[key] = stringifiedItem;
} else { switch (blockValue.variable_type) {
const pathParts = value.path.split('.'); case 'current_item':
let resolvedValue = item.currentItem; clonedBlock[key] = blockValue.path
for (const part of pathParts) { ? resolvePathValue(collectionItem, blockValue.path)
if (resolvedValue && typeof resolvedValue === 'object' && resolvedValue.hasOwnProperty(part)) { : JSON.stringify(collectionItem);
resolvedValue = resolvedValue[part]; break;
} else { default:
resolvedValue = undefined; // Handle cases where the path doesn't exist clonedBlock[key] = collectionItem[blockValue.variable_type];
break; break; // Handle unexpected variable types gracefully
}
}
clonedBlock[key] = resolvedValue;
}
} else if (value.variable_type === 'current_index') {
clonedBlock[key] = String(item.currentIndex);
} else if (value.variable_type === 'first_index') {
clonedBlock[key] = String(item.firstIndex);
} else if (value.variable_type === 'last_index') {
clonedBlock[key] = String(item.lastIndex);
} else if (value.variable_type === 'collection_name') {
clonedBlock[key] = String(item.collectionName);
} else if (value.variable_type === 'total_items') {
clonedBlock[key] = String(item.totalItems);
} else if (value.variable_type === 'remaining_items') {
clonedBlock[key] = String(item.remainingItems);
} }
} else if (Array.isArray(value)) { } else if (Array.isArray(blockValue)) {
// Handle arrays: Resolve each item in the array // Resolve each item in the array
clonedBlock[key] = value.map((itemInArray: any) => { clonedBlock[key] = blockValue.map((arrayItem: any) =>
if (typeof itemInArray === 'object') { typeof arrayItem === 'object' ? resolveBlockValues(context, arrayItem) : arrayItem
return resolveBlockValue(item, itemInArray); );
}
return itemInArray; // Return primitive values directly
});
} else { } else {
clonedBlock[key] = resolveBlockValue(item, value); clonedBlock[key] = resolveBlockValues(context, blockValue);
} }
} }
} }
@ -177,3 +173,18 @@ function resolveBlockValue(item: any, block: any): any {
return clonedBlock; return clonedBlock;
} }
function resolvePathValue(object: any, path: string): any {
const pathSegments = path.split('.');
let resolvedValue = object;
for (const segment of pathSegments) {
if (resolvedValue && typeof resolvedValue === 'object' && segment in resolvedValue) {
resolvedValue = resolvedValue[segment];
} else {
return undefined; // Return undefined if the path doesn't exist
}
}
return resolvedValue;
}

31
packages/core/src/dom_components/model/Component.ts

@ -56,9 +56,9 @@ import { ConditionalVariableType, DataCondition } from '../../data_sources/model
import { isDynamicValue, isDynamicValueDefinition } from '../../data_sources/model/utils'; import { isDynamicValue, isDynamicValueDefinition } from '../../data_sources/model/utils';
import { DynamicValueDefinition } from '../../data_sources/types'; import { DynamicValueDefinition } from '../../data_sources/types';
export interface IComponent extends ExtractMethods<Component> {} export interface IComponent extends ExtractMethods<Component> { }
export interface SetAttrOptions extends SetOptions, UpdateStyleOptions {} export interface SetAttrOptions extends SetOptions, UpdateStyleOptions { }
const escapeRegExp = (str: string) => { const escapeRegExp = (str: string) => {
return str.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&'); return str.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&');
@ -225,12 +225,12 @@ export default class Component extends StyleableModel<ComponentProperties> {
return this.frame?.getPage(); return this.frame?.getPage();
} }
preInit() {} preInit() { }
/** /**
* Hook method, called once the model is created * Hook method, called once the model is created
*/ */
init() {} init() { }
/** /**
* Hook method, called when the model has been updated (eg. updated some model's property) * Hook method, called when the model has been updated (eg. updated some model's property)
@ -238,12 +238,12 @@ export default class Component extends StyleableModel<ComponentProperties> {
* @param {*} value Property value, if triggered after some property update * @param {*} value Property value, if triggered after some property update
* @param {*} previous Property previous value, if triggered after some property update * @param {*} previous Property previous value, if triggered after some property update
*/ */
updated(property: string, value: any, previous: any) {} updated(property: string, value: any, previous: any) { }
/** /**
* Hook method, called once the model has been removed * Hook method, called once the model has been removed
*/ */
removed() {} removed() { }
em!: EditorModel; em!: EditorModel;
opt!: ComponentOptions; opt!: ComponentOptions;
@ -262,6 +262,25 @@ export default class Component extends StyleableModel<ComponentProperties> {
collection!: Components; collection!: Components;
constructor(props: ComponentProperties = {}, opt: ComponentOptions) { constructor(props: ComponentProperties = {}, opt: ComponentOptions) {
if (Array.isArray(props['components'])) {
props['components']?.map(component => {
return {
...component,
collectionsItems: {
...props.collectionsItems
}
}
})
} else if (typeof props['components'] === 'object') {
props['components'] = {
...props['components'],
// @ts-ignore
collectionsItems: {
...props.collectionsItems
}
}
}
super(props, opt); super(props, opt);
bindAll(this, '__upSymbProps', '__upSymbCls', '__upSymbComps'); bindAll(this, '__upSymbProps', '__upSymbCls', '__upSymbComps');
const em = opt.em; const em = opt.em;

Loading…
Cancel
Save