Skip to content

Commit

Permalink
Fix matrix rows animation doesn't work in React (#8364)
Browse files Browse the repository at this point in the history
* Fix matrix animation doesnt work in React

* Disable sync remove and addition animations for visible elements
  • Loading branch information
dk981234 authored Jun 4, 2024
1 parent 1f0d7c7 commit d4083c0
Show file tree
Hide file tree
Showing 6 changed files with 137 additions and 126 deletions.
13 changes: 1 addition & 12 deletions packages/survey-vue3-ui/src/MatrixTable.vue
Original file line number Diff line number Diff line change
Expand Up @@ -68,16 +68,5 @@ const props = defineProps<{ question: QuestionMatrixDropdownModelBase }>();
const table = computed(() => {
return props.question.renderedTable;
});
useBase(
() => table.value,
(newValue) => {
const instance = getCurrentInstance();
newValue.renderedRowsChangedCallback = () => {
instance?.proxy?.$forceUpdate();
};
},
(value) => {
value.renderedRowsChangedCallback = () => {};
}
);
useBase(() => table.value);
</script>
9 changes: 5 additions & 4 deletions src/panel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ export class QuestionRowModel extends Base {
return {
getRerenderEvent: () => this.onElementRerendered,
isAnimationEnabled: () => this.animationAllowed,
allowSyncRemovalAddition: false,
getAnimatedElement: (element: IElement) => (element as any as SurveyElement).getWrapperElement(),
getLeaveOptions: (element: IElement) => {
const surveyElement = element as unknown as SurveyElement;
Expand All @@ -146,8 +147,8 @@ export class QuestionRowModel extends Base {
};
}
public visibleElementsAnimation: AnimationGroup<IElement> = new AnimationGroup(this.getVisibleElementsAnimationOptions(), (value) => {
this.setWidth(value);
this.setPropertyValue("visibleElements", value);
this.setWidth();
}, () => this.visibleElements);
public set visibleElements(val: Array<IElement>) {
if(!val.length) {
Expand Down Expand Up @@ -195,10 +196,10 @@ export class QuestionRowModel extends Base {
public get index(): number {
return this.panel.rows.indexOf(this);
}
private setWidth() {
var visCount = this.visibleElements.length;
private setWidth(visibleElement: Array<IElement>) {
var visCount = visibleElement.length;
if (visCount == 0) return;
const isSingleInRow = this.visibleElements.length === 1;
const isSingleInRow = visibleElement.length === 1;
var counter = 0;
var preSetWidthElements = [];
for (var i = 0; i < this.elements.length; i++) {
Expand Down
3 changes: 0 additions & 3 deletions src/question_matrixdropdownrendered.ts
Original file line number Diff line number Diff line change
Expand Up @@ -220,10 +220,8 @@ export class QuestionMatrixDropdownRenderedTable extends Base {
private hasRemoveRowsValue: boolean;
private rowsActions: Array<Array<IAction>>;
private cssClasses: any;
public renderedRowsChangedCallback = (): void => { };
@propertyArray({
onPush: (_: any, i: number, target: QuestionMatrixDropdownRenderedTable) => {
target.renderedRowsChangedCallback();
target.updateRenderedRows();
},
onRemove: (_: any, i: number, target: QuestionMatrixDropdownRenderedTable) => {
Expand Down Expand Up @@ -262,7 +260,6 @@ export class QuestionMatrixDropdownRenderedTable extends Base {
}
private renderedRowsAnimation = new AnimationGroup(this.getRenderedRowsAnimationOptions(), (val) => {
this._renderedRows = val;
this.renderedRowsChangedCallback();
}, () => this._renderedRows)

public get renderedRows(): Array<QuestionMatrixDropdownRenderedRow> {
Expand Down
3 changes: 2 additions & 1 deletion src/question_ranking.ts
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,8 @@ export class QuestionRankingModel extends QuestionCheckboxModel {
}
const index = isRankingChoices ? this.renderedRankingChoices.indexOf(item) : this.renderedUnRankingChoices.indexOf(item);
return this.domNode?.querySelector(`${containerSelector} [data-sv-drop-target-ranking-item='${index}']`);
}
},
allowSyncRemovalAddition: true
};
}

Expand Down
165 changes: 89 additions & 76 deletions src/react/reactquestion_matrixdropdownbase.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import * as React from "react";
import {
ReactSurveyElement,
SurveyQuestionElementBase
SurveyElementBase,
SurveyQuestionElementBase,
} from "./reactquestion_element";
import { SurveyElementErrors, SurveyQuestion, SurveyQuestionAndErrorsCell, SurveyQuestionErrorCell } from "./reactquestion";
import { ISurveyCreator, SurveyQuestion, SurveyQuestionAndErrorsCell, SurveyQuestionErrorCell } from "./reactquestion";
import {
QuestionMatrixDropdownModelBase,
QuestionMatrixDropdownRenderedRow,
QuestionMatrixDropdownRenderedCell,
MatrixDropdownColumn,
AdaptiveActionContainer,
Question,
Base
Base,
} from "survey-core";
import { SurveyQuestionCheckboxItem } from "./reactquestion_checkbox";
import { SurveyQuestionRadioItem } from "./reactquestion_radiogroup";
Expand All @@ -22,80 +23,38 @@ import { SurveyQuestionMatrixDynamicDragDropIcon } from "./components/matrix-act
import { SurveyQuestionOtherValueItem } from "./reactquestion_comment";
import { ReactElementFactory } from "./element-factory";

export class SurveyQuestionMatrixDropdownBase extends SurveyQuestionElementBase {
constructor(props: any) {
super(props);
//Create rendered table in contructor and not on rendering
const table = this.question.renderedTable;
this.state = this.getState();
}
protected get question(): QuestionMatrixDropdownModelBase {
return this.questionBase as QuestionMatrixDropdownModelBase;
}
private getState(prevState: any = null) {
return { rowCounter: !prevState ? 0 : prevState.rowCounter + 1 };
}
private updateStateOnCallback() {
if (this.isRendering) return;
this.setState(this.getState(this.state));
class SurveyQuestionMatrixTable extends SurveyElementBase<{ question: QuestionMatrixDropdownModelBase, wrapCell: (cell: QuestionMatrixDropdownRenderedCell, element: JSX.Element, reason: string) => JSX.Element, creator: ISurveyCreator}, any> {
protected get question() {
return this.props.question;
}
componentDidMount() {
super.componentDidMount();
this.question.visibleRowsChangedCallback = () => {
this.updateStateOnCallback();
};
this.question.onRenderedTableResetCallback = () => {
this.question.renderedTable.renderedRowsChangedCallback = () => {
this.updateStateOnCallback();
};
this.updateStateOnCallback();
};
this.question.renderedTable.renderedRowsChangedCallback = () => {
this.updateStateOnCallback();
};
protected get creator() {
return this.props.creator;
}
componentWillUnmount() {
super.componentWillUnmount();
this.question.visibleRowsChangedCallback = () => {};
this.question.onRenderedTableResetCallback = () => {};
this.question.renderedTable.renderedRowsChangedCallback = () => {};
protected get table() {
return this.question.renderedTable;
}
protected renderElement(): JSX.Element {
return this.renderTableDiv();
protected getStateElement() {
return this.table;
}
renderTableDiv(): JSX.Element {
var header = this.renderHeader();
var footers = this.renderFooter();
var rows = this.renderRows();
var divStyle = this.question.showHorizontalScroll
? ({ overflowX: "scroll" } as React.CSSProperties)
: ({} as React.CSSProperties);
return (
<div style={divStyle} className={this.question.cssClasses.tableWrapper} ref={(root) => (this.setControl(root))}>
<table className={this.question.getTableCss()}>
{header}
{rows}
{footers}
</table>
</div>
);
protected wrapCell(cell: QuestionMatrixDropdownRenderedCell, element: JSX.Element, reason: string): JSX.Element {
return this.props.wrapCell(cell, element, reason);
}
renderHeader(): JSX.Element | null {
var table = this.question.renderedTable;
const table = this.question.renderedTable;
if (!table.showHeader) return null;
var headers: any[] = [];
var cells = table.headerRow.cells;
const headers: any[] = [];
const cells = table.headerRow.cells;
for (var i = 0; i < cells.length; i++) {
var cell = cells[i];
var key = "column" + i;
var columnStyle: any = {};
const cell = cells[i];
const key = "column" + i;
const columnStyle: any = {};
if (!!cell.width) {
columnStyle.width = cell.width;
}
if (!!cell.minWidth) {
columnStyle.minWidth = cell.minWidth;
}
var cellContent = this.renderCellContent(cell, "column-header", {});
const cellContent = this.renderCellContent(cell, "column-header", {});
const header = cell.hasTitle ?
<th className={cell.className} key={key} style={columnStyle}> {cellContent} </th>
: <td className={cell.className} key={key} style={columnStyle}></td>;
Expand All @@ -108,9 +67,9 @@ export class SurveyQuestionMatrixDropdownBase extends SurveyQuestionElementBase
);
}
renderFooter(): JSX.Element | null {
var table = this.question.renderedTable;
const table = this.question.renderedTable;
if (!table.showFooter) return null;
var row = this.renderRow(
const row = this.renderRow(
"footer",
table.footerRow,
this.question.cssClasses,
Expand All @@ -119,9 +78,9 @@ export class SurveyQuestionMatrixDropdownBase extends SurveyQuestionElementBase
return <tfoot>{row}</tfoot>;
}
renderRows(): JSX.Element {
var cssClasses = this.question.cssClasses;
var rows:Array<JSX.Element> = [];
var renderedRows = this.question.renderedTable.renderedRows;
const cssClasses = this.question.cssClasses;
const rows:Array<JSX.Element> = [];
const renderedRows = this.question.renderedTable.renderedRows;
for (var i = 0; i < renderedRows.length; i++) {
rows.push(
this.renderRow(renderedRows[i].id, renderedRows[i], cssClasses)
Expand All @@ -135,13 +94,13 @@ export class SurveyQuestionMatrixDropdownBase extends SurveyQuestionElementBase
cssClasses: any,
reason?: string
): JSX.Element {
var matrixrow:Array<JSX.Element> = [];
var cells = row.cells;
const matrixrow:Array<JSX.Element> = [];
const cells = row.cells;

for (var i = 0; i < cells.length; i++) {
matrixrow.push(this.renderCell(cells[i], i, cssClasses, reason));
}
var key = "row" + keyValue;
const key = "row" + keyValue;

return (
<React.Fragment key={key}>
Expand All @@ -156,7 +115,7 @@ export class SurveyQuestionMatrixDropdownBase extends SurveyQuestionElementBase
cssClasses: any,
reason?: string
): JSX.Element {
var key = "cell" + index;
const key = "cell" + index;
if (cell.hasQuestion) {
return (
<SurveyQuestionMatrixDropdownCell
Expand All @@ -172,8 +131,8 @@ export class SurveyQuestionMatrixDropdownBase extends SurveyQuestionElementBase
if(!calcReason) {
calcReason = cell.hasTitle ? "row-header" : "";
}
var cellContent = this.renderCellContent(cell, calcReason, cssClasses);
var cellStyle: any = null;
const cellContent = this.renderCellContent(cell, calcReason, cssClasses);
let cellStyle: any = null;
if (!!cell.width || !!cell.minWidth) {
cellStyle = {};
if (!!cell.width) cellStyle.width = cell.width;
Expand All @@ -198,8 +157,8 @@ export class SurveyQuestionMatrixDropdownBase extends SurveyQuestionElementBase
reason: string,
cssClasses: any
): JSX.Element | null {
var cellContent: JSX.Element | null = null;
var cellStyle: any = null;
let cellContent: JSX.Element | null = null;
let cellStyle: any = null;
if (!!cell.width || !!cell.minWidth) {
cellStyle = {};
if (!!cell.width) cellStyle.width = cell.width;
Expand Down Expand Up @@ -255,6 +214,60 @@ export class SurveyQuestionMatrixDropdownBase extends SurveyQuestionElementBase
);
return this.wrapCell(cell, readyCell, reason);
}
protected renderElement(): JSX.Element | null {
const header = this.renderHeader();
const footers = this.renderFooter();
const rows = this.renderRows();
return (
<table className={this.question.getTableCss()}>
{header}
{rows}
{footers}
</table>
);
}
}

export class SurveyQuestionMatrixDropdownBase extends SurveyQuestionElementBase {
constructor(props: any) {
super(props);
//Create rendered table in contructor and not on rendering
const table = this.question.renderedTable;
this.state = this.getState();
}
protected get question(): QuestionMatrixDropdownModelBase {
return this.questionBase as QuestionMatrixDropdownModelBase;
}
private getState(prevState: any = null) {
return { rowCounter: !prevState ? 0 : prevState.rowCounter + 1 };
}
private updateStateOnCallback() {
if (this.isRendering) return;
this.setState(this.getState(this.state));
}
componentDidMount(): void {
super.componentDidMount();
this.question.onRenderedTableResetCallback = () => {
this.updateStateOnCallback();
};
}
componentWillUnmount(): void {
super.componentWillUnmount();
this.question.onRenderedTableResetCallback = () => {};
}
protected renderElement(): JSX.Element {
return this.renderTableDiv();
}
renderTableDiv(): JSX.Element {
var divStyle = this.question.showHorizontalScroll
? ({ overflowX: "scroll" } as React.CSSProperties)
: ({} as React.CSSProperties);
return (
<div style={divStyle} className={this.question.cssClasses.tableWrapper} ref={(root) => (this.setControl(root))}>
<SurveyQuestionMatrixTable question={this.question} creator={this.creator} wrapCell={(cell, element, reason) => this.wrapCell(cell, element, reason)}></SurveyQuestionMatrixTable>
</div>
);
}
}

class SurveyQuestionMatrixActionsCell extends ReactSurveyElement {
Expand Down
Loading

0 comments on commit d4083c0

Please sign in to comment.