Skip to content

Commit

Permalink
Fix rows rebuilding on drop (#7833)
Browse files Browse the repository at this point in the history
* Implement updating only the necessary rows when inserting an element or changing swnl

* Small refactor

* Refactor renderRows in React

* Fix row keys in Vue3
  • Loading branch information
dk981234 committed Feb 9, 2024
1 parent cdfc601 commit 9eec028
Show file tree
Hide file tree
Showing 6 changed files with 851 additions and 27 deletions.
2 changes: 1 addition & 1 deletion packages/survey-vue3-ui/src/Page.vue
Expand Up @@ -5,7 +5,7 @@
<survey-string :locString="page.locDescription" />
</div>
<survey-errors :element="page" />
<template v-for="(row, index) in page.rows" :key="page.id + '_' + index">
<template v-for="row in page.rows" :key="row.id">
<component
:is="(page.getSurvey() as SurveyModel).getRowWrapperComponentName(row)"
v-bind="{
Expand Down
5 changes: 1 addition & 4 deletions packages/survey-vue3-ui/src/Panel.vue
Expand Up @@ -19,10 +19,7 @@
v-if="!element.isCollapsed"
:class="element.cssClasses.panel.content"
>
<template
v-for="(row, index) in element.rows"
:key="element.id + '_' + index"
>
<template v-for="row in element.rows" :key="row.id">
<component
:is="(element.getSurvey() as SurveyModel).getRowWrapperComponentName(row)"
v-bind="{
Expand Down
2 changes: 1 addition & 1 deletion packages/survey-vue3-ui/src/Row.vue
Expand Up @@ -18,7 +18,7 @@ import type {
SurveyElement,
SurveyModel,
} from "survey-core";
import { computed, onBeforeUnmount, onMounted, onUnmounted, ref } from "vue";
import { computed, onMounted, ref } from "vue";
import { useBase } from "./base";
const props = defineProps<{
Expand Down
115 changes: 109 additions & 6 deletions src/panel.ts
Expand Up @@ -1051,13 +1051,80 @@ export class PanelModelBase extends SurveyElement<Question>
if (this.isLoadingFromJson) return;
this.setArrayPropertyDirectly("rows", this.buildRows());
}
protected onAddElement(element: IElement, index: number) {

private locCountRowUpdates = 0;
private blockRowsUpdates() {
this.locCountRowUpdates++;
}
private releaseRowsUpdates() {
this.locCountRowUpdates--;
}
private updateRowsBeforeElementRemoved(element: IElement): void {
const elementRow = this.findRowByElement(element);
const elementRowIndex = this.rows.indexOf(elementRow);
const elementIndexInRow = elementRow.elements.indexOf(element);
elementRow.elements.splice(elementIndexInRow, 1);
if(elementRow.elements.length == 0) {
this.rows.splice(elementRowIndex, 1);
} else if(!elementRow.elements[0].startWithNewLine && this.rows[elementRowIndex - 1]) {
elementRow.elements.forEach(el => this.rows[elementRowIndex - 1].addElement(el));
this.rows.splice(elementRowIndex, 1);
}
else {
elementRow.updateVisible();
}
}
private updateRowsOnElementAdded(element: IElement): void {
const index = this.elements.indexOf(element);
const targetElement = this.elements[index + 1];
const createRowAtIndex = (index: number) => {
const row = this.createRowAndSetLazy(index);
if(this.isDesignModeV2) {
row.setIsLazyRendering(false);
}
this.rows.splice(index, 0, row);
return row;
};
const updateRow = (row: QuestionRowModel, start: number, deleteCount: number, ...elements: IElement[]) => {
const removedElements = row.elements.splice(start, deleteCount, ...elements);
row.updateVisible();
return removedElements;
};
if(!targetElement) {
if(index == 0 || element.startWithNewLine) {
updateRow(createRowAtIndex(this.rows.length), 0, 0, element);
} else {
this.rows[this.rows.length - 1].addElement(element);
}
return;
}
const targetRow = this.findRowByElement(targetElement);
if(!targetRow) return;
const targetRowIndex = this.rows.indexOf(targetRow);
const targetElementIndexInRow = targetRow.elements.indexOf(targetElement);
if(targetElementIndexInRow == 0) {
if(!targetElement.startWithNewLine) {
updateRow(targetRow, 0, 0, element);
}
else if(element.startWithNewLine || targetRowIndex < 1) {
createRowAtIndex(targetRowIndex).addElement(element);
} else {
this.rows[targetRowIndex - 1].addElement(element);
}
} else {
if(element.startWithNewLine) {
updateRow(createRowAtIndex(targetRowIndex + 1), 0, 0, ...[element].concat(updateRow(targetRow, targetElementIndexInRow, targetRow.elements.length)));
} else {
updateRow(targetRow, targetElementIndexInRow, 0, element);
}
}
}
protected onAddElement(element: IElement, index: number): void {
element.setSurveyImpl(this.surveyImpl);
element.parent = this;
this.markQuestionListDirty();
if (this.canBuildRows()) {
let dragDropInfo = settings.supportCreatorV2 ? this.getDragDropInfo() : undefined;
this.dragDropPanelHelper.updateRowsOnElementAdded(element, index, dragDropInfo, this);
this.updateRowsOnElementAdded(element);
}
if (element.isPanel) {
var p = <PanelModel>element;
Expand Down Expand Up @@ -1106,7 +1173,9 @@ export class PanelModelBase extends SurveyElement<Question>
}
}
private onElementStartWithNewLineChanged(element: any) {
this.onRowsChanged();
if(this.locCountRowUpdates > 0) return;
this.updateRowsBeforeElementRemoved(element);
this.updateRowsOnElementAdded(element);
}
private updateRowsVisibility(element: any) {
var rows = this.rows;
Expand Down Expand Up @@ -1169,7 +1238,9 @@ export class PanelModelBase extends SurveyElement<Question>
if (elIndex < 0) return;
row.elements.splice(elIndex, 1);
if (row.elements.length > 0) {
this.blockRowsUpdates();
row.elements[0].startWithNewLine = true;
this.releaseRowsUpdates();
row.updateVisible();
} else {
if (row.index >= 0) {
Expand Down Expand Up @@ -1364,7 +1435,39 @@ export class PanelModelBase extends SurveyElement<Question>
}
return true;
}

public insertElement(element: IElement, dest?: IElement, location: "bottom" | "top" | "left" | "right" = "bottom"): void {
if(!dest) {
this.addElement(element);
return;
}
this.blockRowsUpdates();
let index = this.elements.indexOf(dest);
const destRow = this.findRowByElement(dest);
if(location == "left" || location == "right") {
if(location == "right") {
element.startWithNewLine = false;
index++;
}
else {
if(destRow.elements.indexOf(dest) == 0) {
dest.startWithNewLine = false;
element.startWithNewLine = true;
} else {
element.startWithNewLine = false;
}
}
}
else {
element.startWithNewLine = true;
if(location == "top") {
index = this.elements.indexOf(destRow.elements[0]);
} else {
index = this.elements.indexOf(destRow.elements[destRow.elements.length - 1]) + 1;
}
}
this.releaseRowsUpdates();
this.addElement(element, index);
}
public insertElementAfter(element: IElement, after: IElement) {
const index = this.elements.indexOf(after);
if (index >= 0) this.addElement(element, index + 1);
Expand Down Expand Up @@ -1410,7 +1513,7 @@ export class PanelModelBase extends SurveyElement<Question>
*
* This method returns `null` if the panel cannot be created or added to this panel/page; otherwise, the method returns the created panel.
* @param name A panel name.
* @see elements
* @see elementsup
* @see addElement
*/
public addNewPanel(name: string = null): PanelModel {
Expand Down
16 changes: 1 addition & 15 deletions src/react/panel-base.tsx
Expand Up @@ -77,22 +77,8 @@ export class SurveyPanelBase extends SurveyElementBase<any, any> {
&& this.panelBase.isVisible && !!this.panelBase.survey
);
}
private renderedRowsCache: any = {};
protected renderRows(css: any): Array<JSX.Element> {
if (this.changedStatePropName !== "rows") {
this.renderedRowsCache = {};
}
var rows:Array<JSX.Element> = [];
var questionRows = this.panelBase.rows;
for (var i = 0; i < questionRows.length; i++) {
var row = this.renderedRowsCache[questionRows[i].id];
if (!row) {
row = this.createRow(questionRows[i], css);
this.renderedRowsCache[questionRows[i].id] = row;
}
rows.push(row);
}
return rows;
return this.panelBase.rows.map((row) => this.createRow(row, css));
}
protected createRow(row: QuestionRowModel, css: any): JSX.Element {
return (
Expand Down

0 comments on commit 9eec028

Please sign in to comment.