Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 58 additions & 1 deletion e2e/questions/text.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
import { Page } from "playwright/test";
import { frameworks, url, initSurvey, getSurveyData, test, expect } from "../helper";

const title = "text";

async function fullQuestionRerender(page: Page, name: string): Promise<void> {
await page.evaluate(([name]) => {
const q = window["survey"].getQuestionByName(name);
q.readOnly = true;
q.readOnly = false;
}, [name]);
}
const json = {
"pages": [
{
Expand Down Expand Up @@ -73,5 +80,55 @@ frameworks.forEach((framework) => {
expect(surveyResult.question2).toEqual("#000000");
expect(surveyResult.question3).toEqual(undefined);
});
test("Do not lost the value is being entered on re-rendering the question, Bug#10584", async ({ page }) => {
const locJSON = {
"elements": [
{ "type": "text", "name": "q1" },
{ "type": "text", "name": "q2", "maskType": "pattern", "maskSettings": { "pattern": "99-99" } },
{ "type": "text", "name": "q3", "inputType": "time" },
{ "type": "comment", "name": "q4" }]
};
await initSurvey(page, framework, locJSON);

const q1 = page.locator("input").first();
await q1.focus();
await q1.fill("Test");
await fullQuestionRerender(page, "q1");
await page.keyboard.type("A");
await page.keyboard.press("Tab");
/*
const q2 = page.locator("input").nth(1);
await q2.focus();
await page.keyboard.type("1");
await page.keyboard.type("2");
await fullQuestionRerender(page, "q2");
await page.keyboard.press("ArrowRight"); await page.keyboard.press("ArrowRight"); await page.keyboard.press("ArrowRight");
await page.keyboard.type("3");
await page.keyboard.type("4");
await page.keyboard.press("Tab");
*/
const q3 = page.locator("input").nth(2);
await q3.focus();
await page.keyboard.type("1");
await page.keyboard.type("0");
await fullQuestionRerender(page, "q3");
await page.keyboard.type("2");
await page.keyboard.type("5");
await page.keyboard.type("P");
await page.keyboard.press("Tab");

const q4 = page.locator("textarea").nth(0);
await q4.focus();
await q4.fill("Test");
await fullQuestionRerender(page, "q4");
await page.keyboard.type("B");
await page.keyboard.press("Tab");

const surveyResult = await getSurveyData(page);
expect(surveyResult.q1).toBe("TestA");
// expect(surveyResult.q2).toBe("1234");
expect(surveyResult.q3).toBe("22:25");
expect(surveyResult.q4).toBe("TestB");
});
});
});
2 changes: 1 addition & 1 deletion packages/survey-angular-ui/src/questions/text.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export class TextQuestionComponent extends QuestionAngular<QuestionTextModel> {
@ViewChild("inputElement") inputElementRef!: ElementRef<HTMLDivElement>;

get value(): string {
return this.model.inputValue ?? "";
return this.model.renderedValue ?? "";
}

blur(event: any): void {
Expand Down
10 changes: 6 additions & 4 deletions packages/survey-core/src/question.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1560,16 +1560,19 @@ export class Question extends SurveyElement<Question>
return false;
}
public get isContainer(): boolean { return false; }
protected getValueFromEvent(event: any): any {
return event?.target?.value;
}
public onCommentInput(event: any): void {
if (this.isInputTextUpdate) {
if (event.target) {
this.comment = event.target.value;
this.comment = this.getValueFromEvent(event);
}
}
}
public onCommentChange(event: any): void {
this.comment = event.target.value;
if (this.comment !== event.target.value) {
this.comment = this.getValueFromEvent(event);
if (this.comment !== this.getValueFromEvent(event)) {
event.target.value = this.comment;
}
}
Expand Down Expand Up @@ -3012,7 +3015,6 @@ export class Question extends SurveyElement<Question>
return !!this.survey ? this.survey.isUpdateValueTextOnTyping : false;
}
get requireStrictCompare(): boolean { return false; }
getExpressionValue(val: any): any { return val; }
private getDataLocNotification(): any {
return this.isInputTextUpdate ? "text" : false;
}
Expand Down
2 changes: 1 addition & 1 deletion packages/survey-core/src/question_baseselect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1874,7 +1874,7 @@ export class QuestionSelectBase extends Question implements IChoiceOwner {
}
private onOtherValueInput(item: ItemValue, event: any): void {
if (this.isInputTextUpdate && event.target) {
this.setCommentValueCore(item, event.target.value);
this.setCommentValueCore(item, this.getValueFromEvent(event));
}
}
private onOtherValueChange(item: ItemValue, event: any): void {
Expand Down
7 changes: 4 additions & 3 deletions packages/survey-core/src/question_comment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ export class QuestionCommentModel extends QuestionTextBase {
ariaInvalid: () => this.a11y_input_ariaInvalid,
ariaErrormessage: () => this.a11y_input_ariaErrormessage,
getTextValue: () => { return this.value; },
onTextAreaChange: (e) => { updateQuestionValue(e.target.value); },
onTextAreaChange: (e) => { updateQuestionValue(this.getValueFromEvent(e)); },
onTextAreaInput: (event) => { this.onInput(event); },
onTextAreaKeyDown: (event) => { this.onKeyDown(event); },
onTextAreaFocus: (event) => { this.onFocus(event); },
Expand Down Expand Up @@ -143,9 +143,10 @@ export class QuestionCommentModel extends QuestionTextBase {
this.element = undefined;
}
public onInput(event: any): void {
const val = this.getValueFromEvent(event);
if (this.isInputTextUpdate)
this.value = event.target.value;
this.updateRemainingCharacterCounter(event.target.value);
this.value = val;
this.updateRemainingCharacterCounter(val);
}
protected onBlurCore(event: any): void {
super.onBlurCore(event);
Expand Down
59 changes: 35 additions & 24 deletions packages/survey-core/src/question_text.ts
Original file line number Diff line number Diff line change
Expand Up @@ -367,33 +367,44 @@ export class QuestionTextModel extends QuestionTextBase {
return isMinMaxType(this);
}

@property() _inputValue: string;
public get maskInstance(): IInputMask {
return this.maskSettings;
}
private setInputValue(val: string) {
this.setPropertyValue("inputValue", val);
this.setRenderedValue(val);
}
public get renderedValue(): string {
return this.maskTypeIsEmpty ? this.getPropertyValue("renderedValue") : this.inputValue;
}
public set renderedValue(val: string) {
this.inputValue = val;
}
protected setRenderedValue(val: string) {
this.setPropertyValue("renderedValue", val);
}
public get inputValue(): string {
if (!this._inputValue && !this.maskTypeIsEmpty) return this.maskInstance.getMaskedValue("");
return this._inputValue;
const res = this.getPropertyValue("inputValue");
if (!res && !this.maskTypeIsEmpty) return this.maskInstance.getMaskedValue("");
return res;
}
public set inputValue(val: string) {
let value = val;
this._inputValue = val;
let inputVal = val;
if (!this.maskTypeIsEmpty) {
value = this.maskInstance.getUnmaskedValue(val);
this._inputValue = this.maskInstance.getMaskedValue(value);
inputVal = this.maskInstance.getMaskedValue(value);
if (!!value && this.maskSettings.saveMaskedValue) {
value = this._inputValue;
value = inputVal;
}
}
this.setInputValue(inputVal);
if (!Helpers.isTwoValueEquals(this.value, value, false, true)) {
this.value = value;
}
}
public getFilteredValue(): any {
return this.getExpressionValue(this.value);
}
//TODO remove this method in the future
getExpressionValue(val: any): any {
const val = this.value;
if (!this.maskTypeIsEmpty && this.maskSettings.saveMaskedValue)
return this.maskInstance.getUnmaskedValue(val);
return val;
Expand All @@ -411,14 +422,13 @@ export class QuestionTextModel extends QuestionTextBase {
}

private updateInputValue() {
const _value = this.value;
if (this.maskTypeIsEmpty) {
this._inputValue = _value;
} else if (this.maskSettings.saveMaskedValue) {
this._inputValue = (_value !== undefined && _value !== null) ? _value : this.maskInstance.getMaskedValue("");
} else {
this._inputValue = this.maskInstance.getMaskedValue(_value);
}
this.setInputValue(this.getInputValueFromValue());
}
private getInputValueFromValue(): string {
const res = this.value;
if (this.maskTypeIsEmpty) return res;
if (this.maskSettings.saveMaskedValue) return (res !== undefined && res !== null) ? res : this.maskInstance.getMaskedValue("");
return this.maskInstance.getMaskedValue(res);
}
private hasToConvertToUTC(val: any): boolean {
return settings.storeUtcDates && this.isDateTimeLocaleType() && !!val;
Expand Down Expand Up @@ -678,7 +688,7 @@ export class QuestionTextModel extends QuestionTextBase {
private _isWaitingForEnter = false;

private updateValueOnEvent(event: any) {
const newValue = event.target.value;
const newValue = this.getValueFromEvent(event);
if (!this.isTwoValueEquals(this.value, newValue)) {
this.inputValue = newValue;
}
Expand All @@ -689,7 +699,7 @@ export class QuestionTextModel extends QuestionTextBase {
this.updateValueOnEvent(event);
}, 1);
}
this.updateRemainingCharacterCounter(event.target.value);
this.updateRemainingCharacterCounter(this.getValueFromEvent(event));
};
public onKeyUp = (event: any) => {
this.updateDateValidationMessage(event);
Expand All @@ -703,7 +713,7 @@ export class QuestionTextModel extends QuestionTextBase {
this.updateValueOnEvent(event);
}
}
this.updateRemainingCharacterCounter(event.target.value);
this.updateRemainingCharacterCounter(this.getValueFromEvent(event));
};
private updateDateValidationMessage(event: any): void {
this.dateValidationMessage = this.isDateInputType && !!event.target ? event.target.validationMessage : undefined;
Expand All @@ -725,6 +735,7 @@ export class QuestionTextModel extends QuestionTextBase {
this.onTextKeyDownHandler(event);
};
public onChange = (event: any): void => {
this.setRenderedValue(this.getValueFromEvent(event));
this.updateDateValidationMessage(event);
const elementIsFocused = event.target === settings.environment.root.activeElement;
if (elementIsFocused) {
Expand All @@ -734,16 +745,16 @@ export class QuestionTextModel extends QuestionTextBase {
} else {
this.updateValueOnEvent(event);
}
this.updateRemainingCharacterCounter(event.target.value);
this.updateRemainingCharacterCounter(this.getValueFromEvent(event));
};
protected onBlurCore(event: any): void {
this.updateDateValidationMessage(event);
this.updateValueOnEvent(event);
this.updateRemainingCharacterCounter(event.target.value);
this.updateRemainingCharacterCounter(this.getValueFromEvent(event));
super.onBlurCore(event);
}
protected onFocusCore(event: any): void {
this.updateRemainingCharacterCounter(event.target.value);
this.updateRemainingCharacterCounter(this.getValueFromEvent(event));
super.onFocusCore(event);
}
public afterRenderQuestionElement(el: HTMLElement) {
Expand Down
17 changes: 17 additions & 0 deletions packages/survey-core/tests/question_texttests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -774,4 +774,21 @@ QUnit.test("Could not change the value from upper case into lower case, #10590",
assert.equal(q.value, "TEST", "value is set to upper case");
q.inputValue = "test";
assert.equal(q.value, "test", "value is changed to lower case");
});
QUnit.test("text question, renderedValue property, Bug#10584", (assert) => {
const survey = new SurveyModel({
elements: [
{ type: "text", name: "q1", defaultValue: "AB" }
]
});
const q = <QuestionTextModel>survey.getQuestionByName("q1");
assert.equal(q.renderedValue, "AB", "renderedValue is correct");
q.value = "CD";
assert.equal(q.renderedValue, "CD", "renderedValue is correct, #2");
q.inputValue = "EF";
assert.equal(q.renderedValue, "EF", "renderedValue is correct, #3");
q.onChange({ target: { value: "GH" } });
assert.equal(q.renderedValue, "GH", "renderedValue is correct, #4");
q.renderedValue = "IJ";
assert.equal(q.inputValue, "IJ", "inputValue is correct, #5");
});
2 changes: 1 addition & 1 deletion packages/survey-react-ui/src/reactquestion_text.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ export class SurveyQuestionText extends SurveyQuestionUncontrolledElement<
this.question.inputValue = newValue;
}
protected getValueCore(): any {
return this.question.inputValue;
return this.question.renderedValue;
}
private renderDataList(): React.JSX.Element | null {
if (!this.question.dataListId) return null;
Expand Down
4 changes: 2 additions & 2 deletions packages/survey-vue3-ui/src/TextInput.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
:list="question.dataListId"
:placeholder="question.renderedPlaceholder"
:autocomplete="question.autocomplete"
:value="question.inputValue"
:value="question.renderedValue"
@change="question.onChange"
@click="question.readOnlyBlocker"
@pointerdown="question.readOnlyBlocker"
Expand Down Expand Up @@ -48,7 +48,7 @@
:list="question.dataListId"
:placeholder="question.renderedPlaceholder"
:autocomplete="question.autocomplete"
:value="question.inputValue"
:value="question.renderedValue"
@change="question.onChange"
@click="question.readOnlyBlocker"
@pointerdown="question.readOnlyBlocker"
Expand Down