Skip to content

Commit a4de099

Browse files
authored
Bug/9982 single input navigation prev (#10008)
* Implement Preview for adding/editing dynamic items * Remove summary link from the brandscrum * FIx unit tests, navigation issues * Add skipped unit tests for nested navigation. We will need to re-think the navigation * Fix infinity-loop image
1 parent 2699c50 commit a4de099

File tree

7 files changed

+318
-54
lines changed

7 files changed

+318
-54
lines changed

packages/survey-core/src/panel.ts

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -951,14 +951,12 @@ export class PanelModelBase extends SurveyElement<Question>
951951
* @see [Data Validation](https://surveyjs.io/form-library/documentation/data-validation)
952952
*/
953953
public validate(fireCallback: boolean = true, focusFirstError: boolean = false, rec: any = null): boolean {
954-
rec = !!rec
955-
? rec
956-
: {
957-
fireCallback: fireCallback,
958-
focusOnFirstError: focusFirstError,
959-
firstErrorQuestion: <any>null,
960-
result: false,
961-
};
954+
rec = rec || {
955+
fireCallback: fireCallback,
956+
focusOnFirstError: focusFirstError,
957+
firstErrorQuestion: <any>null,
958+
result: false,
959+
};
962960
if (rec.result !== true) rec.result = false;
963961
this.hasErrorsCore(rec);
964962
return !rec.result;

packages/survey-core/src/question.ts

Lines changed: 60 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -733,8 +733,9 @@ export class Question extends SurveyElement<Question>
733733
}
734734
const questions = this.getSingleInputQuestions();
735735
if (Array.isArray(questions) && questions.length > 0) {
736-
questions[0].onFirstRendering();
737-
return questions[0];
736+
const q = questions[0];
737+
this.onBeforeSetSingleInputQuestion(q);
738+
return q;
738739
}
739740
return undefined;
740741
}
@@ -798,8 +799,10 @@ export class Question extends SurveyElement<Question>
798799
this.onSingleInputChanged();
799800
}
800801
}
801-
private onSingleInputChanged(): void {
802-
this.resetSingleInputSummary();
802+
private onSingleInputChanged(resetSummary: boolean = true): void {
803+
if (resetSummary) {
804+
this.resetSingleInputSummary();
805+
}
803806
this.singleInputLocTitle?.strChanged();
804807
this.resetPropertyValue("singleInputLocTitle");
805808
this.calcSingleInputActions();
@@ -812,9 +815,20 @@ export class Question extends SurveyElement<Question>
812815
public validateSingleInput(fireCallback: boolean = true, rec: any = null): boolean {
813816
const q = this.currentSingleInputQuestion;
814817
if (!q) return true;
815-
return q.validate(fireCallback, rec);
818+
rec = rec || {
819+
fireCallback: fireCallback,
820+
focusOnFirstError: fireCallback,
821+
firstErrorQuestion: <any>null,
822+
result: false,
823+
};
824+
const res = q.validate(fireCallback, rec);
825+
if (!res && rec.focusOnFirstError && !!rec.firstErrorQuestion) {
826+
rec.firstErrorQuestion.focus(true);
827+
}
828+
return res;
816829
}
817830
public getSingleInputElementPos(): number {
831+
if (this.singleInputQuestion === this) return 0;
818832
const pQ = this.currentSingleInputParentQuestion;
819833
if (pQ !== this) {
820834
let res = pQ.getSingleInputElementPos();
@@ -859,7 +873,9 @@ export class Question extends SurveyElement<Question>
859873
this.resetSingleInput();
860874
}
861875
}
876+
private isSingleInputSummaryShown: boolean;
862877
public onSetAsSingleInput(): void {
878+
this.isSingleInputSummaryShown = false;
863879
const needReset = !this.wasRendered || this.singleInputSummary;
864880
this.onFirstRendering();
865881
if (needReset) {
@@ -941,7 +957,7 @@ export class Question extends SurveyElement<Question>
941957
private getSingleQuestionActions(): Array<Action> {
942958
const res = new Array<Action>();
943959
const p = this.currentSingleInputParentQuestion;
944-
if (!p) return res;
960+
if (!p || p === this) return res;
945961
const pSQs = p.getSingleInputQuestions();
946962
const qs = new Array<Question>();
947963
let summaryQ = undefined;
@@ -956,21 +972,27 @@ export class Question extends SurveyElement<Question>
956972
}
957973
for (let i = qs.length - 1; i >= 0; i--) {
958974
const q = qs[i];
959-
const title = q == summaryQ ? q.locTitle : q.singleInputLocTitle;
960-
const action = new Action({ id: "single-action" + q.id, locTitle: title,
961-
css: this.cssClasses.breadcrumbsItem,
962-
innerCss: this.cssClasses.breadcrumbsItemButton,
963-
action: () => {
964-
if (q == summaryQ) {
965-
q.setSingleInputQuestion(q);
966-
} else {
975+
if (q !== summaryQ) {
976+
//const title = q == summaryQ ? q.locTitle : q.singleInputLocTitle;
977+
const title = q.singleInputLocTitle;
978+
const action = new Action({ id: "single-action" + q.id, locTitle: title,
979+
css: this.cssClasses.breadcrumbsItem,
980+
innerCss: this.cssClasses.breadcrumbsItemButton,
981+
action: () => {
967982
q.singleInputMoveToFirst();
983+
/*
984+
if (q == summaryQ) {
985+
q.setSingleInputQuestion(q);
986+
} else {
987+
q.singleInputMoveToFirst();
988+
}
989+
*/
968990
}
969-
}
970-
});
991+
});
971992

972-
action.cssClasses = {};
973-
res.push(action);
993+
action.cssClasses = {};
994+
res.push(action);
995+
}
974996
}
975997
return res;
976998
}
@@ -993,23 +1015,25 @@ export class Question extends SurveyElement<Question>
9931015
}
9941016
private getSingleInputQuestions(): Array<Question> {
9951017
if (!this.supportNestedSingleInput()) return [];
996-
const res = this.getSingleInputQuestionsCore(this.getPropertyValue("singleInputQuestion"));
1018+
const question = this.getPropertyValue("singleInputQuestion");
1019+
if (question === this) return [this];
1020+
const res = this.getSingleInputQuestionsCore(question, !question || !this.isSingleInputSummaryShown);
9971021
res.forEach(q => { if (q !== this)this.onSingleInputQuestionAdded(q); });
9981022
return res;
9991023
}
1000-
protected getSingleInputQuestionsCore(question: Question): Array<Question> {
1024+
protected getSingleInputQuestionsCore(question: Question, checkDynamic: boolean): Array<Question> {
10011025
return this.getNestedQuestions(true, false);
10021026
}
10031027
protected onSingleInputQuestionAdded(question: Question): void {}
10041028
protected fillSingleInputQuestionsInContainer(res: Array<Question>, innerQuestion: Question): void {}
1005-
protected getSingleInputQuestionsForDynamic(question?: Question): Array<Question> {
1029+
protected getSingleInputQuestionsForDynamic(question: Question, arr: Array<Question>): Array<Question> {
10061030
const res = new Array<Question>();
1007-
if (question) {
1008-
this.setSingleInputQuestionCore(question);
1031+
if (!!question && question !== this && arr.indexOf(question) < 0) {
1032+
this.fillSingleInputQuestionsInContainer(res, question);
10091033
}
1010-
const q = this.getPropertyValue("singleInputQuestion");
1011-
if (!!q && q !== this) {
1012-
this.fillSingleInputQuestionsInContainer(res, q);
1034+
arr.forEach(q => res.push(q));
1035+
if (this.isSingleInputSummaryShown && res.length > 0) {
1036+
res.unshift(this);
10131037
}
10141038
res.push(this);
10151039
return res;
@@ -1018,13 +1042,19 @@ export class Question extends SurveyElement<Question>
10181042
protected singleInputAddItemCore(): void {}
10191043
protected singleInputRemoveItemCore(question: Question): void {}
10201044
private setSingleInputQuestionCore(question: Question): void {
1021-
question.onFirstRendering();
1045+
this.onBeforeSetSingleInputQuestion(question);
10221046
this.setPropertyValue("singleInputQuestion", question);
10231047
}
1024-
protected setSingleInputQuestion(question: Question): void {
1048+
private onBeforeSetSingleInputQuestion(question: Question): void {
1049+
question.onFirstRendering();
1050+
if (question === this) {
1051+
this.isSingleInputSummaryShown = true;
1052+
}
1053+
}
1054+
protected setSingleInputQuestion(question: Question, onPrev?: boolean): void {
10251055
if (this.singleInputQuestion !== question) {
10261056
this.setSingleInputQuestionCore(question);
1027-
this.onSingleInputChanged();
1057+
this.onSingleInputChanged(!onPrev || question !== this);
10281058
}
10291059
}
10301060
private nextPrevSingleInput(skip: number): boolean {
@@ -1045,7 +1075,7 @@ export class Question extends SurveyElement<Question>
10451075
}
10461076
index += skip;
10471077
if (index < 0 || index >= questions.length) return false;
1048-
this.setSingleInputQuestion(questions[index]);
1078+
this.setSingleInputQuestion(questions[index], skip < 0);
10491079
return true;
10501080
}
10511081
/**

packages/survey-core/src/question_matrix.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -472,7 +472,7 @@ export class QuestionMatrixModel
472472
}
473473
return null;
474474
}
475-
protected getSingleInputQuestionsCore(question: Question): Array<Question> {
475+
protected getSingleInputQuestionsCore(question: Question, checkDynamic: boolean): Array<Question> {
476476
if (!!this.nestedQuestionsValue) return this.nestedQuestionsValue;
477477
const res: Array<Question> = [];
478478
this.visibleRows.forEach(row => {

packages/survey-core/src/question_matrixdynamic.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -731,18 +731,18 @@ export class QuestionMatrixDynamicModel extends QuestionMatrixDropdownModelBase
731731
question.titleLocation = "hidden";
732732
}
733733
}
734-
protected getSingleInputQuestionsCore(question: Question): Array<Question> {
734+
protected getSingleInputQuestionsCore(question: Question, checkDynamic: boolean): Array<Question> {
735735
const res = new Array<Question>();
736736
const rows = this.visibleRows;
737-
if ((!question || question === this) && rows.length > 0) {
737+
if (checkDynamic) {
738738
for (let i = 0; i < rows.length; i ++) {
739739
const row = rows[i];
740740
if (!row.hasValueAnyQuestion(true) || row.hasErrors(false, {}, () => {})) {
741741
this.fillSingleInputQuestionsByRow(res, row);
742742
}
743743
}
744744
}
745-
return this.getSingleInputQuestionsForDynamic(res.length > 0 ? res[0] : null);
745+
return this.getSingleInputQuestionsForDynamic(question, res);
746746
}
747747
protected fillSingleInputQuestionsInContainer(res: Array<Question>, innerQuestion: Question): void {
748748
const row = this.getRowByQuestion(innerQuestion);

packages/survey-core/src/question_paneldynamic.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1231,19 +1231,19 @@ export class QuestionPanelDynamicModel extends Question
12311231
super.resetSingleInput();
12321232
this.locTemplateTitle.onGetTextCallback = null;
12331233
}
1234-
protected getSingleInputQuestionsCore(question: Question): Array<Question> {
1234+
protected getSingleInputQuestionsCore(question: Question, checkDynamic: boolean): Array<Question> {
12351235
this.onFirstRendering();
12361236
const res = new Array<Question>();
12371237
const panels = this.visiblePanels;
1238-
if ((!question || question === this) && panels.length > 0) {
1238+
if (checkDynamic) {
12391239
for (let i = 0; i < panels.length; i ++) {
12401240
const panel = panels[i];
12411241
if (!panel.hasValueAnyQuestion(true) || panel.hasErrors(false, false)) {
12421242
this.fillSingleInputQuestionsByPanel(res, panel);
12431243
}
12441244
}
12451245
}
1246-
return this.getSingleInputQuestionsForDynamic(res.length > 0 ? res[0] : null);
1246+
return this.getSingleInputQuestionsForDynamic(question, res);
12471247
}
12481248
protected fillSingleInputQuestionsInContainer(res: Array<Question>, innerQuestion: Question): void {
12491249
const panel = this.getPanelByQuestion(innerQuestion);

0 commit comments

Comments
 (0)