Skip to content

Commit

Permalink
Fix data change events not cascading properly when setting data
Browse files Browse the repository at this point in the history
  • Loading branch information
KetanReddy committed Feb 24, 2024
1 parent 38727dc commit ad19df1
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 2 deletions.
88 changes: 88 additions & 0 deletions plugins/data-change-listener/core/src/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -343,3 +343,91 @@ describe('Data-Change-Listener with Validations', () => {
expect(getCurrentView()?.initialView?.listeners).toBeUndefined();
});
});

describe('Data-Change-Listener that are chained', () => {
let player: Player;
let dataController: DataController;
let testExpression: jest.Mock<any, any>;

const flow: Flow = {
id: 'test-flow',
data: {
name: {
first: '',
second: '',
third: '',
},
},
views: [
{
id: 'view-1',
type: 'info',
fields: {
asset: {
id: 'input',
type: 'input',
binding: 'name.first',
},
},
listeners: {
'dataChange.name.first': ["{{name.second}} = 'update 1'"],
'dataChange.name.second': ["{{name.third}} = 'update 2'"],
},
},
],
navigation: {
BEGIN: 'FLOW_1',
FLOW_1: {
startState: 'VIEW_1',
VIEW_1: {
state_type: 'VIEW',
ref: 'view-1',
transitions: {
'*': 'END',
},
},
},
},
};

beforeEach(() => {
player = new Player({
plugins: [
new DataChangeListenerPlugin(),
new AssetTransformPlugin(
new Registry([[{ type: 'input' }, transform]])
),
],
});

testExpression = jest.fn();

player.hooks.expressionEvaluator.tap('test', (ev) => {
ev.addExpressionFunction('test', (context, ...args) => {
testExpression(...args);
});
});

player.hooks.dataController.tap('test', (dc) => {
dataController = dc;
});

player.start(flow);
});

function getState() {
return player.getState() as InProgressState;
}

function getInputAsset() {
return getState().controllers.view.currentView?.lastUpdate?.fields.asset;
}

it('chained listeners that set data trigger each other', async () => {
getInputAsset().set('something');
await waitFor(() => {
expect(dataController.get('name.second')).toStrictEqual('update 1');
expect(dataController.get('name.third')).toStrictEqual('update 2');
});
});
});
11 changes: 9 additions & 2 deletions plugins/data-change-listener/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import type {
ExpressionEvaluator,
BindingInstance,
BindingParser,
ValidationController,
} from '@player-ui/player';
import { isExpressionNode } from '@player-ui/player';

Expand Down Expand Up @@ -194,6 +195,7 @@ export class DataChangeListenerPlugin implements PlayerPlugin {
apply(player: Player) {
let expressionEvaluator: ExpressionEvaluator;
let dataChangeListeners: Array<ViewListenerHandler> = [];
let validationController: ValidationController;

player.hooks.expressionEvaluator.tap(
this.name,
Expand Down Expand Up @@ -234,8 +236,9 @@ export class DataChangeListenerPlugin implements PlayerPlugin {
const { silent = false } = options || {};
if (silent) return;
const validUpdates = updates.filter((update) => {
const committedVal = options?.context?.model.get(update.binding);
return committedVal === update.newValue;
return !validationController
.getValidationForBinding(update.binding)
?.getAll().length;
});
onFieldUpdateHandler(validUpdates.map((t) => t.binding));
})
Expand Down Expand Up @@ -277,6 +280,10 @@ export class DataChangeListenerPlugin implements PlayerPlugin {
}
);

player.hooks.validationController.tap(this.name, (vc) => {
validationController = vc;
});

player.hooks.flowController.tap(this.name, (flowController) => {
flowController.hooks.flow.tap(this.name, (flow) => {
flow.hooks.transition.tap(this.name, (from, to) => {
Expand Down

0 comments on commit ad19df1

Please sign in to comment.