diff --git a/packages/core/src/data_sources/model/DataVariableListenerManager.ts b/packages/core/src/data_sources/model/DataVariableListenerManager.ts index e090e962b..62e165a5f 100644 --- a/packages/core/src/data_sources/model/DataVariableListenerManager.ts +++ b/packages/core/src/data_sources/model/DataVariableListenerManager.ts @@ -7,7 +7,7 @@ import { DynamicValue } from '../types'; import { DataCondition, ConditionalVariableType } from './conditional_variables/DataCondition'; import ComponentDataVariable from './ComponentDataVariable'; import { CollectionVariableType } from './data_collection/constants'; -import CollectionVariable from './data_collection/CollectionVariable'; +import DataCollectionVariable from './data_collection/DataCollectionVariable'; export interface DynamicVariableListenerManagerOptions { em: EditorModel; @@ -44,11 +44,7 @@ export default class DynamicVariableListenerManager { let dataListeners: DataVariableListener[] = []; switch (type) { case CollectionVariableType: - const collectionVariable = dynamicVariable as CollectionVariable; - if (collectionVariable.hasDynamicValue()) { - dataListeners = this.listenToDataVariable(collectionVariable.dataVariable!, em); - } - + dataListeners = this.listenToDataCollectionVariable(dynamicVariable as DataCollectionVariable); break; case DataVariableType: dataListeners = this.listenToDataVariable(dynamicVariable as DataVariable | ComponentDataVariable, em); @@ -86,6 +82,10 @@ export default class DynamicVariableListenerManager { return dataListeners; } + private listenToDataCollectionVariable(dataVariable: DataCollectionVariable) { + return [{ obj: dataVariable, event: 'change:value' }]; + } + private removeListeners() { this.dataListeners.forEach((ls) => this.model.stopListening(ls.obj, ls.event, this.onChange)); this.dataListeners = []; diff --git a/packages/core/src/data_sources/model/data_collection/ComponentDataCollection.ts b/packages/core/src/data_sources/model/data_collection/ComponentDataCollection.ts index a1d8d1893..0d6a925c9 100644 --- a/packages/core/src/data_sources/model/data_collection/ComponentDataCollection.ts +++ b/packages/core/src/data_sources/model/data_collection/ComponentDataCollection.ts @@ -95,6 +95,7 @@ export default class ComponentDataCollection extends Component { }, { em }, ); + new DynamicVariableListenerManager({ em: em, dataVariable, diff --git a/packages/core/src/data_sources/model/data_collection/ComponentDataCollectionVariable.ts b/packages/core/src/data_sources/model/data_collection/ComponentDataCollectionVariable.ts new file mode 100644 index 000000000..484aa9fd3 --- /dev/null +++ b/packages/core/src/data_sources/model/data_collection/ComponentDataCollectionVariable.ts @@ -0,0 +1,53 @@ +import Component, { keyCollectionsStateMap, keySymbolOvrd } from '../../../dom_components/model/Component'; +import { ComponentOptions, ComponentProperties } from '../../../dom_components/model/types'; +import { toLowerCase } from '../../../utils/mixins'; +import DataCollectionVariable from './DataCollectionVariable'; +import { CollectionVariableType, keyInnerCollectionState } from './constants'; +import { DataCollectionStateMap, DataCollectionVariableDefinition } from './types'; + +export default class ComponentDataCollectionVariable extends Component { + datacollectionVariable: DataCollectionVariable; + + get defaults() { + return { + // @ts-ignore + ...super.defaults, + type: CollectionVariableType, + variableType: '', + path: '', + collectionName: keyInnerCollectionState, + }; + } + + constructor(props: DataCollectionVariableDefinition & ComponentProperties, opt: ComponentOptions) { + super(props, opt); + const em = opt.em; + const { type, variableType, path, collectionName } = props; + + this.datacollectionVariable = new DataCollectionVariable( + { type, variableType, path, collectionName }, + { + em, + collectionsStateMap: this.get(keyCollectionsStateMap), + }, + ); + + this.listenTo(this, `change:${keyCollectionsStateMap}`, this.handleCollectionsMapStateUpdate); + } + + private handleCollectionsMapStateUpdate(m: any, v: DataCollectionStateMap, opts = {}) { + this.datacollectionVariable.updateCollectionsStateMap(v); + } + + getDataValue() { + return this.datacollectionVariable.getDataValue(); + } + + getInnerHTML() { + return this.getDataValue(); + } + + static isComponent(el: HTMLElement) { + return toLowerCase(el.tagName) === CollectionVariableType; + } +} diff --git a/packages/core/src/data_sources/model/data_collection/ComponentDataCollectionVariableView.ts b/packages/core/src/data_sources/model/data_collection/ComponentDataCollectionVariableView.ts new file mode 100644 index 000000000..fa4bab47d --- /dev/null +++ b/packages/core/src/data_sources/model/data_collection/ComponentDataCollectionVariableView.ts @@ -0,0 +1,24 @@ +import ComponentView from '../../../dom_components/view/ComponentView'; +import DynamicVariableListenerManager from '../DataVariableListenerManager'; +import ComponentDataCollectionVariable from './ComponentDataCollectionVariable'; + +export default class ComponentDataCollectionVariableView extends ComponentView { + collectionVariableListener?: DynamicVariableListenerManager; + + initialize(opt = {}) { + super.initialize(opt); + this.postRender(); + this.collectionVariableListener = new DynamicVariableListenerManager({ + em: this.em!, + dataVariable: this.model.datacollectionVariable, + updateValueFromDataVariable: this.postRender, + }); + } + + postRender() { + const { model, el } = this; + el.innerHTML = model.datacollectionVariable.getDataValue(); + + super.postRender(); + } +} diff --git a/packages/core/src/data_sources/model/data_collection/CollectionVariable.ts b/packages/core/src/data_sources/model/data_collection/DataCollectionVariable.ts similarity index 69% rename from packages/core/src/data_sources/model/data_collection/CollectionVariable.ts rename to packages/core/src/data_sources/model/data_collection/DataCollectionVariable.ts index 38dc6d429..7e8073ecd 100644 --- a/packages/core/src/data_sources/model/data_collection/CollectionVariable.ts +++ b/packages/core/src/data_sources/model/data_collection/DataCollectionVariable.ts @@ -2,16 +2,31 @@ import { DataCollectionVariableDefinition } from './types'; import { Model } from '../../../common'; import EditorModel from '../../../editor/model/Editor'; import DataVariable, { DataVariableType } from '../DataVariable'; -import { keyInnerCollectionState } from './constants'; +import { CollectionVariableType, keyInnerCollectionState } from './constants'; import { DataCollectionState, DataCollectionStateMap } from './types'; +import DynamicVariableListenerManager from '../DataVariableListenerManager'; +type ResolvedDataCollectionVariable = DataCollectionVariableDefinition & { + value?: any; +}; -export default class CollectionVariable extends Model { +export default class DataCollectionVariable extends Model { em: EditorModel; collectionsStateMap: DataCollectionStateMap; dataVariable?: DataVariable; + dynamicValueListener?: DynamicVariableListenerManager; + + defaults(): Partial { + return { + type: CollectionVariableType, + variableType: undefined, + path: '', + collectionName: keyInnerCollectionState, + value: undefined, + }; + } constructor( - attrs: DataCollectionVariableDefinition, + attrs: ResolvedDataCollectionVariable, options: { em: EditorModel; collectionsStateMap: DataCollectionStateMap; @@ -20,7 +35,6 @@ export default class CollectionVariable extends Model { componentTypes: ComponentStackItem[] = [ + { + id: CollectionVariableType, + model: ComponentDataCollectionVariable, + view: ComponentDataCollectionVariableView, + }, { id: CollectionComponentType, model: ComponentDataCollection, diff --git a/packages/core/test/specs/data_sources/model/data_collection/ComponentDataCollection.ts b/packages/core/test/specs/data_sources/model/data_collection/ComponentDataCollection.ts index 7a6a4a72e..cf944bef3 100644 --- a/packages/core/test/specs/data_sources/model/data_collection/ComponentDataCollection.ts +++ b/packages/core/test/specs/data_sources/model/data_collection/ComponentDataCollection.ts @@ -6,7 +6,7 @@ import { } from '../../../../../src/data_sources/model/data_collection/constants'; import { DataCollectionStateVariableType } from '../../../../../src/data_sources/model/data_collection/types'; import EditorModel from '../../../../../src/editor/model/Editor'; -import { filterObjectForSnapshot, setupTestEditor } from '../../../../common'; +import { setupTestEditor } from '../../../../common'; import { getSymbolMain } from '../../../../../src/dom_components/model/SymbolUtils'; import { ProjectData } from '../../../../../src/storage_manager'; diff --git a/packages/core/test/specs/data_sources/model/data_collection/ComponentDataCollectionVariable.ts b/packages/core/test/specs/data_sources/model/data_collection/ComponentDataCollectionVariable.ts new file mode 100644 index 000000000..7c3bc161c --- /dev/null +++ b/packages/core/test/specs/data_sources/model/data_collection/ComponentDataCollectionVariable.ts @@ -0,0 +1,69 @@ +import { Component, DataRecord, DataSource, DataSourceManager, Editor } from '../../../../../src'; +import { DataVariableType } from '../../../../../src/data_sources/model/DataVariable'; +import { + CollectionComponentType, + CollectionVariableType, +} from '../../../../../src/data_sources/model/data_collection/constants'; +import { DataCollectionStateVariableType } from '../../../../../src/data_sources/model/data_collection/types'; +import EditorModel from '../../../../../src/editor/model/Editor'; +import { setupTestEditor } from '../../../../common'; + +describe('Collection component', () => { + let em: EditorModel; + let editor: Editor; + let dsm: DataSourceManager; + let dataSource: DataSource; + let wrapper: Component; + let firstRecord: DataRecord; + let secondRecord: DataRecord; + + beforeEach(() => { + ({ em, editor, dsm } = setupTestEditor()); + wrapper = em.getWrapper()!; + dataSource = dsm.add({ + id: 'my_data_source_id', + records: [ + { id: 'user1', user: 'user1', age: '12' }, + { id: 'user2', user: 'user2', age: '14' }, + { id: 'user3', user: 'user3', age: '16' }, + ], + }); + + firstRecord = dataSource.getRecord('user1')!; + secondRecord = dataSource.getRecord('user2')!; + }); + + afterEach(() => { + em.destroy(); + }); + + test('Collection variable components', async () => { + const cmp = wrapper.components({ + type: CollectionComponentType, + collectionDefinition: { + block: { + type: 'default', + components: [ + { + type: CollectionVariableType, + variableType: DataCollectionStateVariableType.currentItem, + path: 'user', + }, + ], + }, + config: { + dataSource: { + type: DataVariableType, + path: 'my_data_source_id', + }, + }, + }, + })[0]; + + const firstGrandchild = cmp.components().at(0).components().at(0); + expect(firstGrandchild.getInnerHTML()).toContain('user1'); + + const secondGrandchild = cmp.components().at(1).components().at(0); + expect(secondGrandchild.getInnerHTML()).toContain('user2'); + }); +});