From c56382ddc75b9d0785a4558722c3c509403a637d Mon Sep 17 00:00:00 2001 From: Andrew Date: Mon, 15 Jan 2024 11:19:18 +0200 Subject: [PATCH] Panel dynamic: creates panels based on template on demand fix #7662 (#7663) * Panel dynamic: creates panels based on template on demand fix #7662 * Change visiblePanelCount getter #7662 --- src/panel.ts | 9 +- src/question_paneldynamic.ts | 205 +++++++++++++++------------ src/survey-element.ts | 17 ++- src/survey.ts | 2 +- tests/question_paneldynamic_tests.ts | 9 +- tests/surveytests.ts | 49 ++++++- 6 files changed, 184 insertions(+), 107 deletions(-) diff --git a/src/panel.ts b/src/panel.ts index e0ff13b168..b8b75888fc 100644 --- a/src/panel.ts +++ b/src/panel.ts @@ -1015,20 +1015,20 @@ export class PanelModelBase extends SurveyElement public createRow(): QuestionRowModel { return new QuestionRowModel(this); } - public onSurveyLoad() { + public onSurveyLoad(): void { for (var i = 0; i < this.elements.length; i++) { this.elements[i].onSurveyLoad(); } this.onElementVisibilityChanged(this); } - public onFirstRendering() { + public onFirstRendering(): void { super.onFirstRendering(); for (var i = 0; i < this.elements.length; i++) { this.elements[i].onFirstRendering(); } this.onRowsChanged(); } - public updateRows() { + public updateRows(): void { if (this.isLoadingFromJson) return; for (var i = 0; i < this.elements.length; i++) { if (this.elements[i].isPanel) { @@ -1359,6 +1359,9 @@ export class PanelModelBase extends SurveyElement } else { this.elements.splice(index, 0, element); } + if(this.wasRendered) { + element.onFirstRendering(); + } return true; } diff --git a/src/question_paneldynamic.ts b/src/question_paneldynamic.ts index f3972f0081..2a236e7914 100644 --- a/src/question_paneldynamic.ts +++ b/src/question_paneldynamic.ts @@ -295,8 +295,8 @@ export class QuestionPanelDynamicModel extends Question public get hasSingleInput(): boolean { return false; } public get isContainer(): boolean { return true; } public getFirstQuestionToFocus(withError: boolean): Question { - for (var i = 0; i < this.visiblePanels.length; i++) { - const res = this.visiblePanels[i].getFirstQuestionToFocus(withError); + for (var i = 0; i < this.visiblePanelsCore.length; i++) { + const res = this.visiblePanelsCore[i].getFirstQuestionToFocus(withError); if (!!res) return res; } return null; @@ -327,11 +327,11 @@ export class QuestionPanelDynamicModel extends Question } } private onTemplateElementPropertyChanged(element: any, options: any) { - if (this.isLoadingFromJson || this.useTemplatePanel || this.panels.length == 0) + if (this.isLoadingFromJson || this.useTemplatePanel || this.panelsCore.length == 0) return; var property = Serializer.findProperty(element.getType(), options.name); if (!property) return; - var panels = this.panels; + var panels = this.panelsCore; for (var i = 0; i < panels.length; i++) { var question = panels[i].getQuestionByName(element.name); if (!!question && (question)[options.name] !== options.newValue) { @@ -346,7 +346,7 @@ export class QuestionPanelDynamicModel extends Question return "paneldynamic"; } public clearOnDeletingContainer(): void { - this.panels.forEach((panel) => { + this.panelsCore.forEach((panel) => { panel.clearOnDeletingContainer(); }); } @@ -462,8 +462,8 @@ export class QuestionPanelDynamicModel extends Question } protected get items(): Array { var res = []; - for (var i = 0; i < this.panels.length; i++) { - res.push(this.panels[i].data); + for (var i = 0; i < this.panelsCore.length; i++) { + res.push(this.panelsCore[i].data); } return res; } @@ -474,25 +474,33 @@ export class QuestionPanelDynamicModel extends Question * @see panelCount */ public get panels(): Array { - return this.getPropertyValue("panels"); + this.buildPanelsFirstTime(this.canBuildPanels); + return this.panelsCore; } /** * An array of currently visible panels ([`PanelModel`](https://surveyjs.io/form-library/documentation/api-reference/panel-model) objects). * @see templateVisibleIf */ public get visiblePanels(): Array { + this.buildPanelsFirstTime(this.canBuildPanels); + return this.visiblePanelsCore; + } + protected get panelsCore(): Array { + return this.getPropertyValue("panels"); + } + protected get visiblePanelsCore(): Array { return this.getPropertyValue("visiblePanels"); } private onPanelAdded(panel: PanelModel): void { this.onPanelRemovedCore(panel); if(!panel.visible) return; let index = 0; - const panels = this.panels; + const panels = this.panelsCore; for(var i = 0; i < panels.length; i ++) { if(panels[i] === panel) break; if(panels[i].visible) index++; } - this.visiblePanels.splice(index, 0, panel); + this.visiblePanelsCore.splice(index, 0, panel); this.addTabFromToolbar(panel, index); if(!this.currentPanel) { this.currentPanel = panel; @@ -501,13 +509,13 @@ export class QuestionPanelDynamicModel extends Question private onPanelRemoved(panel: PanelModel): void { let index = this.onPanelRemovedCore(panel); if(this.currentPanel === panel) { - const visPanels = this.visiblePanels; + const visPanels = this.visiblePanelsCore; if(index >= visPanels.length) index = visPanels.length - 1; this.currentPanel = index >= 0 ? visPanels[index] : null; } } private onPanelRemovedCore(panel: PanelModel): number { - const visPanels = this.visiblePanels; + const visPanels = this.visiblePanelsCore; let index = visPanels.indexOf(panel); if(index > -1) { visPanels.splice(index, 1); @@ -527,12 +535,12 @@ export class QuestionPanelDynamicModel extends Question public get currentIndex(): number { if (this.isRenderModeList) return -1; if (this.useTemplatePanel) return 0; - return this.visiblePanels.indexOf(this.currentPanel); + return this.visiblePanelsCore.indexOf(this.currentPanel); } public set currentIndex(val: number) { if(val < 0 || this.visiblePanelCount < 1) return; if(val >= this.visiblePanelCount) val = this.visiblePanelCount - 1; - this.currentPanel = this.visiblePanels[val]; + this.currentPanel = this.visiblePanelsCore[val]; } /** * A `PanelModel` object that is the currently displayed panel. @@ -548,7 +556,7 @@ export class QuestionPanelDynamicModel extends Question if(this.isRenderModeList || this.useTemplatePanel) return null; let res = this.getPropertyValue("currentPanel", null); if(!res && this.visiblePanelCount > 0) { - res = this.visiblePanels[0]; + res = this.visiblePanelsCore[0]; this.currentPanel = res; } return res; @@ -556,7 +564,7 @@ export class QuestionPanelDynamicModel extends Question public set currentPanel(val: PanelModel) { if(this.isRenderModeList || this.useTemplatePanel) return; const curPanel = this.getPropertyValue("currentPanel"); - const index = !!val ? this.visiblePanels.indexOf(val) : -1; + const index = !!val ? this.visiblePanelsCore.indexOf(val) : -1; if(!!val && index < 0 || val === curPanel) return; if(curPanel) { curPanel.onHidingContent(); @@ -579,7 +587,7 @@ export class QuestionPanelDynamicModel extends Question this.currentPanel.onHidingContent(); } else { - this.visiblePanels.forEach(panel => panel.onHidingContent()); + this.visiblePanelsCore.forEach(panel => panel.onHidingContent()); } } /** @@ -755,13 +763,13 @@ export class QuestionPanelDynamicModel extends Question } public setIsMobile(val: boolean) { super.setIsMobile(val); - (this.panels || []).forEach(panel => panel.getQuestions(true).forEach(question => { + (this.panelsCore || []).forEach(panel => panel.getQuestions(true).forEach(question => { question.setIsMobile(val); })); } public themeChanged(theme: ITheme): void { super.themeChanged(theme); - (this.panels || []).forEach(panel => + (this.panelsCore || []).forEach(panel => panel.getQuestions(true).forEach(question => { question.themeChanged(theme); }) @@ -774,22 +782,22 @@ export class QuestionPanelDynamicModel extends Question * @see maxPanelCount */ public get panelCount(): number { - return this.isLoadingFromJson || this.useTemplatePanel + return !this.canBuildPanels || this.wasNotRenderedInSurvey ? this.getPropertyValue("panelCount") - : this.panels.length; + : this.panelsCore.length; } public set panelCount(val: number) { if (val < 0) return; - if (this.isLoadingFromJson || this.useTemplatePanel) { + if (!this.canBuildPanels || this.wasNotRenderedInSurvey) { this.setPropertyValue("panelCount", val); return; } - if (val == this.panels.length || this.useTemplatePanel) return; + if (val == this.panelsCore.length || this.useTemplatePanel) return; this.updateBindings("panelCount", val); this.prepareValueForPanelCreating(); for (let i = this.panelCount; i < val; i++) { - var panel = this.createNewPanel(); - this.panels.push(panel); + const panel = this.createNewPanel(); + this.panelsCore.push(panel); if (this.renderMode == "list" && this.panelsState != "default") { if (this.panelsState === "expand") { panel.expand(); @@ -802,7 +810,7 @@ export class QuestionPanelDynamicModel extends Question } let removedPanels:Array = []; if (val < this.panelCount) { - removedPanels = this.panels.splice(val, this.panelCount - val); + removedPanels = this.panelsCore.splice(val, this.panelCount - val); } this.setValueAfterPanelsCreating(); this.setValueBasedOnPanelCount(); @@ -841,8 +849,8 @@ export class QuestionPanelDynamicModel extends Question ); } private setPanelsSurveyImpl() { - for (var i = 0; i < this.panels.length; i++) { - var panel = this.panels[i]; + for (var i = 0; i < this.panelsCore.length; i++) { + var panel = this.panelsCore[i]; if (panel == this.template) continue; panel.setSurveyImpl(panel.data); } @@ -850,12 +858,12 @@ export class QuestionPanelDynamicModel extends Question private setPanelsState() { if (this.useTemplatePanel || this.renderMode != "list" || !this.templateTitle) return; - for (var i = 0; i < this.panels.length; i++) { + for (var i = 0; i < this.panelsCore.length; i++) { var state = this.panelsState; if (state === "firstExpanded") { state = i === 0 ? "expanded" : "collapsed"; } - this.panels[i].state = state; + this.panelsCore[i].state = state; } } private setValueBasedOnPanelCount() { @@ -1065,9 +1073,9 @@ export class QuestionPanelDynamicModel extends Question public setVisibleIndex(value: number): number { if (!this.isVisible) return 0; var startIndex = this.showQuestionNumbers == "onSurvey" ? value : 0; - for (var i = 0; i < this.visiblePanels.length; i++) { + for (var i = 0; i < this.visiblePanelsCore.length; i++) { var counter = this.setPanelVisibleIndex( - this.visiblePanels[i], + this.visiblePanelsCore[i], startIndex, this.showQuestionNumbers != "off" ); @@ -1152,7 +1160,7 @@ export class QuestionPanelDynamicModel extends Question panels.push(this.createNewPanel()); } } - this.panels.splice(0, this.panels.length, ...panels); + this.panelsCore.splice(0, this.panelsCore.length, ...panels); this.setValueAfterPanelsCreating(); this.setPanelsState(); this.reRunCondition(); @@ -1214,7 +1222,7 @@ export class QuestionPanelDynamicModel extends Question } public getProgressInfo(): IProgressInfo { return SurveyElement.getProgressInfoByElements( - this.visiblePanels, + this.visiblePanelsCore, this.isRequired ); } @@ -1263,7 +1271,7 @@ export class QuestionPanelDynamicModel extends Question this.currentIndex = index; } if (this.survey) this.survey.dynamicPanelAdded(this); - return this.panels[index]; + return this.panelsCore[index]; } private updateValueOnAddingPanel(prevIndex: number, index: number): void { this.panelCount++; @@ -1319,7 +1327,7 @@ export class QuestionPanelDynamicModel extends Question if(!this.confirmDelete) return false; const index = this.getVisualPanelIndex(val); if(index < 0 || index >= this.visiblePanelCount) return false; - const panelValue = this.visiblePanels[index].getValue(); + const panelValue = this.visiblePanelsCore[index].getValue(); return !this.isValueEmpty(panelValue) && (this.isValueEmpty(this.defaultPanelValue) || !this.isTwoValueEquals(panelValue, this.defaultPanelValue)); } @@ -1349,11 +1357,11 @@ export class QuestionPanelDynamicModel extends Question public removePanel(value: any): void { const visIndex = this.getVisualPanelIndex(value); if (visIndex < 0 || visIndex >= this.visiblePanelCount) return; - const panel = this.visiblePanels[visIndex]; - const index = this.panels.indexOf(panel); + const panel = this.visiblePanelsCore[visIndex]; + const index = this.panelsCore.indexOf(panel); if(index < 0) return; if (this.survey && !this.survey.dynamicPanelRemoving(this, index, panel)) return; - this.panels.splice(index, 1); + this.panelsCore.splice(index, 1); this.updateBindings("panelCount", this.panelCount); var value = this.value; if (!value || !Array.isArray(value) || index >= value.length) return; @@ -1367,21 +1375,21 @@ export class QuestionPanelDynamicModel extends Question } private getVisualPanelIndex(val: any): number { if (Helpers.isNumber(val)) return val; - const visPanels = this.visiblePanels; + const visPanels = this.visiblePanelsCore; for (var i = 0; i < visPanels.length; i++) { if (visPanels[i] === val || visPanels[i].data === val) return i; } return -1; } private getPanelIndexById(id: string): number { - for (var i = 0; i < this.panels.length; i++) { - if (this.panels[i].id === id) return i; + for (var i = 0; i < this.panelsCore.length; i++) { + if (this.panelsCore[i].id === id) return i; } return -1; } public locStrsChanged() { super.locStrsChanged(); - var panels = this.panels; + var panels = this.panelsCore; for (var i = 0; i < panels.length; i++) { panels[i].locStrsChanged(); } @@ -1390,22 +1398,22 @@ export class QuestionPanelDynamicModel extends Question } } public clearIncorrectValues() { - for (var i = 0; i < this.panels.length; i++) { + for (var i = 0; i < this.panelsCore.length; i++) { this.clearIncorrectValuesInPanel(i); } } public clearErrors() { super.clearErrors(); - for (var i = 0; i < this.panels.length; i++) { - this.panels[i].clearErrors(); + for (var i = 0; i < this.panelsCore.length; i++) { + this.panelsCore[i].clearErrors(); } } public getQuestionFromArray(name: string, index: number): IQuestion { if (index >= this.panelCount) return null; - return this.panels[index].getQuestionByName(name); + return this.panelsCore[index].getQuestionByName(name); } private clearIncorrectValuesInPanel(index: number) { - var panel = this.panels[index]; + var panel = this.panelsCore[index]; panel.clearIncorrectValues(); var val = this.value; var values = !!val && index < val.length ? val[index] : null; @@ -1494,7 +1502,7 @@ export class QuestionPanelDynamicModel extends Question } } protected collectNestedQuestionsCore(questions: Question[], visibleOnly: boolean): void { - const panels = visibleOnly ? this.visiblePanels : this.panels; + const panels = visibleOnly ? this.visiblePanelsCore : this.panelsCore; if(!Array.isArray(panels)) return; panels.forEach(panel => { panel.questions.forEach(q => q.collectNestedQuestions(questions, visibleOnly)); @@ -1515,8 +1523,8 @@ export class QuestionPanelDynamicModel extends Question protected onReadOnlyChanged(): void { var readOnly = this.isReadOnly; this.template.readOnly = readOnly; - for (var i = 0; i < this.panels.length; i++) { - this.panels[i].readOnly = readOnly; + for (var i = 0; i < this.panelsCore.length; i++) { + this.panelsCore[i].readOnly = readOnly; } this.updateNoEntriesTextDefaultLoc(); this.updateFooterActions(); @@ -1531,6 +1539,16 @@ export class QuestionPanelDynamicModel extends Question public onSurveyLoad(): void { this.template.readOnly = this.isReadOnly; this.template.onSurveyLoad(); + this.buildPanelsFirstTime(); + super.onSurveyLoad(); + } + private hasPanelBuildFirstTime: boolean; + private isBuildingPanelsFirstTime: boolean; + private buildPanelsFirstTime(force: boolean = false): void { + if(this.hasPanelBuildFirstTime) return; + if(!force && this.wasNotRenderedInSurvey) return; + this.hasPanelBuildFirstTime = true; + this.isBuildingPanelsFirstTime = true; if (this.getPropertyValue("panelCount") > 0) { this.panelCount = this.getPropertyValue("panelCount"); } @@ -1550,28 +1568,35 @@ export class QuestionPanelDynamicModel extends Question this.updateNoEntriesTextDefaultLoc(); } this.updateFooterActions(); - super.onSurveyLoad(); + this.isBuildingPanelsFirstTime = false; + } + private get wasNotRenderedInSurvey(): boolean { + return !this.hasPanelBuildFirstTime && !this.wasRendered && !!this.survey; + } + private get canBuildPanels(): boolean { + return !this.isLoadingFromJson && !this.useTemplatePanel; } - public onFirstRendering() { + public onFirstRendering(): void { + super.onFirstRendering(); + this.buildPanelsFirstTime(); this.template.onFirstRendering(); - for (var i = 0; i < this.panels.length; i++) { - this.panels[i].onFirstRendering(); + for (var i = 0; i < this.panelsCore.length; i++) { + this.panelsCore[i].onFirstRendering(); } - super.onFirstRendering(); } public localeChanged() { super.localeChanged(); - for (var i = 0; i < this.panels.length; i++) { - this.panels[i].localeChanged(); + for (var i = 0; i < this.panelsCore.length; i++) { + this.panelsCore[i].localeChanged(); } } public runCondition(values: HashTable, properties: HashTable) { super.runCondition(values, properties); - this.runPanelsCondition(this.panels, values, properties); + this.runPanelsCondition(this.panelsCore, values, properties); } public runTriggers(name: string, value: any): void { super.runTriggers(name, value); - this.visiblePanels.forEach(p => { + this.visiblePanelsCore.forEach(p => { p.questions.forEach(q => q.runTriggers(name, value)); }); } @@ -1607,17 +1632,17 @@ export class QuestionPanelDynamicModel extends Question } onAnyValueChanged(name: string, questionName: string): void { super.onAnyValueChanged(name, questionName); - for (var i = 0; i < this.panels.length; i++) { - this.panels[i].onAnyValueChanged(name, questionName); - this.panels[i].onAnyValueChanged(QuestionPanelDynamicItem.ItemVariableName, ""); + for (var i = 0; i < this.panelsCore.length; i++) { + this.panelsCore[i].onAnyValueChanged(name, questionName); + this.panelsCore[i].onAnyValueChanged(QuestionPanelDynamicItem.ItemVariableName, ""); } } private hasKeysDuplicated(fireCallback: boolean, rec: any = null) { var keyValues: Array = []; var res; - for (var i = 0; i < this.panels.length; i++) { + for (var i = 0; i < this.panelsCore.length; i++) { res = - this.isValueDuplicated(this.panels[i], keyValues, rec, fireCallback) || + this.isValueDuplicated(this.panelsCore[i], keyValues, rec, fireCallback) || res; } return res; @@ -1632,7 +1657,7 @@ export class QuestionPanelDynamicModel extends Question this.updateContainsErrors(); } public hasErrors(fireCallback: boolean = true, rec: any = null): boolean { - if (this.isValueChangingInternally) return false; + if (this.isValueChangingInternally || this.isBuildingPanelsFirstTime) return false; var res = false; if (!!this.changingValueQuestion) { var res = this.changingValueQuestion.hasErrors(fireCallback, rec); @@ -1646,7 +1671,7 @@ export class QuestionPanelDynamicModel extends Question protected getContainsErrors(): boolean { var res = super.getContainsErrors(); if (res) return res; - var panels = this.panels; + var panels = this.panelsCore; for (var i = 0; i < panels.length; i++) { if (panels[i].containsErrors) return true; } @@ -1654,7 +1679,7 @@ export class QuestionPanelDynamicModel extends Question } protected getIsAnswered(): boolean { if (!super.getIsAnswered()) return false; - var panels = this.visiblePanels; + var panels = this.visiblePanelsCore; for (var i = 0; i < panels.length; i++) { var visibleQuestions = >[]; panels[i].addQuestionsToList(visibleQuestions, true); @@ -1677,8 +1702,8 @@ export class QuestionPanelDynamicModel extends Question super.clearValueIfInvisible(reason); } private clearValueInPanelsIfInvisible(reason: string): void { - for (var i = 0; i < this.panels.length; i++) { - var questions = this.panels[i].questions; + for (var i = 0; i < this.panelsCore.length; i++) { + var questions = this.panelsCore[i].questions; this.isSetPanelItemData = {}; for (var j = 0; j < questions.length; j++) { const q = questions[j]; @@ -1690,8 +1715,8 @@ export class QuestionPanelDynamicModel extends Question } protected getIsRunningValidators(): boolean { if (super.getIsRunningValidators()) return true; - for (var i = 0; i < this.panels.length; i++) { - var questions = this.panels[i].questions; + for (var i = 0; i < this.panelsCore.length; i++) { + var questions = this.panelsCore[i].questions; for (var j = 0; j < questions.length; j++) { if (questions[j].isRunningValidators) return true; } @@ -1700,7 +1725,7 @@ export class QuestionPanelDynamicModel extends Question } public getAllErrors(): Array { var result = super.getAllErrors(); - const panels = this.visiblePanels; + const panels = this.visiblePanelsCore; for (var i = 0; i < panels.length; i++) { var questions = panels[i].questions; for (var j = 0; j < questions.length; j++) { @@ -1715,7 +1740,7 @@ export class QuestionPanelDynamicModel extends Question protected getDisplayValueCore(keysAsText: boolean, value: any): any { var values = this.getUnbindValue(value); if (!values || !Array.isArray(values)) return values; - for (var i = 0; i < this.panels.length && i < values.length; i++) { + for (var i = 0; i < this.panelsCore.length && i < values.length; i++) { var val = values[i]; if (!val) continue; values[i] = this.getPanelDisplayValue(i, val, keysAsText); @@ -1729,7 +1754,7 @@ export class QuestionPanelDynamicModel extends Question keysAsText: boolean ): any { if (!val) return val; - var panel = this.panels[panelIndex]; + var panel = this.panelsCore[panelIndex]; var keys = Object.keys(val); for (var i = 0; i < keys.length; i++) { var key = keys[i]; @@ -1750,7 +1775,7 @@ export class QuestionPanelDynamicModel extends Question } private hasErrorInPanels(fireCallback: boolean, rec: any): boolean { var res = false; - var panels = this.visiblePanels; + var panels = this.visiblePanelsCore; var keyValues: Array = []; for (var i = 0; i < panels.length; i++) { this.setOnCompleteAsyncInPanel(panels[i]); @@ -1886,16 +1911,16 @@ export class QuestionPanelDynamicModel extends Question if(this.settingPanelCountBasedOnValue) return; super.setQuestionValue(newValue, false); this.setPanelCountBasedOnValue(); - for (var i = 0; i < this.panels.length; i++) { - this.panelUpdateValueFromSurvey(this.panels[i]); + for (var i = 0; i < this.panelsCore.length; i++) { + this.panelUpdateValueFromSurvey(this.panelsCore[i]); } this.updateIsAnswered(); } public onSurveyValueChanged(newValue: any) { if(newValue === undefined && this.isAllPanelsEmpty()) return; super.onSurveyValueChanged(newValue); - for (var i = 0; i < this.panels.length; i++) { - this.panelSurveyValueChanged(this.panels[i]); + for (var i = 0; i < this.panelsCore.length; i++) { + this.panelSurveyValueChanged(this.panelsCore[i]); } if (newValue === undefined) { this.setValueBasedOnPanelCount(); @@ -1903,8 +1928,8 @@ export class QuestionPanelDynamicModel extends Question this.updateIsReady(); } private isAllPanelsEmpty(): boolean { - for (var i = 0; i < this.panels.length; i++) { - if(!Helpers.isValueEmpty(this.panels[i].getValue())) + for (var i = 0; i < this.panelsCore.length; i++) { + if(!Helpers.isValueEmpty(this.panelsCore[i].getValue())) return false; } return true; @@ -1945,7 +1970,7 @@ export class QuestionPanelDynamicModel extends Question return res > -1 ? res : this.items.length; } getVisibleItemIndex(item: ISurveyData): number { - const visPanels = this.visiblePanels; + const visPanels = this.visiblePanelsCore; for(var i = 0; i < visPanels.length; i ++) { if(visPanels[i].data === item) return i; } @@ -1989,8 +2014,8 @@ export class QuestionPanelDynamicModel extends Question } else { delete qValue[index][name]; } - if (index >= 0 && index < this.panels.length) { - this.changingValueQuestion = this.panels[index].getQuestionByValueName( + if (index >= 0 && index < this.panelsCore.length) { + this.changingValueQuestion = this.panelsCore[index].getQuestionByValueName( name ); } @@ -2048,8 +2073,8 @@ export class QuestionPanelDynamicModel extends Question } public updateElementCss(reNew?: boolean) { super.updateElementCss(reNew); - for (var i = 0; i < this.panels.length; i++) { - var el = this.panels[i]; + for (var i = 0; i < this.panelsCore.length; i++) { + var el = this.panelsCore[i]; el.updateElementCss(reNew); } } @@ -2249,7 +2274,7 @@ export class QuestionPanelDynamicModel extends Question private updateTabToolbarItemsPressedState() { if(!this.isRenderModeTab) return; if(this.currentIndex < 0 || this.currentIndex >= this.visiblePanelCount) return; - const panel = this.visiblePanels[this.currentIndex]; + const panel = this.visiblePanelsCore[this.currentIndex]; this.additionalTitleToolbar.renderedActions.forEach(action => { const isActive = action.id === panel.id; action.pressed = isActive; @@ -2264,9 +2289,9 @@ export class QuestionPanelDynamicModel extends Question if(!this.isRenderModeTab) return; const items: Array = []; - const visPanels = this.visiblePanels; + const visPanels = this.visiblePanelsCore; for(let i = 0; i < visPanels.length; i ++) { - this.visiblePanels.forEach(panel => items.push(this.createTabByPanel(visPanels[i], i))); + this.visiblePanelsCore.forEach(panel => items.push(this.createTabByPanel(visPanels[i], i))); } this.additionalTitleToolbar.setItems(items); } diff --git a/src/survey-element.ts b/src/survey-element.ts index 8f42f90b8c..ddf13b7947 100644 --- a/src/survey-element.ts +++ b/src/survey-element.ts @@ -632,13 +632,16 @@ export class SurveyElement extends SurveyElementCore implements ISurvey public set selectedElementInDesign(val: SurveyElement) { this.selectedElementInDesignValue = val; } - public updateCustomWidgets() { } + public updateCustomWidgets(): void { } - public onSurveyLoad() { } - public onFirstRendering() { + public onSurveyLoad(): void { } + private wasRenderedValue: boolean; + public get wasRendered(): boolean { return !!this.wasRenderedValue; } + public onFirstRendering(): void { + this.wasRenderedValue = true; this.ensureCssClassesValue(); } - endLoadingFromJson() { + endLoadingFromJson(): void { super.endLoadingFromJson(); if (!this.survey) { this.onSurveyLoad(); @@ -652,21 +655,21 @@ export class SurveyElement extends SurveyElementCore implements ISurvey * Returns `true` if the survey element is a page. * @see Base.getType */ - public get isPage() { + public get isPage(): boolean { return false; } /** * Returns `true` if the survey element is a panel. * @see Base.getType */ - public get isPanel() { + public get isPanel(): boolean { return false; } /** * Returns `true` if the survey element is a question. * @see Base.getType */ - public get isQuestion() { + public get isQuestion(): boolean { return false; } public delete(doDispose: boolean): void { } diff --git a/src/survey.ts b/src/survey.ts index f1f5c5d545..09f8e9b8ef 100644 --- a/src/survey.ts +++ b/src/survey.ts @@ -4011,7 +4011,7 @@ export class SurveyModel extends SurveyElementCore * @see showPreviewBeforeComplete * @see state */ - public cancelPreview(currentPage: any = null) { + public cancelPreview(currentPage: any = null): void { if (!this.isShowingPreview) return; this.gotoPageFromPreview = currentPage; this.isShowingPreview = false; diff --git a/tests/question_paneldynamic_tests.ts b/tests/question_paneldynamic_tests.ts index 41cbf9beab..6c754acd47 100644 --- a/tests/question_paneldynamic_tests.ts +++ b/tests/question_paneldynamic_tests.ts @@ -4094,7 +4094,6 @@ QUnit.test( assert.ok(rootPanel, "root panel is here"); var nestedPanel = rootPanel.panels[0].getQuestionByName("nested1"); assert.ok(nestedPanel, "nested panel is here"); - nestedPanel.addPanel(); //TODO there is should be one panel assert.equal( nestedPanel.panels.length, 1, @@ -4302,8 +4301,8 @@ QUnit.test( assert.equal(panel.panels[0].questions[0].displayValue, "Item2", "display value is correct, #1"); survey.cancelPreview(); panel = survey.getQuestionByName("panel"); - assert.equal(panel.panels[0].questions[0].choices.length, 2, "Choices is added, #1"); - assert.equal(panel.panels[0].questions[0].displayValue, "Item2", "display value is correct, #1"); + assert.equal(panel.panels[0].questions[0].choices.length, 2, "Choices is added, #2"); + assert.equal(panel.panels[0].questions[0].displayValue, "Item2", "display value is correct, #2"); } ); @@ -4544,7 +4543,7 @@ QUnit.test("Support panel dynamic for isContainerReady", function (assert) { assert.equal(exp.value, true, "exp"); }); -QUnit.test("cssClasses for a question in nested panel dynamic", function (assert) { +QUnit.test("cssClasses for a question in nested panel dynamic, #1", function (assert) { var survey = new SurveyModel({ elements: [ { @@ -4573,7 +4572,7 @@ QUnit.test("cssClasses for a question in nested panel dynamic", function (assert const question = nestedPanel.panels[0].getQuestionByName("q1"); assert.ok(question.cssClassesValue.mainRoot, "Main root style is set"); }); -QUnit.test("cssClasses for a question in nested panel dynamic", function (assert) { +QUnit.test("cssClasses for a question in nested panel dynamic, #2", function (assert) { var survey = new SurveyModel({ elements: [ { diff --git a/tests/surveytests.ts b/tests/surveytests.ts index 13fb7685ea..4e78e6c9b6 100644 --- a/tests/surveytests.ts +++ b/tests/surveytests.ts @@ -16619,7 +16619,7 @@ QUnit.test("progress is not changed on the start page", function (assert) { question.value = ["1"]; assert.equal(progressChangeCount, 0, "Progress hasn't been called"); }); -QUnit.test("Make sure that panel is not collapsed on focusing the question", function (assert) { +QUnit.test("Make sure that panel is not collapsed on focusing the question, #2", function (assert) { const survey = new SurveyModel({ elements: [ { @@ -18692,3 +18692,50 @@ QUnit.test("Check triggerReponsiveness is called when isCompact changed", functi survey["isCompact"] = false; assert.equal(log, "->q1:true->q2:true"); }); +QUnit.test("element.wasREndered", function (assert) { + const json = { + pages: [ + { + "elements": [ + { + type: "text", + name: "q1" + } + ] + }, + { + "elements": [ + { + type: "text", + name: "q2" + } + ] + }, + ] + }; + const survey = new SurveyModel(json); + assert.equal(survey.pages[0].wasRendered, true, "page1 wasRendered"); + assert.equal(survey.getQuestionByName("q1").wasRendered, true, "q1 wasRendered"); + const q3 = survey.pages[0].addNewQuestion("text", "q3"); + assert.equal(q3.wasRendered, true, "q3 wasRendered"); + const panel1 = survey.pages[0].addNewPanel("panel1"); + assert.equal(panel1.wasRendered, true, "panel1 wasRendered"); + const q4 = panel1.addNewQuestion("text", "q4"); + assert.equal(q4.wasRendered, true, "q4 wasRendered"); + + assert.equal(survey.pages[1].wasRendered, false, "page2 wasRendered, #1"); + assert.equal(survey.getQuestionByName("q2").wasRendered, false, "q2 wasRendered, #1"); + const q5 = survey.pages[1].addNewQuestion("text", "q5"); + assert.equal(q5.wasRendered, false, "q5 wasRendered, #1"); + const panel2 = survey.pages[1].addNewPanel("panel1"); + assert.equal(panel2.wasRendered, false, "panel2 wasRendered, #1"); + const q6 = panel2.addNewQuestion("text", "q6"); + assert.equal(q6.wasRendered, false, "q6 wasRendered, #1"); + + survey.nextPage(); + assert.equal(survey.pages[1].wasRendered, true, "page2 wasRendered, #2"); + assert.equal(survey.getQuestionByName("q2").wasRendered, true, "q2 wasRendered, #2"); + assert.equal(q5.wasRendered, true, "q5 wasRendered, #2"); + assert.equal(panel2.wasRendered, true, "panel2 wasRendered, #2"); + assert.equal(q6.wasRendered, true, "q6 wasRendered, #2"); +});