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.
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<T extends Record<string, any> | 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;
}

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 { 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) => {
return str.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&');
@ -225,12 +225,12 @@ export default class Component extends StyleableModel<ComponentProperties> {
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<ComponentProperties> {
* @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<ComponentProperties> {
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;

Loading…
Cancel
Save