Skip to content

Commit 546cc80

Browse files
authored
"Cannot read properties of undefined (reading 'withFrame')" is thrown when questionsOnPageMode: "inputPerPage" and survey.data is specified from code fix #10653 (#10658)
1 parent 9de575c commit 546cc80

File tree

5 files changed

+183
-26
lines changed

5 files changed

+183
-26
lines changed

packages/survey-core/src/question.ts

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -662,7 +662,7 @@ export class Question extends SurveyElement<Question>
662662
}
663663
}
664664
if (val !== this.visible && this.areInvisibleElementsShowing) {
665-
this.updateQuestionCss(true);
665+
this.updateQuestionCss();
666666
}
667667
}
668668
/**
@@ -1804,24 +1804,22 @@ export class Question extends SurveyElement<Question>
18041804
if (this.wasRendered) {
18051805
super.updateElementCss(reNew);
18061806
if (reNew) {
1807-
this.updateQuestionCss(true);
1807+
this.updateQuestionCss();
18081808
}
18091809
} else {
18101810
this.clearCssClasses();
18111811
}
18121812
this.resetIndents();
18131813
}
1814-
protected updateQuestionCss(reNew?: boolean): void {
1815-
if (this.isLoadingFromJson || !this.survey) return;
1814+
private updateQuestionCss(): void {
1815+
if (this.isLoadingFromJson || !this.survey || this.isDisposed) return;
18161816
if (this.wasRendered) {
18171817
this.updateElementCssCore(this.cssClasses);
1818-
} else {
1819-
this.isRequireUpdateElements = true;
18201818
}
18211819
}
18221820
private ensureElementCss() {
18231821
if (!this.cssClassesValue) {
1824-
this.updateQuestionCss(true);
1822+
this.updateQuestionCss();
18251823
}
18261824
}
18271825
protected updateElementCssCore(cssClasses: any): void {

packages/survey-core/src/question_file.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -421,8 +421,8 @@ export class QuestionFileModel extends QuestionFileModelBase {
421421
}
422422
protected updateElementCssCore(cssClasses: any): void {
423423
super.updateElementCssCore(cssClasses);
424-
this.prevFileAction.iconName = this.cssClasses.leftIconId;
425-
this.nextFileAction.iconName = this.cssClasses.rightIconId;
424+
this.prevFileAction.iconName = cssClasses.leftIconId;
425+
this.nextFileAction.iconName = cssClasses.rightIconId;
426426
this.updateCurrentMode();
427427
}
428428
private getFileIndexCaption(): string {

packages/survey-core/src/question_matrix.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -618,13 +618,20 @@ export class QuestionMatrixModel
618618
this.nestedQuestionsValue = res;
619619
return res;
620620
}
621-
public resetSingleInput(): void {
622-
super.resetSingleInput();
621+
private disposeNestedQuestions(): void {
623622
if (this.nestedQuestionsValue) {
624623
this.nestedQuestionsValue.forEach(q => q.dispose());
625624
this.nestedQuestionsValue = null;
626625
}
627626
}
627+
public resetSingleInput(): void {
628+
this.disposeNestedQuestions();
629+
super.resetSingleInput();
630+
}
631+
public dispose(): void {
632+
this.disposeNestedQuestions();
633+
super.dispose();
634+
}
628635
//#region For simple radiogroup questions setSurveyImpl
629636
getSurveyData(): ISurveyData { return this; }
630637
getTextProcessor(): ITextProcessor { return this.surveyImpl?.getTextProcessor(); }

packages/survey-core/src/survey-element.ts

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -672,21 +672,19 @@ export class SurveyElement<E = any> extends SurveyElementCore implements ISurvey
672672
private get css(): any {
673673
return !!this.survey ? this.survey.getCss() : {};
674674
}
675-
private isCssValueCalculating: boolean;
676675
public get cssClassesValue(): any {
677-
let res = this.getPropertyValueWithoutDefault("cssClassesValue");
678-
if (!res && !this.isCssValueCalculating) {
679-
this.isCssValueCalculating = true;
680-
res = this.createCssClassesValue();
681-
this.isCssValueCalculating = false;
682-
}
683-
return res;
676+
return this.getPropertyValue("cssClassesValue", undefined, () => this.createCssClassesValue());
684677
}
678+
private isCalculatingCssClasses: boolean;
685679
private createCssClassesValue(): any {
680+
const callOnCalc = this.isCalculatingCssClasses;
681+
this.isCalculatingCssClasses = true;
686682
const res = this.calcCssClasses(this.css);
687-
this.setPropertyValue("cssClassesValue", res);
688-
this.onCalcCssClasses(res);
689-
this.updateElementCssCore(this.cssClassesValue);
683+
if (!callOnCalc) {
684+
this.onCalcCssClasses(res);
685+
}
686+
this.updateElementCssCore(res);
687+
this.isCalculatingCssClasses = false;
690688
return res;
691689
}
692690
protected onCalcCssClasses(classes: any): void {}
@@ -703,11 +701,7 @@ export class SurveyElement<E = any> extends SurveyElementCore implements ISurvey
703701
* [View Demo](https://surveyjs.io/form-library/examples/customize-survey-with-css/ (linkStyle))
704702
*/
705703
public get cssClasses(): any {
706-
const _dummy = this.cssClassesValue;
707704
if (!this.survey) return this.calcCssClasses(this.css);
708-
if (!this.cssClassesValue) {
709-
this.createCssClassesValue();
710-
}
711705
return this.cssClassesValue;
712706
}
713707
public get cssTitleNumber(): any {

packages/survey-core/tests/inputPerPageTests.ts

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2429,3 +2429,161 @@ QUnit.test("Do not show summary page on request, Issue#10435", assert => {
24292429
assert.equal(survey.currentSingleQuestion.name, "q3", "currentSingleQuestion is q3, #3");
24302430
assert.equal(addBtn.visible, false, "addBtn.visible, #3");
24312431
});
2432+
QUnit.test("Cannot read properties of undefined with survey.data, Bug #10653", assert => {
2433+
const survey = new SurveyModel({
2434+
questionsOnPageMode: "inputPerPage",
2435+
pages: [
2436+
{
2437+
name: "page1",
2438+
elements: [
2439+
{
2440+
type: "matrix",
2441+
name: "qualities",
2442+
title:
2443+
"Please indicate if you agree or disagree with the following statements",
2444+
columns: [
2445+
{
2446+
value: 5,
2447+
text: "Strongly agree",
2448+
},
2449+
{
2450+
value: 4,
2451+
text: "Agree",
2452+
},
2453+
{
2454+
value: 3,
2455+
text: "Neutral",
2456+
},
2457+
{
2458+
value: 2,
2459+
text: "Disagree",
2460+
},
2461+
{
2462+
value: 1,
2463+
text: "Strongly disagree",
2464+
},
2465+
],
2466+
rows: [
2467+
{
2468+
value: "affordable",
2469+
text: "Product is affordable",
2470+
},
2471+
{
2472+
value: "does-what-it-claims",
2473+
text: "Product does what it claims",
2474+
},
2475+
{
2476+
value: "better-than-others",
2477+
text: "Product is better than other products on the market",
2478+
},
2479+
{
2480+
value: "easy-to-use",
2481+
text: "Product is easy to use",
2482+
},
2483+
],
2484+
},
2485+
{
2486+
type: "rating",
2487+
name: "satisfaction-score",
2488+
title: "How satisfied are you with our product?",
2489+
minRateDescription: "Not satisfied",
2490+
maxRateDescription: "Completely satisfied",
2491+
},
2492+
{
2493+
type: "rating",
2494+
name: "recommend",
2495+
visibleIf: "{satisfaction-score} > 3",
2496+
title:
2497+
"How likely are you to recommend our product to a friend or co-worker?",
2498+
minRateDescription: "Will not recommend",
2499+
maxRateDescription: "I will recommend",
2500+
},
2501+
{
2502+
type: "comment",
2503+
name: "suggestions",
2504+
title: "What would make you more satisfied with our product?",
2505+
},
2506+
],
2507+
},
2508+
{
2509+
name: "page2",
2510+
elements: [
2511+
{
2512+
type: "radiogroup",
2513+
name: "price-comparison",
2514+
title: "Compared to our competitors, do you feel our product is:",
2515+
choices: [
2516+
"Less expensive",
2517+
"Priced about the same",
2518+
"More expensive",
2519+
"Not sure",
2520+
],
2521+
},
2522+
{
2523+
type: "radiogroup",
2524+
name: "current-price",
2525+
title: "Do you feel our current price is merited by our product?",
2526+
choices: [
2527+
{
2528+
value: "correct",
2529+
text: "Yes, the price is about right",
2530+
},
2531+
{
2532+
value: "low",
2533+
text: "No, the price is too low for your product",
2534+
},
2535+
{
2536+
value: "high",
2537+
text: "No, the price is too high for your product",
2538+
},
2539+
],
2540+
},
2541+
{
2542+
type: "multipletext",
2543+
name: "price-limits",
2544+
title:
2545+
"What is the highest and lowest price you would pay for a product like ours?",
2546+
items: [
2547+
{
2548+
name: "highest",
2549+
title: "Highest",
2550+
},
2551+
{
2552+
name: "lowest",
2553+
title: "Lowest",
2554+
},
2555+
],
2556+
itemTitleWidth: "60px",
2557+
},
2558+
],
2559+
},
2560+
{
2561+
name: "page3",
2562+
elements: [
2563+
{
2564+
type: "text",
2565+
name: "email",
2566+
title:
2567+
"Please leave your email address if you would like us to contact you.",
2568+
},
2569+
],
2570+
},
2571+
],
2572+
});
2573+
survey.setIsMobile(true);
2574+
survey.data = {
2575+
qualities: {
2576+
affordable: 3,
2577+
"does-what-it-claims": 5,
2578+
"better-than-others": 3,
2579+
"easy-to-use": 2,
2580+
},
2581+
"satisfaction-score": 4,
2582+
};
2583+
assert.equal(survey.currentSingleQuestion.name, "qualities", "currentSingleQuestion is qualities, #1");
2584+
assert.ok(survey.currentSingleQuestion.cssClasses, "cssClasses is defined");
2585+
const affordable = survey.currentSingleQuestion.singleInputQuestion;
2586+
assert.equal(affordable.name, "affordable", "singleInputQuestion is affordable, #1");
2587+
assert.ok(affordable.cssClasses, "singleInputQuestion cssClasses is defined");
2588+
assert.ok(affordable.cssRoot, "singleInputQuestion cssRoot is defined");
2589+
});

0 commit comments

Comments
 (0)