diff --git a/packages/core/src/data_sources/model/collection_component/CollectionComponent.ts b/packages/core/src/data_sources/model/collection_component/CollectionComponent.ts index 876c7a41a..5b069cb08 100644 --- a/packages/core/src/data_sources/model/collection_component/CollectionComponent.ts +++ b/packages/core/src/data_sources/model/collection_component/CollectionComponent.ts @@ -23,26 +23,26 @@ interface CollectionConfig { // Provides access to collection state variables during iteration. interface CollectionStateVariables { - currentIndex: number; // Current collection index - firstIndex: number; // Start index - currentItem: any; // Current item in the iteration - lastIndex: number; // End index - collectionName?: string; // Optional name of the collection - totalItems: number; // Total number of items in the collection - remainingItems: number; // Remaining items in the collection + current_index: number; // Current collection index + first_index: number; // Start index + current_item: any; // Current item in the iteration + last_index: number; // End index + collection_name?: string; // Optional name of the collection + total_items: number; // Total number of items in the collection + remaining_items: number; // Remaining items in the collection } // Defines the complete structure for a collection, including configuration and state variables. interface CollectionDefinition { type: typeof CollectionVariableType; - collectionName?: string; // Optional collection name + collection_name?: string; // Optional collection name config: CollectionConfig; // Loop configuration details block: ComponentDefinition; // Component definition for each iteration } export default class CollectionComponent extends Component { constructor(props: CollectionDefinition & ComponentProperties, opt: ComponentOptions) { - const { block, config } = props.collectionDefinition; + const { collection_name, block, config } = props.collectionDefinition; const { dataSource } = config; let items: CollectionStateVariables[] = []; switch (true) { @@ -68,16 +68,30 @@ export default class CollectionComponent extends Component { default: } - const components: ComponentDefinitionDefined[] = items.map((item: CollectionStateVariables, index) => resolveBlockValue({ - currentIndex: index, - firstIndex: config.startIndex, - currentItem: item, - lastIndex: config.endIndex, - collectionName: props.collectionName, - totalItems: items.length, - remainingItems: items.length - index, - }, block) - ); + const components: ComponentDefinitionDefined[] = items.map((item: CollectionStateVariables, index) => { + const innerMostCollectionItem = { + collection_name, + current_index: index, + first_index: config.startIndex, + current_item: item, + last_index: config.endIndex, + total_items: items.length, + 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 = { ...props, type: CollectionVariableType, @@ -117,59 +131,41 @@ function deepCloneObject | null | undefined>(obj: 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); if (typeof clonedBlock === 'object' && clonedBlock !== null) { - const stringifiedItem = JSON.stringify(item.currentItem); - const keys = Object.keys(clonedBlock); - - for (let i = 0; i < keys.length; i++) { - const key = keys[i]; - let value = clonedBlock[key]; - - if (typeof value === 'object') { - if (value.type === 'parent-collection-variable') { - if (value.variable_type === 'current_item') { - if (!value.path) { - clonedBlock[key] = stringifiedItem; - } else { - const pathParts = value.path.split('.'); - let resolvedValue = item.currentItem; - for (const part of pathParts) { - if (resolvedValue && typeof resolvedValue === 'object' && resolvedValue.hasOwnProperty(part)) { - resolvedValue = resolvedValue[part]; - } else { - resolvedValue = undefined; // Handle cases where the path doesn't exist - break; - } - } - 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); + const blockKeys = Object.keys(clonedBlock); + + for (const key of blockKeys) { + let blockValue = clonedBlock[key]; + + if (typeof blockValue === 'object' && blockValue !== null) { + if (blockValue.type === 'parent-collection-variable') { + const collectionItem = blockValue.collection_name + ? context[blockValue.collection_name] + : innerMostCollectionItem; + if (!collectionItem) continue; + + switch (blockValue.variable_type) { + case 'current_item': + clonedBlock[key] = blockValue.path + ? resolvePathValue(collectionItem, blockValue.path) + : JSON.stringify(collectionItem); + break; + default: + clonedBlock[key] = collectionItem[blockValue.variable_type]; + break; // Handle unexpected variable types gracefully } - } else if (Array.isArray(value)) { - // Handle arrays: Resolve each item in the array - clonedBlock[key] = value.map((itemInArray: any) => { - if (typeof itemInArray === 'object') { - return resolveBlockValue(item, itemInArray); - } - - return itemInArray; // Return primitive values directly - }); + } else if (Array.isArray(blockValue)) { + // Resolve each item in the array + clonedBlock[key] = blockValue.map((arrayItem: any) => + typeof arrayItem === 'object' ? resolveBlockValues(context, arrayItem) : arrayItem + ); } else { - clonedBlock[key] = resolveBlockValue(item, value); + clonedBlock[key] = resolveBlockValues(context, blockValue); } } } @@ -177,3 +173,18 @@ function resolveBlockValue(item: any, block: any): any { 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; +} diff --git a/packages/core/src/dom_components/model/Component.ts b/packages/core/src/dom_components/model/Component.ts index fe93d6931..35b22ebec 100644 --- a/packages/core/src/dom_components/model/Component.ts +++ b/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 { DynamicValueDefinition } from '../../data_sources/types'; -export interface IComponent extends ExtractMethods {} +export interface IComponent extends ExtractMethods { } -export interface SetAttrOptions extends SetOptions, UpdateStyleOptions {} +export interface SetAttrOptions extends SetOptions, UpdateStyleOptions { } const escapeRegExp = (str: string) => { return str.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&'); @@ -225,12 +225,12 @@ export default class Component extends StyleableModel { return this.frame?.getPage(); } - preInit() {} + preInit() { } /** * 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) @@ -238,12 +238,12 @@ export default class Component extends StyleableModel { * @param {*} value Property 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 */ - removed() {} + removed() { } em!: EditorModel; opt!: ComponentOptions; @@ -262,6 +262,25 @@ export default class Component extends StyleableModel { collection!: Components; 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); bindAll(this, '__upSymbProps', '__upSymbCls', '__upSymbComps'); const em = opt.em;