From 2e2a8dd60616d758c6b788592ab640b943c78c5b Mon Sep 17 00:00:00 2001 From: OlgaLarina Date: Wed, 24 Jul 2024 16:39:06 +0300 Subject: [PATCH 01/27] textarea component enhancement --- src/entries/core-wo-model.ts | 1 + src/entries/react-ui-model.ts | 1 + src/knockout/templates/comment.html | 54 ++++++++- src/knockout/templates/question-comment.html | 6 +- src/question.ts | 21 ++++ src/question_baseselect.ts | 21 ++++ src/question_comment.ts | 25 ++++ src/react/components/textarea.tsx | 77 +++++++++++++ src/react/reactquestion_comment.tsx | 107 ++++++++++-------- src/utils/textarea.ts | 94 +++++++++++++++ .../snapshots/checkbox-comment-V2.snap.html | 2 +- ...nt-into-question-commentAreaRows.snap.html | 2 +- tests/surveyquestiontests.ts | 69 +++++++++++ 13 files changed, 421 insertions(+), 59 deletions(-) create mode 100644 src/react/components/textarea.tsx create mode 100644 src/utils/textarea.ts diff --git a/src/entries/core-wo-model.ts b/src/entries/core-wo-model.ts index b8d614011c..7519dfc402 100644 --- a/src/entries/core-wo-model.ts +++ b/src/entries/core-wo-model.ts @@ -18,3 +18,4 @@ export * from "../utils/animation"; export * from "../actions/adaptive-container"; export * from "../actions/container"; export * from "../utils/dragOrClickHelper"; +export * from "../utils/textarea"; diff --git a/src/entries/react-ui-model.ts b/src/entries/react-ui-model.ts index b3f1f75484..207371b762 100644 --- a/src/entries/react-ui-model.ts +++ b/src/entries/react-ui-model.ts @@ -1,4 +1,5 @@ // react +export { TextAreaComponent } from "../react/components/textarea"; export { Survey, attachKey2click } from "../react/reactSurvey"; export { ReactSurveyElementsWrapper } from "../react/reactsurveymodel"; export { SurveyNavigationBase } from "../react/reactSurveyNavigationBase"; diff --git a/src/knockout/templates/comment.html b/src/knockout/templates/comment.html index b97b538cf4..cd1164a4b7 100644 --- a/src/knockout/templates/comment.html +++ b/src/knockout/templates/comment.html @@ -1,12 +1,20 @@  + + \ No newline at end of file diff --git a/src/knockout/templates/question-comment.html b/src/knockout/templates/question-comment.html index c983a3a16e..1849883e93 100644 --- a/src/knockout/templates/question-comment.html +++ b/src/knockout/templates/question-comment.html @@ -1,10 +1,12 @@  - - \ No newline at end of file diff --git a/src/knockout/templates/question-comment.html b/src/knockout/templates/question-comment.html index 1849883e93..3f843a807f 100644 --- a/src/knockout/templates/question-comment.html +++ b/src/knockout/templates/question-comment.html @@ -1,19 +1,14 @@  \ No newline at end of file diff --git a/src/question.ts b/src/question.ts index d4ab65b465..8326dea2bb 100644 --- a/src/question.ts +++ b/src/question.ts @@ -22,7 +22,7 @@ import { ConsoleWarnings } from "./console-warnings"; import { ProcessValue } from "./conditionProcessValue"; import { ITheme } from "./themes"; import { DomWindowHelper } from "./global_variables_utils"; -import { ITextArea, TextAreaViewModel } from "./utils/textarea"; +import { ITextArea, TextAreaViewModel } from "./utils/text-area"; export interface IConditionObject { name: string; @@ -2493,11 +2493,9 @@ export class Question extends SurveyElement placeholder: this.renderedCommentPlaceholder, rows: this.commentAreaRows, maxLength: this.getOthersMaxLength(), - getTextValue: () => { return this.comment; }, - setTextValue: (newValue) => { this.comment = newValue; }, ariaRequired: this.a11y_input_ariaRequired, ariaLabel: this.a11y_input_ariaLabel, - + getTextValue: () => { return this.comment; }, onTextAreaChange: (e) => { this.onCommentChange(e); }, onTextAreaInput: (e) => { this.onCommentInput(e); }, }; diff --git a/src/question_baseselect.ts b/src/question_baseselect.ts index f711485883..f29759c0e7 100644 --- a/src/question_baseselect.ts +++ b/src/question_baseselect.ts @@ -13,7 +13,7 @@ import { Helpers, HashTable } from "./helpers"; import { settings } from "./settings"; import { CssClassBuilder } from "./utils/cssClassBuilder"; import { classesToSelector, mergeValues } from "./utils/utils"; -import { ITextArea, TextAreaViewModel } from "./utils/textarea"; +import { ITextArea, TextAreaViewModel } from "./utils/text-area"; /** * A base class for multiple-choice question types ([Checkboxes](https://surveyjs.io/form-library/documentation/questioncheckboxmodel), [Dropdown](https://surveyjs.io/form-library/documentation/questiondropdownmodel), [Radio Button Group](https://surveyjs.io/form-library/documentation/questionradiogroupmodel), etc.). @@ -1994,8 +1994,6 @@ export class QuestionSelectBase extends Question { ariaRequired: this.ariaRequired || this.a11y_input_ariaRequired, ariaLabel: this.ariaLabel || this.a11y_input_ariaLabel, getTextValue: () => { return this.otherValue; }, - setTextValue: (newValue) => { this.otherValue = newValue; }, - onTextAreaChange: (e) => { this.onOtherValueChange(e); }, onTextAreaInput: (e) => { this.onOtherValueInput(e); }, }; diff --git a/src/question_comment.ts b/src/question_comment.ts index f2cf3bec99..cd2bd8b4eb 100644 --- a/src/question_comment.ts +++ b/src/question_comment.ts @@ -3,7 +3,8 @@ import { QuestionFactory } from "./questionfactory"; import { QuestionTextBase } from "./question_textbase"; import { increaseHeightByContent } from "./utils/utils"; import { settings } from "./settings"; -import { ITextArea, TextAreaViewModel } from "./utils/textarea"; +import { ITextArea, TextAreaViewModel } from "./utils/text-area"; +import { Helpers } from "./helpers"; /** * A class that describes the Long Text question type. @@ -127,6 +128,13 @@ export class QuestionCommentModel extends QuestionTextBase { return (this.cssClasses ? this.getControlClass() : "panel-comment-root") || undefined; } public getTextArea(): ITextArea { + const _this = this; + const updateQuestionValue = (newValue: any) => { + if (!Helpers.isTwoValueEquals(_this.value, newValue, false, true, false)) { + _this.value = newValue; + } + }; + const options: ITextArea = { question: this, id: this.inputId, @@ -143,9 +151,8 @@ export class QuestionCommentModel extends QuestionTextBase { ariaDescribedBy: this.a11y_input_ariaDescribedBy, ariaInvalid: this.a11y_input_ariaInvalid, ariaErrormessage: this.a11y_input_ariaErrormessage, - - // onTextAreaChange: onBlur, - // onTextAreaInput: onInput, + getTextValue: () => { return this.value; }, + onTextAreaChange: (e) => { updateQuestionValue(e.target.value); }, onTextAreaInput: (event) => { this.onInput(event); }, onTextAreaKeyDown: (event) => { this.onKeyDown(event); }, }; diff --git a/src/react/components/textarea.tsx b/src/react/components/text-area.tsx similarity index 55% rename from src/react/components/textarea.tsx rename to src/react/components/text-area.tsx index 1d0bf04119..273e68dd82 100644 --- a/src/react/components/textarea.tsx +++ b/src/react/components/text-area.tsx @@ -1,43 +1,19 @@ import React from "react"; -import { Helpers, TextAreaViewModel } from "survey-core"; +import { TextAreaViewModel } from "survey-core"; import { ReactElementFactory } from "../element-factory"; import { SurveyElementBase } from "../reactquestion_element"; interface ITextAreaProps { - viewModelOptions: TextAreaViewModel; + viewModel: TextAreaViewModel; } export class TextAreaComponent extends SurveyElementBase { - private control: HTMLElement; - constructor(props: ITextAreaProps) { super(props); this.state = { comment: this.viewModel.getTextValue() || "" }; } get viewModel(): TextAreaViewModel { - return this.props.viewModelOptions; - } - componentDidUpdate(prevProps: any, prevState: any): void { - super.componentDidUpdate(prevProps, prevState); - this.updateDomElement(); - } - componentDidMount(): void { - super.componentDidMount(); - this.updateDomElement(); - } - protected updateDomElement(): void { - if (!!this.control) { - const control: any = this.control; - const newValue = this.viewModel.getTextValue() || ""; - if (!Helpers.isTwoValueEquals(newValue, control.value, false, true, false)) { - control.value = newValue; - } - } - } - protected setControl(element: HTMLElement | null): void { - if(!!element) { - this.control = element; - } + return this.props.viewModel; } protected canRender(): boolean { return !!this.viewModel.question; @@ -48,19 +24,18 @@ export class TextAreaComponent extends SurveyElementBase { + + +
{{ otherValue }}
diff --git a/packages/survey-angular-ui/src/comment-other.component.ts b/packages/survey-angular-ui/src/comment-other.component.ts index e5ae01c51b..0696bb54ce 100644 --- a/packages/survey-angular-ui/src/comment-other.component.ts +++ b/packages/survey-angular-ui/src/comment-other.component.ts @@ -1,5 +1,5 @@ import { Component, Input } from "@angular/core"; -import { Question, QuestionSelectBase } from "survey-core"; +import { Question, QuestionSelectBase, TextAreaModel } from "survey-core"; @Component({ selector: "sv-ng-comment-other, '[sv-ng-comment-other]'", @@ -13,16 +13,7 @@ export class SurveyCommentOtherComponent { const val = (this.question).otherValue; return !!val ? val : ""; } - public onOtherValueChange(event: any): void { - (this.question).onOtherValueChange(event); - } - public onOtherValueInput(event: any): void { - (this.question).onOtherValueInput(event); - } - public get otherId(): string { - return (this.question).otherId; - } - public get otherPlaceholder(): string { - return (this.question).otherPlaceholder; + public get textAreaModel(): TextAreaModel { + return (this.question).otherTextAreaModel; } } \ No newline at end of file diff --git a/packages/survey-angular-ui/src/comment.component.html b/packages/survey-angular-ui/src/comment.component.html index ed165a8e35..6f6f85bdd3 100644 --- a/packages/survey-angular-ui/src/comment.component.html +++ b/packages/survey-angular-ui/src/comment.component.html @@ -1,10 +1,4 @@ - + + +
{{ question.comment }}
diff --git a/packages/survey-angular-ui/src/components/text-area/text-area.component.html b/packages/survey-angular-ui/src/components/text-area/text-area.component.html new file mode 100644 index 0000000000..faefe29d63 --- /dev/null +++ b/packages/survey-angular-ui/src/components/text-area/text-area.component.html @@ -0,0 +1,22 @@ + diff --git a/packages/survey-angular-ui/src/components/text-area/text-area.component.ts b/packages/survey-angular-ui/src/components/text-area/text-area.component.ts new file mode 100644 index 0000000000..3b843b21b6 --- /dev/null +++ b/packages/survey-angular-ui/src/components/text-area/text-area.component.ts @@ -0,0 +1,18 @@ +import { Component, Input } from "@angular/core"; +import { TextAreaModel } from "survey-core"; +import { AngularComponentFactory } from "../../component-factory"; +import { EmbeddedViewContentComponent } from "../../embedded-view-content.component"; + +@Component({ + selector: "sv-text-area", + templateUrl: "./text-area.component.html" +}) +export class TextAreaComponent extends EmbeddedViewContentComponent { + @Input() model!: TextAreaModel; + + get value() { + return this.model.getTextValue(); + } +} + +AngularComponentFactory.Instance.registerComponent("sv-text-area", TextAreaComponent); \ No newline at end of file diff --git a/packages/survey-angular-ui/src/questions/comment.component.html b/packages/survey-angular-ui/src/questions/comment.component.html index 814b6df838..5a7d16d908 100644 --- a/packages/survey-angular-ui/src/questions/comment.component.html +++ b/packages/survey-angular-ui/src/questions/comment.component.html @@ -1,27 +1,8 @@ - - - + + + + +
{{ model.value }}
\ No newline at end of file diff --git a/src/knockout/templates/comment.html b/src/knockout/templates/comment.html index 6f57cca318..fec8315081 100644 --- a/src/knockout/templates/comment.html +++ b/src/knockout/templates/comment.html @@ -1,6 +1,6 @@  diff --git a/src/vue/question-comment.vue b/src/vue/question-comment.vue index 4c033c47fa..edc5ff2695 100644 --- a/src/vue/question-comment.vue +++ b/src/vue/question-comment.vue @@ -1,20 +1,8 @@ diff --git a/packages/survey-vue3-ui/src/index.ts b/packages/survey-vue3-ui/src/index.ts index c05a25293a..5363b18435 100644 --- a/packages/survey-vue3-ui/src/index.ts +++ b/packages/survey-vue3-ui/src/index.ts @@ -103,6 +103,7 @@ import SurveyNavigationButton from "./components/survey-actions/SurveyNavigation import PopupSurvey from "./PopupSurvey.vue"; import CustomWidget from "./CustomWidget.vue"; import PopupModal from "./components/popup/PopupModal.vue"; +import TextAreaComponent from "./components/TextArea.vue"; import CharacterCounterComponent from "./components/CharacterCounter.vue"; import Composite from "./Composite.vue"; import Custom from "./Custom.vue"; @@ -258,8 +259,9 @@ function registerComponents(app: App) { app.component("survey-customwidget", CustomWidget); app.component("survey-popup-modal", PopupModal); - app.component("sv-character-counter", CharacterCounterComponent); - + app.component("sv-character-counter", TextAreaComponent); + app.component("sv-text-area", CharacterCounterComponent); + app.component("survey-composite", Composite); app.component("survey-custom", Custom); app.component("sv-timerpanel", TimerPanel); From e7370631980e0393109d59bcc4b711cb6ab8a595 Mon Sep 17 00:00:00 2001 From: OlgaLarina Date: Fri, 2 Aug 2024 12:36:54 +0300 Subject: [PATCH 14/27] work for textarea component enhancement: add vue3 component --- packages/survey-vue3-ui/src/Comment.vue | 80 ++----------------- .../survey-vue3-ui/src/QuestionComment.vue | 29 +------ packages/survey-vue3-ui/src/QuestionOther.vue | 26 +----- .../src/components/TextArea.vue | 58 ++++++++++++++ packages/survey-vue3-ui/src/index.ts | 6 +- src/vue/comment.vue | 3 +- 6 files changed, 74 insertions(+), 128 deletions(-) create mode 100644 packages/survey-vue3-ui/src/components/TextArea.vue diff --git a/packages/survey-vue3-ui/src/Comment.vue b/packages/survey-vue3-ui/src/Comment.vue index a06744287e..3b2baf7fd2 100644 --- a/packages/survey-vue3-ui/src/Comment.vue +++ b/packages/survey-vue3-ui/src/Comment.vue @@ -1,73 +1,16 @@ @@ -76,14 +19,7 @@ import type { QuestionCommentModel } from "survey-core"; import { useQuestion } from "./base"; import { ref } from "vue"; defineOptions({ inheritAttrs: false }); -const props = defineProps<{ - question: QuestionCommentModel; - css?: object; -}>(); +const props = defineProps<{ question: QuestionCommentModel }>(); const root = ref(null); useQuestion(props, root); -const change = (event: any) => { - const question = props.question; - question.value = event.target.value; -}; diff --git a/packages/survey-vue3-ui/src/QuestionComment.vue b/packages/survey-vue3-ui/src/QuestionComment.vue index a5b5366419..96db8ba2ce 100644 --- a/packages/survey-vue3-ui/src/QuestionComment.vue +++ b/packages/survey-vue3-ui/src/QuestionComment.vue @@ -1,31 +1,6 @@ + + diff --git a/packages/survey-vue3-ui/src/index.ts b/packages/survey-vue3-ui/src/index.ts index c05a25293a..5363b18435 100644 --- a/packages/survey-vue3-ui/src/index.ts +++ b/packages/survey-vue3-ui/src/index.ts @@ -103,6 +103,7 @@ import SurveyNavigationButton from "./components/survey-actions/SurveyNavigation import PopupSurvey from "./PopupSurvey.vue"; import CustomWidget from "./CustomWidget.vue"; import PopupModal from "./components/popup/PopupModal.vue"; +import TextAreaComponent from "./components/TextArea.vue"; import CharacterCounterComponent from "./components/CharacterCounter.vue"; import Composite from "./Composite.vue"; import Custom from "./Custom.vue"; @@ -258,8 +259,9 @@ function registerComponents(app: App) { app.component("survey-customwidget", CustomWidget); app.component("survey-popup-modal", PopupModal); - app.component("sv-character-counter", CharacterCounterComponent); - + app.component("sv-character-counter", TextAreaComponent); + app.component("sv-text-area", CharacterCounterComponent); + app.component("survey-composite", Composite); app.component("survey-custom", Custom); app.component("sv-timerpanel", TimerPanel); diff --git a/src/vue/comment.vue b/src/vue/comment.vue index b2bd0fdc73..f41754d302 100644 --- a/src/vue/comment.vue +++ b/src/vue/comment.vue @@ -4,8 +4,7 @@ - + > Date: Fri, 2 Aug 2024 14:50:45 +0300 Subject: [PATCH 15/27] work for textarea component enhancement: update textAreaModel options --- src/question.ts | 20 ++++++++++++-------- src/question_baseselect.ts | 20 ++++++++++++-------- src/question_comment.ts | 27 ++++++++++++++++++--------- 3 files changed, 42 insertions(+), 25 deletions(-) diff --git a/src/question.ts b/src/question.ts index 586f8ce3ee..ae640a55c3 100644 --- a/src/question.ts +++ b/src/question.ts @@ -91,7 +91,6 @@ export class Question extends SurveyElement private isReadyValue: boolean = true; private commentElements: Array; private dependedQuestions: Array = []; - private _commentTextAreaModel: TextAreaModel; /** * An event that is raised when the question's ready state has changed (expressions are evaluated, choices are loaded from a web resource specified by the `choicesByUrl` property, etc.). @@ -124,6 +123,7 @@ export class Question extends SurveyElement @property({ defaultValue: false }) isMobile: boolean; @property() forceIsInputReadOnly: boolean; @property() ariaExpanded: "true" | "false"; + @property() commentTextAreaModel: TextAreaModel; constructor(name: string) { super(name); @@ -178,6 +178,10 @@ export class Question extends SurveyElement }); this.registerPropertyChangedHandlers(["isMobile"], () => { this.onMobileChanged(); }); this.registerPropertyChangedHandlers(["colSpan"], () => { this.parent?.updateColumns(); }); + this.registerPropertyChangedHandlers(["id", "renderedCommentPlaceholder"], () => { + this.updateCommentTextAreaModel(); + }); + this.updateCommentTextAreaModel(); } protected getDefaultTitle(): string { return this.name; } protected createLocTitleProperty(): LocalizableString { @@ -2476,11 +2480,11 @@ export class Question extends SurveyElement ); } - public get commentTextAreaModel(): TextAreaModel { - if (!this._commentTextAreaModel) { - this._commentTextAreaModel = new TextAreaModel(this.getCommentTextAreaOptions()); + public updateCommentTextAreaModel(): void { + if (this.commentTextAreaModel) { + this.commentTextAreaModel.dispose(); } - return this._commentTextAreaModel; + this.commentTextAreaModel = new TextAreaModel(this.getCommentTextAreaOptions()); } public getCommentTextAreaOptions(): ITextArea { const options: ITextArea = { @@ -2666,9 +2670,9 @@ export class Question extends SurveyElement super.dispose(); this.resetDependedQuestions(); this.destroyResizeObserver(); - if (this._commentTextAreaModel) { - this._commentTextAreaModel.dispose(); - this._commentTextAreaModel = undefined; + if (this.commentTextAreaModel) { + this.commentTextAreaModel.dispose(); + this.commentTextAreaModel = undefined; } } private resetDependedQuestions(): void { diff --git a/src/question_baseselect.ts b/src/question_baseselect.ts index 97ba51d384..c984cdee10 100644 --- a/src/question_baseselect.ts +++ b/src/question_baseselect.ts @@ -36,7 +36,6 @@ export class QuestionSelectBase extends Question { private newItemValue: ItemValue; private canShowOptionItemCallback: (item: ItemValue) => boolean; private waitingGetChoiceDisplayValueResponse: boolean; - private _otherTextAreaModel: TextAreaModel; private get waitingChoicesByURL(): boolean { return !this.isChoicesLoaded && this.hasChoicesUrl; } @@ -45,6 +44,7 @@ export class QuestionSelectBase extends Question { target.onSelectedItemValuesChangedHandler(newVal); } }) protected selectedItemValues: any; + @property() otherTextAreaModel: TextAreaModel; constructor(name: string) { super(name); @@ -67,6 +67,10 @@ export class QuestionSelectBase extends Question { this.registerPropertyChangedHandlers(["hideIfChoicesEmpty"], () => { this.onVisibleChanged(); }); + this.registerPropertyChangedHandlers(["id", "otherPlaceholder"], () => { + this.updateOtherTextAreaModel(); + }); + this.updateOtherTextAreaModel(); this.createNewArray("visibleChoices"); this.setNewRestfulProperty(); var locOtherText = this.createLocalizableString("otherText", this.otherItemValue, true, "otherItemText"); @@ -101,9 +105,9 @@ export class QuestionSelectBase extends Question { if (!!q) { q.removeDependedQuestion(this); } - if (this._otherTextAreaModel) { - this._otherTextAreaModel.dispose(); - this._otherTextAreaModel = undefined; + if (this.otherTextAreaModel) { + this.otherTextAreaModel.dispose(); + this.otherTextAreaModel = undefined; } } protected resetDependedQuestion(): void { @@ -1970,11 +1974,11 @@ export class QuestionSelectBase extends Question { return classes; } - public get otherTextAreaModel(): TextAreaModel { - if (!this._otherTextAreaModel) { - this._otherTextAreaModel = new TextAreaModel(this.getOtherTextAreaOptions()); + public updateOtherTextAreaModel(): void { + if (this.otherTextAreaModel) { + this.otherTextAreaModel.dispose(); } - return this._otherTextAreaModel; + this.otherTextAreaModel = new TextAreaModel(this.getOtherTextAreaOptions()); } public getOtherTextAreaOptions(): ITextArea { const options: ITextArea = { diff --git a/src/question_comment.ts b/src/question_comment.ts index e3d1b33228..6f7e0d5476 100644 --- a/src/question_comment.ts +++ b/src/question_comment.ts @@ -1,4 +1,4 @@ -import { Serializer } from "./jsonobject"; +import { property, Serializer } from "./jsonobject"; import { QuestionFactory } from "./questionfactory"; import { QuestionTextBase } from "./question_textbase"; import { increaseHeightByContent } from "./utils/utils"; @@ -13,7 +13,16 @@ import { Helpers } from "./helpers"; */ export class QuestionCommentModel extends QuestionTextBase { private element: HTMLElement; - private _textAreaModel: TextAreaModel; + + constructor(name: string) { + super(name); + + this.registerPropertyChangedHandlers(["id", "rows", "cols", "renderedPlaceholder", "autoGrow"], () => { + this.updateTextAreaModel(); + }); + this.updateTextAreaModel(); + } + @property() textAreaModel: TextAreaModel; /** * Specifies the visible height of the comment area, measured in lines. * @@ -129,11 +138,11 @@ export class QuestionCommentModel extends QuestionTextBase { return (this.cssClasses ? this.getControlClass() : "panel-comment-root") || undefined; } - public get textAreaModel(): TextAreaModel { - if (!this._textAreaModel) { - this._textAreaModel = new TextAreaModel(this.getTextAreaOptions()); + public updateTextAreaModel(): void { + if (this.textAreaModel) { + this.textAreaModel.dispose(); } - return this._textAreaModel; + this.textAreaModel = new TextAreaModel(this.getTextAreaOptions()); } public getTextAreaOptions(): ITextArea { @@ -171,9 +180,9 @@ export class QuestionCommentModel extends QuestionTextBase { } public dispose(): void { super.dispose(); - if (this._textAreaModel) { - this._textAreaModel.dispose(); - this._textAreaModel = undefined; + if (this.textAreaModel) { + this.textAreaModel.dispose(); + this.textAreaModel = undefined; } } } From 8c0df37191a3449ceed29bfbc72b911334ae70a2 Mon Sep 17 00:00:00 2001 From: OlgaLarina Date: Fri, 2 Aug 2024 15:29:32 +0300 Subject: [PATCH 16/27] work for textarea component enhancement --- src/question.ts | 2 +- src/question_baseselect.ts | 7 +++++-- src/question_comment.ts | 5 ++++- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/question.ts b/src/question.ts index b888e87b89..e9bbc3b7ce 100644 --- a/src/question.ts +++ b/src/question.ts @@ -181,7 +181,6 @@ export class Question extends SurveyElement this.registerPropertyChangedHandlers(["id", "renderedCommentPlaceholder"], () => { this.updateCommentTextAreaModel(); }); - this.updateCommentTextAreaModel(); } protected getDefaultTitle(): string { return this.name; } protected createLocTitleProperty(): LocalizableString { @@ -1478,6 +1477,7 @@ export class Question extends SurveyElement this.onIndentChanged(); this.updateQuestionCss(); this.updateIsAnswered(); + this.updateCommentTextAreaModel(); } protected initDataFromSurvey(): void { if (!!this.data) { diff --git a/src/question_baseselect.ts b/src/question_baseselect.ts index e88c98a952..54d687bdbe 100644 --- a/src/question_baseselect.ts +++ b/src/question_baseselect.ts @@ -70,7 +70,6 @@ export class QuestionSelectBase extends Question { this.registerPropertyChangedHandlers(["id", "otherPlaceholder"], () => { this.updateOtherTextAreaModel(); }); - this.updateOtherTextAreaModel(); this.createNewArray("visibleChoices"); this.setNewRestfulProperty(); var locOtherText = this.createLocalizableString("otherText", this.otherItemValue, true, "otherItemText"); @@ -1977,6 +1976,10 @@ export class QuestionSelectBase extends Question { return classes; } + protected onSetData(): void { + super.onSetData(); + this.updateOtherTextAreaModel(); + } public updateOtherTextAreaModel(): void { if (this.otherTextAreaModel) { this.otherTextAreaModel.dispose(); @@ -1993,7 +1996,7 @@ export class QuestionSelectBase extends Question { placeholder: this.otherPlaceholder, rows: this.commentAreaRows, maxLength: this.getOthersMaxLength(), - autoGrow: this.survey.autoGrowComment, + autoGrow: this.survey && this.survey.autoGrowComment, ariaRequired: this.ariaRequired || this.a11y_input_ariaRequired, ariaLabel: this.ariaLabel || this.a11y_input_ariaLabel, getTextValue: () => { return this.otherValue; }, diff --git a/src/question_comment.ts b/src/question_comment.ts index 6f7e0d5476..2161554fee 100644 --- a/src/question_comment.ts +++ b/src/question_comment.ts @@ -20,7 +20,6 @@ export class QuestionCommentModel extends QuestionTextBase { this.registerPropertyChangedHandlers(["id", "rows", "cols", "renderedPlaceholder", "autoGrow"], () => { this.updateTextAreaModel(); }); - this.updateTextAreaModel(); } @property() textAreaModel: TextAreaModel; /** @@ -118,6 +117,10 @@ export class QuestionCommentModel extends QuestionTextBase { event.stopPropagation(); } } + protected onSetData(): void { + super.onSetData(); + this.updateTextAreaModel(); + } protected setQuestionValue(newValue: any, updateIsAnswered: boolean = true): void { super.setQuestionValue(newValue, updateIsAnswered); this.updateElement(); From 4e0e8c1fbc574bd0ae0fedf5aa3d86b8a99bd4ea Mon Sep 17 00:00:00 2001 From: OlgaLarina Date: Mon, 19 Aug 2024 10:09:53 +0300 Subject: [PATCH 17/27] work for textarea component enhancement --- src/utils/text-area.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/text-area.ts b/src/utils/text-area.ts index f503534a8f..086129f737 100644 --- a/src/utils/text-area.ts +++ b/src/utils/text-area.ts @@ -78,7 +78,7 @@ export class TextAreaModel { return this.options.id; } get placeholder(): string { - return this.options.placeholder; + return this.options.placeholder || ""; } get className(): string { return this.options.className; From 5769f19ded0f660eea1da8a1773c47cd9a150493 Mon Sep 17 00:00:00 2001 From: OlgaLarina Date: Mon, 19 Aug 2024 11:20:45 +0300 Subject: [PATCH 18/27] work for textarea component enhancement --- .../text-area/text-area.component.html | 3 +- .../survey-core/src}/utils/text-area.ts | 10 ++++ .../src/components/text-area.tsx | 55 +++++++++++++++++++ .../src/components/TextArea.vue | 7 ++- .../components/text-area/text-area.html | 3 +- src/vue/components/text-area.vue | 7 ++- 6 files changed, 81 insertions(+), 4 deletions(-) rename {src => packages/survey-core/src}/utils/text-area.ts (90%) create mode 100644 packages/survey-react-ui/src/components/text-area.tsx diff --git a/packages/survey-angular-ui/src/components/text-area/text-area.component.html b/packages/survey-angular-ui/src/components/text-area/text-area.component.html index faefe29d63..e39dfaba0a 100644 --- a/packages/survey-angular-ui/src/components/text-area/text-area.component.html +++ b/packages/survey-angular-ui/src/components/text-area/text-area.component.html @@ -10,7 +10,8 @@ [value]="value" (input)="model.onTextAreaInput($event)" (keydown)="model.onTextAreaKeyDown($event)" -(blur)="model.onTextAreaChange($event)" +(focus)="model.onTextAreaFocus($event)" +(blur)="model.onTextAreaBlur($event)" (change)="model.onTextAreaChange($event)" [attr.aria-required]="model.ariaRequired" [attr.aria-label]="model.ariaLabel" diff --git a/src/utils/text-area.ts b/packages/survey-core/src/utils/text-area.ts similarity index 90% rename from src/utils/text-area.ts rename to packages/survey-core/src/utils/text-area.ts index 086129f737..b35c8f93b9 100644 --- a/src/utils/text-area.ts +++ b/packages/survey-core/src/utils/text-area.ts @@ -18,6 +18,8 @@ export interface ITextArea { onTextAreaChange?: (event: any) => void; onTextAreaInput?: (event: any) => void; onTextAreaKeyDown?: (event: any) => void; + onTextAreaBlur?: (event: any) => void; + onTextAreaFocus?: (event: any) => void; ariaRequired: "true" | "false"; ariaLabel: string; @@ -71,6 +73,14 @@ export class TextAreaModel { if (!!this.options.onTextAreaKeyDown) this.options.onTextAreaKeyDown(event); } + public onTextAreaBlur(event: any): void { + if (!!this.options.onTextAreaBlur) + this.options.onTextAreaBlur(event); + } + public onTextAreaFocus(event: any): void { + if (!!this.options.onTextAreaFocus) + this.options.onTextAreaFocus(event); + } get question(): Question { return this.options.question as Question; } diff --git a/packages/survey-react-ui/src/components/text-area.tsx b/packages/survey-react-ui/src/components/text-area.tsx new file mode 100644 index 0000000000..063efc3a54 --- /dev/null +++ b/packages/survey-react-ui/src/components/text-area.tsx @@ -0,0 +1,55 @@ +import React from "react"; +import { TextAreaModel } from "survey-core"; +import { ReactElementFactory } from "../element-factory"; +import { SurveyElementBase } from "../reactquestion_element"; + +interface ITextAreaProps { + viewModel: TextAreaModel; +} + +export class TextAreaComponent extends SurveyElementBase { + private initialValue; + + constructor(props: ITextAreaProps) { + super(props); + this.initialValue = this.viewModel.getTextValue() || ""; + } + get viewModel(): TextAreaModel { + return this.props.viewModel; + } + protected canRender(): boolean { + return !!this.viewModel.question; + } + + protected renderElement(): JSX.Element { + return ( +