Skip to content

Commit

Permalink
Improve performance for extremely large JSON #8961 (#8962)
Browse files Browse the repository at this point in the history
* setJson with isLoading parameter #8961

* Use setJson with isLoading true in more case #8961

* Do not build matrices rows on hiding the question #8961

* Do not run ItemValue.onPropertyValueChanged on creating #8961

* Calculate allowLineBreaks in localization string on request #8961

* FIx issues with knockout #8961

* Allow to setup locName for localization string in contructor #8691
  • Loading branch information
andrewtelnov authored Oct 24, 2024
1 parent 28ea911 commit b96a26e
Show file tree
Hide file tree
Showing 9 changed files with 63 additions and 43 deletions.
11 changes: 7 additions & 4 deletions packages/survey-core/src/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ export class Bindings {
}
return res;
}
public setJson(value: any) {
public setJson(value: any, isLoading?: boolean): void {
const oldValue = this.getJson();
this.values = null;
if (!!value) {
Expand All @@ -97,7 +97,9 @@ export class Bindings {
this.values[key] = value[key];
}
}
this.onChangedJSON(oldValue);
if(!isLoading) {
this.onChangedJSON(oldValue);
}
}
private fillProperties() {
if (this.properties !== null) return;
Expand Down Expand Up @@ -833,10 +835,11 @@ export class Base {
useMarkDown: boolean = false,
defaultStr: boolean|string = false
): LocalizableString {
var locStr = new LocalizableString(owner, useMarkDown, name);
let locName = undefined;
if (defaultStr) {
locStr.localizationName = defaultStr === true ? name : defaultStr;
locName = defaultStr === true ? name : defaultStr;
}
const locStr = new LocalizableString(owner, useMarkDown, name, locName);
locStr.onStrChanged = (oldValue: string, newValue: string) => {
this.propertyValueChanged(name, oldValue, newValue);
};
Expand Down
38 changes: 22 additions & 16 deletions packages/survey-core/src/itemvalue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -189,11 +189,7 @@ export class ItemValue extends BaseAction implements ILocalizableOwner, IShortcu
private visibleConditionRunner: ConditionRunner;
private enableConditionRunner: ConditionRunner;

constructor(
value: any,
text: string = null,
protected typeName = "itemvalue"
) {
constructor(value: any, text: string = null, protected typeName = "itemvalue") {
super();
this.locTextValue = new LocalizableString(this, true, "text");
this.locTextValue.onStrChanged = (oldValue: string, newValue: string) => {
Expand All @@ -211,9 +207,9 @@ export class ItemValue extends BaseAction implements ILocalizableOwner, IShortcu
};
if (text) this.locText.text = text;
if (!!value && typeof value === "object") {
this.setData(value);
this.setData(value, true);
} else {
this.value = value;
this.setValue(value, true);
}
if (this.getType() != "itemvalue") {
CustomPropertiesCollection.createProperties(this);
Expand Down Expand Up @@ -241,7 +237,7 @@ export class ItemValue extends BaseAction implements ILocalizableOwner, IShortcu
public get locText(): LocalizableString {
return this.locTextValue;
}
setLocText(locText: LocalizableString) {
setLocText(locText: LocalizableString): void {
this.locTextValue = locText;
}
private _locOwner: ILocalizableOwner;
Expand All @@ -257,7 +253,10 @@ export class ItemValue extends BaseAction implements ILocalizableOwner, IShortcu
return this.getPropertyValue("value");
}
public set value(newValue: any) {
var text: string = undefined;
this.setValue(newValue, false);
}
private setValue(newValue: any, newItem: boolean): void {
let text: string = undefined;
if (!Helpers.isValueEmpty(newValue)) {
var str: string = newValue.toString();
var index = str.indexOf(settings.itemValueSeparator);
Expand All @@ -266,7 +265,12 @@ export class ItemValue extends BaseAction implements ILocalizableOwner, IShortcu
text = str.slice(index + 1);
}
}
this.setPropertyValue("value", newValue);
if(newItem) {
this.setPropertyValueDirectly("value", newValue);
}
else {
this.setPropertyValue("value", newValue);
}
if (!!text) {
this.text = text;
}
Expand All @@ -287,7 +291,7 @@ export class ItemValue extends BaseAction implements ILocalizableOwner, IShortcu
public set text(newText: string) {
this.locText.text = newText;
}
public get calculatedText() {
public get calculatedText(): string {
return this.locText.calculatedText;
}
public get shortcutText(): string {
Expand Down Expand Up @@ -328,7 +332,7 @@ export class ItemValue extends BaseAction implements ILocalizableOwner, IShortcu
}
return res;
}
public setData(value: any): void {
public setData(value: any, isNewItem?: boolean): void {
if (Helpers.isValueEmpty(value)) return;
if(typeof value.value === "undefined" && typeof value.text !== "undefined" && Object.keys(value).length === 1) {
value.value = value.text;
Expand All @@ -342,9 +346,11 @@ export class ItemValue extends BaseAction implements ILocalizableOwner, IShortcu
}
new JsonObject().toObject(json, this);
} else {
this.value = value;
this.setValue(value, isNewItem);
}
if(!isNewItem) {
this.locText.strChanged();
}
this.locText.strChanged();
}
public get visibleIf(): string {
return this.getPropertyValueWithoutDefault("visibleIf") || "";
Expand Down Expand Up @@ -379,15 +385,15 @@ export class ItemValue extends BaseAction implements ILocalizableOwner, IShortcu
super.locStrsChanged();
this.locText.strChanged();
}
protected onPropertyValueChanged(name: string, oldValue: any, newValue: any) {
protected onPropertyValueChanged(name: string, oldValue: any, newValue: any): void {
if (name === "value" && !this.hasText) {
this.locText.strChanged();
}
var funcName = "itemValuePropertyChanged";
if (!this.locOwner || !(<any>this.locOwner)[funcName]) return;
(<any>this.locOwner)[funcName](this, name, oldValue, newValue);
}
protected getConditionRunner(isVisible: boolean) {
protected getConditionRunner(isVisible: boolean): ConditionRunner {
if (isVisible) return this.getVisibleConditionRunner();
return this.getEnableConditionRunner();
}
Expand Down
4 changes: 2 additions & 2 deletions packages/survey-core/src/jsonobject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -451,7 +451,7 @@ export class JsonObjectProperty implements IObject, IJsonPropertyInfo {
this.onSetValue(obj, value, jsonConv);
} else {
if (this.serializationProperty && !!obj[this.serializationProperty])
obj[this.serializationProperty].setJson(value);
obj[this.serializationProperty].setJson(value, true);
else {
if (value && typeof value === "string") {
if (this.type == "number") {
Expand Down Expand Up @@ -1086,7 +1086,7 @@ export class JsonMetadata {
public setObjPropertyValue(obj: any, name: string, val: any) {
if (obj[name] === val) return;
if (!!obj[name] && !!obj[name].setJson) {
obj[name].setJson(val);
obj[name].setJson(val, true);
} else {
if (Array.isArray(val)) {
const newVal = [];
Expand Down
42 changes: 26 additions & 16 deletions packages/survey-core/src/localizablestring.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,14 @@ export class LocalizableString implements ILocalizableString {
this.strChanged();
}
}
private _allowLineBreaks: boolean = false;
private _allowLineBreaks: boolean;
public get allowLineBreaks(): boolean {
if(this._allowLineBreaks === undefined) {
this._allowLineBreaks = false;
if (!!this.name && this.owner instanceof SurveyElementCore) {
this._allowLineBreaks = Serializer.findProperty((this.owner as SurveyElementCore).getType(), this.name)?.type == "text";
}
}
return this._allowLineBreaks;
}
public onGetTextCallback: (str: string) => string;
Expand All @@ -62,14 +68,9 @@ export class LocalizableString implements ILocalizableString {
public searchIndex: number;
public disableLocalization: boolean;
public defaultValue: string;
constructor(
public owner: ILocalizableOwner,
public useMarkdown: boolean = false,
public name?: string
) {
if (owner instanceof SurveyElementCore) {
this._allowLineBreaks = Serializer.findProperty((owner as SurveyElementCore).getType(), name)?.type == "text";
}
constructor(public owner: ILocalizableOwner, public useMarkdown: boolean = false,
public name?: string, locName?: string) {
this._localizationName = locName;
this.onCreating();
}
public getIsMultiple(): boolean { return false; }
Expand Down Expand Up @@ -284,22 +285,31 @@ export class LocalizableString implements ILocalizableString {
}
return res;
}
public setJson(value: any): void {
public setJson(value: any, isLoading?: boolean): void {
if (!!this.sharedData) {
this.sharedData.setJson(value);
this.sharedData.setJson(value, isLoading);
return;
}
this.values = {};
this.htmlValues = {};
if (value === null || value === undefined) return;
if (typeof value === "string") {
this.setLocaleText(null, value);
if(isLoading) {
if (typeof value === "string") {
this.values[settings.defaultLocaleName] = value;
} else {
this.values = value;
delete this.values["pos"];
}
} else {
for (var key in value) {
this.setLocaleText(key, value[key]);
if (typeof value === "string") {
this.setLocaleText(null, value);
} else {
for (var key in value) {
this.setLocaleText(key, value[key]);
}
}
this.strChanged();
}
this.strChanged();
}
public get renderAs(): string {
if (!this.owner || typeof this.owner.getRenderer !== "function") {
Expand Down
2 changes: 1 addition & 1 deletion packages/survey-core/src/question_matrix.ts
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ export class MatrixCells extends Base {
}
return res;
}
public setJson(value: any): void {
public setJson(value: any, isLoading?: boolean): void {
this.values = {};
if (!!value) {
for (var row in value) {
Expand Down
1 change: 1 addition & 0 deletions packages/survey-core/src/question_matrixdropdownbase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1958,6 +1958,7 @@ export class QuestionMatrixDropdownModelBase extends QuestionMatrixBaseModel<Mat
}
public onHidingContent(): void {
super.onHidingContent();
if(!this.generatedVisibleRows) return;
const questions: Question[] = [];
this.collectNestedQuestions(questions, true);
questions.forEach(q => q.onHidingContent());
Expand Down
1 change: 0 additions & 1 deletion packages/survey-core/src/question_paneldynamic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1787,7 +1787,6 @@ export class QuestionPanelDynamicModel extends Question
const loc = this.getLocalizableString("noEntriesText");
if (!loc) return;
loc.localizationName = (this.isReadOnly || !this.allowAddPanel) ? "noEntriesReadonlyText" : "noEntriesText";
loc.strChanged();
}
public onSurveyLoad(): void {
this.template.readOnly = this.isReadOnly;
Expand Down
1 change: 1 addition & 0 deletions src/knockout/kosurvey.ts
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ LocalizableString.prototype["onCreating"] = function () {
ItemValue.prototype["onCreating"] = function () {
new ImplementorBase(this);
this.koText = ko.pureComputed(() => { return this.locText.koRenderedHtml(); });
this.locText.strChanged();
};

ko.components.register("survey", {
Expand Down
6 changes: 3 additions & 3 deletions tests/ko/survey_kotests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1785,7 +1785,7 @@ QUnit.test(
}
);

QUnit.test("survey.firstPageIsStarted=true + multiple-language", function (
QUnit.test("survey.firstPageIsStarted=true + multiple-language, #1", function (
assert
) {
var json = {
Expand Down Expand Up @@ -1815,18 +1815,18 @@ QUnit.test("survey.firstPageIsStarted=true + multiple-language", function (
var q1 = survey.getQuestionByName("q1");
var q2 = survey.getQuestionByName("q2");
assert.equal(q1.locTitle["koRenderedHtml"](), "q1-en", "en locale, q1");
assert.equal(q2.locTitle["koRenderedHtml"](), "q2-en", "en locale, q2");
var prevLocale = survey.locale;
survey.locale = "de";
assert.equal(q1.locTitle["koRenderedHtml"](), "q1-de", "de locale, q1");
survey.locale = prevLocale;
survey.start();
assert.equal(q2.locTitle["koRenderedHtml"](), "q2-en", "en locale, q2");
survey.locale = "de";
assert.equal(q2.locTitle["koRenderedHtml"](), "q2-de", "de locale, q2");
survey.locale = prevLocale;
});

QUnit.test("survey.firstPageIsStarted=true + multiple-language", function (
QUnit.test("survey.firstPageIsStarted=true + multiple-language, #2", function (
assert
) {
var survey = new Survey({
Expand Down

0 comments on commit b96a26e

Please sign in to comment.