Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to restrict re-evaluation of expressions for only those change in values on which the expression depends in surveyjs? #9242

Open
kalpadiptyaroy opened this issue Dec 31, 2024 · 2 comments
Assignees
Labels
question user issue An issue or bug reported by users

Comments

@kalpadiptyaroy
Copy link

Describe the bug
I am currently using surveyjs within a react app. I have a custom function that returns an uuid value and I invoke that function using an expression in the surveyjs JSON. Now, I have observed the following.

This uuid() has no parameter input, yet whenever I select any value from any other dropdown of any other field in the form that has no dependency with the uuid expression field, then also the uuid value of the expression gets updated - unnecessarily and this also causes a re-render.

If I have a function with a parameter input, this parameter input comes from a particular field of the survey. Now even if I alter another field that is not related to the parameter input of this expression custom function, then also expression gets re-evaluated, and the function is re-invoked. This also causes an unnecessary re-render.

Considering the obs#2, if I put the mentioned function with single param input within an iif() statement, such that the function should only be invoked if the condition is true, then also the expression containing the function gets evaluated even though the condition is false. This is preventing me from restricting a custom function call via iif statement.

Consider this example for understanding the scenario better.

Steps to reproduce

{
   "type": "expression",
   "name": "audit_id",
   "expression": "uuid()"
},
{
   "type": "dropdown",
   "name": "audit_type",
   "choices": ["audit-type1", "audit-type2"]
},
{
   "type": "dropdown",
   "name": "model",
   "choices": ["model1", "model2"]
},
{
   "type": "expression",
   "name": "service",
   "expression": "iif({enable_model} == true, findServiceByModel({model})), 'null'"
},
{
   "type": "boolean",
   "name": "enable_model",
   "valueTrue": "true",
   "valueFalse": "false"
}

Expected behavior

Note: findServiceByModel() is already registered in a FunctionFactory instance and async in nature.

In this example

audit_id get re-evaluated each time I change audit_type dropdown value.
findServiceByModel() will get invoked even if I change audit_type which is completely independant.
findServiceByModel() will get invoked even if enable_model is set to false.

Ideally, expressions should only be re-evaluated if its dependent param changes else not.

Please let me know how the above concerns can be addressed in surveyjs.

Evidence
Stacktrace evidence:

App.js:182  No parameters received
overrideMethod @ hook.js:608
findOCRService @ App.js:182
FunctionFactory.run @ functionsfactory.ts:60
FunctionOperand.evaluateCore @ expressions.ts:382
FunctionOperand.evaluate @ expressions.ts:367
ExpressionExecutorRunner.runAsyncItemCore @ conditions.ts:86
ExpressionExecutorRunner.runAsyncItem @ conditions.ts:81
(anonymous) @ conditions.ts:79
ExpressionExecutorRunner.runAsyncItem @ conditions.ts:79
ExpressionExecutorRunner.run @ conditions.ts:64
ExpressionExecutor.run @ conditions.ts:173
ExpressionRunnerBase.runCore @ conditions.ts:225
ExpressionRunner.run @ conditions.ts:248
QuestionExpressionModel.runCondition @ question_expression.ts:77
PanelModelBase.runCondition @ panel.ts:1934
QuestionCompositeModel.runCondition @ question_custom.ts:1206
PanelModelBase.runCondition @ panel.ts:1934
PanelModelBase.runCondition @ panel.ts:1934
QuestionPanelDynamicModel.runPanelsCondition @ question_paneldynamic.ts:1890
QuestionPanelDynamicModel.runCondition @ question_paneldynamic.ts:1856
PanelModelBase.runCondition @ panel.ts:1934
SurveyModel.runConditionsCore @ survey.ts:6124
SurveyModel.runConditions @ survey.ts:6070
SurveyModel.runConditionOnValueChanged @ survey.ts:6105
SurveyModel.checkTriggersAndRunConditions @ survey.ts:6032
SurveyModel.updateOnSetValue @ survey.ts:6720
SurveyModel.setValue @ survey.ts:6695
Question.setValueCore @ question.ts:2407
QuestionPanelDynamicModel.setValueCore @ question_paneldynamic.ts:910
Question.setNewValueInData @ question.ts:2397
Question.setNewValue @ question.ts:2354
set @ question.ts:1629
QuestionPanelDynamicModel.setPanelItemData @ question_paneldynamic.ts:2284
QuestionPanelDynamicItem.setValue @ question_paneldynamic.ts:158
Question.setValueCore @ question.ts:2407
QuestionSelectBase.setValueCore @ question_baseselect.ts:672
Question.setNewValueInData @ question.ts:2397
Question.setNewValue @ question.ts:2354
QuestionSelectBase.setNewValue @ question_baseselect.ts:687
set @ question.ts:1629
_onSelectionChanged @ dropdownListModel.ts:221
ListModel._this.onItemClick @ list.ts:211
onClick @ list-item.tsx:53

Please complete the following information:

  • Browser: MS Edge
  • Browser version: latest
  • JS framework/library: React,
  • SurveyJS version: latest
  • Device: PC

Additional context
https://stackoverflow.com/questions/79299024/how-to-restrict-re-evaluation-of-expressions-for-only-those-change-in-values-on

@JaneSjs JaneSjs added question user issue An issue or bug reported by users labels Jan 1, 2025
@andrewtelnov andrewtelnov self-assigned this Jan 2, 2025
@andrewtelnov
Copy link
Member

@kalpadiptyaroy
There is an error in your expression, please correct it:
iif({enable_model} == true, findServiceByModel({model})), 'null'
It should be:
iif({enable_model} == true, findServiceByModel({model}), 'null')

We recalculate the expression whenever any value changes, which is currently by design. We perform checks for changing values in expressions related to triggers and question properties, such as defaultValueExpression or setValueExpression. It is important that we execute these expressions only when a particular question's values change.

However, if we encounter a function, we execute the expression anyway, as we cannot predict what might be contained within it. A developer might utilize any survey or question property inside a custom function.

Thank you,
Andrew

@kalpadiptyaroy
Copy link
Author

@andrewtelnov.

Yes you are correct there is a typographical error in closing the parenthesis. My bad.
Keeping that aside.

I see you are executing the expression anyway if it is a bare expression - right? (not contained in a question prop or triggers).

So that means the behavior I want can be achieved by utilizing the expressions in the questions props or triggers - Fine.

May I request a small example in Plunker that demonstrates both the scenarios (meaning bare expression and another as a part of a trigger and a question prop). That will be helpful reference for me at this stage in my use case.

Thanks,
Kalpadiptya

@JaneSjs JaneSjs self-assigned this Jan 13, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question user issue An issue or bug reported by users
Projects
None yet
Development

No branches or pull requests

3 participants