Как обновить FabricL-UI DetailsList при обновлении строки - PullRequest
0 голосов
/ 04 января 2019

Я пытаюсь создать компонент detailsList для пользовательского интерфейса.Этот компонент должен просто представлять то, что у меня есть в моей базе данных, с возможностью обновления определенного значения столбца для каждой строки.Чтобы выполнить обновление, каждая строка должна иметь Fabric-Ui PrimaryButton.Я также создал два API на моем сервере (GET и POST).Запрос GET вернет приложению реагирования все ресурсы, которые будут показаны, а POST (вызванный нажатием кнопки PrimaryButton определенной строки) будет иметь в параметре Id строки и обновит значение столбца.

Я создал корневой компонент: приложение, которое загружает DetailsList и вызывает GET API, чтобы получить все ресурсы и показать их.Я также создал дочерний компонент: ResolveButton, который будет вызываться для каждой строки в списке сведений в корневом компоненте.

App.tsx:

import * as React from 'react';
import ResolveButton from './ResolveButton';


export interface IDetailsListCustomColumnsExampleState {
  sortedItems?: any[];
  columns?: IColumn[];
  hasError: boolean;
}


export class App extends React.Component<{}, IDetailsListCustomColumnsExampleState> {
  public constructor(props: {}) {
    super(props);

    this.state = {
      columns: [],
      hasError:false,
      sortedItems: []
    };
    this._renderItemColumn=this._renderItemColumn.bind(this);
    this.changeStatus = this.changeStatus.bind(this);
  }
  public componentDidCatch() {
    // Display fallback UI
    this.setState({ hasError: true });
  }
  public componentDidMount(){
    this.fetchResult()
  }
  public render() {
    const { sortedItems, columns } = this.state;
    if (this.state.hasError) {
      // You can render any custom fallback UI
      return <h1>Something went wrong.</h1>;
    }
    else{
      return (
        <DetailsList
          items={sortedItems as any[]}
          setKey="set"
          columns={columns}
          onRenderItemColumn={this._renderItemColumn}
          onColumnHeaderClick={this.onColumnClick}
          onItemInvoked={this._onItemInvoked}
          onColumnHeaderContextMenu={this._onColumnHeaderContextMenu}
          ariaLabelForSelectionColumn="Toggle selection"
          ariaLabelForSelectAllCheckbox="Toggle selection for all items"
        />
      );
    }

  }
  public changeStatus (itemId:React.ReactText){
    // TODO : call the POST API to update the status
    const { sortedItems } = this.state;
    const resolvedKey='Status';
    const idKey='Id';

    sortedItems!.map(ite => {
      if(ite[idKey] === itemId){
          ite[resolvedKey] = 3;
      }
      return ite;
    })
    this.setState({
      sortedItems
    });
  }
  private fetchResult = () =>{
    fetch('https://localhost:44329/home')
    .then((response) => response.json())
    .then(json => this.setState({ columns: _buildColumns(json),
    sortedItems: json })).catch((error) => 
    { 
      this.componentDidCatch()
    })
  }

  private onColumnClick = (event: React.MouseEvent<HTMLElement>, column: IColumn): void => {
    const { columns } = this.state;
    let { sortedItems } = this.state;
    let isSortedDescending = column.isSortedDescending;

    // If we've sorted this column, flip it.
    if (column.isSorted) {
      isSortedDescending = !isSortedDescending;
    }

    // Sort the items.
    sortedItems = sortedItems!.concat([]).sort((a, b) => {
      const firstValue = a[column.fieldName || ''];
      const secondValue = b[column.fieldName || ''];

      if (isSortedDescending) {
        return firstValue > secondValue ? -1 : 1;
      } else {
        return firstValue > secondValue ? 1 : -1;
      }
    });

    // Reset the items and columns to match the state.
    this.setState({
      columns: columns!.map(col => {
        col.isSorted = col.key === column.key;

        if (col.isSorted) {
          col.isSortedDescending = isSortedDescending;
        }

        return col;
      }),
      sortedItems      
    });
  };

  private _onColumnHeaderContextMenu(column: IColumn | undefined, ev: React.MouseEvent<HTMLElement> | undefined): void {

    alert(`column ${column!.key} contextmenu opened.`);
  }

  private _onItemInvoked(item: any, index: number | undefined): void {
    alert(`Item ${item.name} at index ${index} has been invoked.`);
  }

private _renderItemColumn(item: any, index: number, column: IColumn) {

  const fieldContent = item[column.fieldName || ''];

  const crisisColor = {
    1: 'Red',
    2: 'Orange',
    3: 'Yellow',
    4: 'Green'
  }
  const crisis = {
    1: 'Crise',
    2: 'Haute',
    3: 'Moyenne',
    4: 'Basse'
  }
  const statusColor = {
    1: 'Black',
    2: 'Black',
    3: 'Green'
  } 
  const status = {
    1: 'Ouvert',
    2: 'En cours',
    3: 'Résolu'
  }
  const resolvedKey='Status';
  const isResolved = item[resolvedKey]===3;
  switch (column.key) {
    case 'Status':
      return (
        <span data-selection-disabled={true} style={{ color: statusColor[fieldContent], height: '100%', display: 'block' }}>
          {status[fieldContent]}
        </span>
      );

    case 'Criticity':
      return (
        <span data-selection-disabled={true} style={{ color: crisisColor[fieldContent], height: '100%', display: 'block' }}>
          {crisis[fieldContent]}
        </span>
      );
    case 'Creator':
      return(
        <div>
        <img src="https://img.mobiscroll.com/demos/BMW_logo.png" width="30px" height="30px" style={{verticalAlign: 'middle', display:'inline' }}/>
        <p style={{verticalAlign: 'middle', display:'inline' , paddingLeft:'10px'}}>{fieldContent}</p>
        </div>
      ); 
    case 'AssignedTo':
      return(
        <div>
        <img src="https://img.mobiscroll.com/demos/BMW_logo.png" width="30px" height="30px" style={{verticalAlign: 'middle', display:'inline' }}/>
        <p style={{verticalAlign: 'middle', display:'inline' , paddingLeft:'10px'}}>{fieldContent}</p>
        </div>
      );

    case 'Id':
      return(
        // tslint:disable-next-line jsx-no-lambda
        <ResolveButton disabled={isResolved} uniqueId={fieldContent} changeStatus={ ()=>this.changeStatus(fieldContent)} /> 
      );

    default:
      return <span>{fieldContent}</span>;
  }
}
}
function _buildColumns(json:any[]) {
  const columns = buildColumns(json);
  return columns;
}

export default App;

ResolveButton.tsx

import { PrimaryButton } from 'office-ui-fabric-react/lib/Button';
import * as React from 'react';

export interface IHandleChange {
    changeStatus: ()=>void;
    disabled:boolean;
    uniqueId:string| number;
}
export class ResolveButton extends React.Component<IHandleChange, {}> {
    constructor(props:any) {

        super(props);
    }
    public render(): JSX.Element {
        return (
            <div>
                {
                    !this.props.disabled && 
                    <PrimaryButton
                        data-automation-id="test"
                        text="Résolu"
                        onClick={this.props.changeStatus}
                        allowDisabledFocus={true}
                    />
                }
            </div>
        );
    }
}
export default ResolveButton;

Как вы можете видеть в моем App.tsx, я создаю компонент ResolveButton, когда ключом столбца является "Id".Моя проблема заключается в том, что при нажатии на кнопку данные будут обновляться в базе данных, но в приложении реакции всегда отображается старая версия базы данных, поэтому мне нужно обновить страницу при вызове API POST.

1 Ответ

0 голосов
/ 05 января 2019

Это вопрос типа реакции.

Ваш DetailList использует sortedItems для управления своим состоянием.Поэтому, когда вы нажимаете ResolveButton, вам нужно обновить состояние.Что не происходит

Чтобы исправить это, ResolveButton должен предоставить свойство с именем onResolved, чтобы основной компонент мог обрабатывать его состояние.

class ResolveButton extends React.Component<IButtonProps, {}> {
  async handleClick() {
     const response = await fetch('https://localhost:44329/home')
     const json = await response.json();

     if (this.props.onResolved) {
         this.props.onResolved(json);
     }
  }
}

.

В App просто позвоните onResolved, чтобы обновить состояние

class App extends React.Component<{}, IDetailsListCustomColumnsExampleState> {
  …
   <ResolveButton
        disabled={isResolved}
        uniqueId={fieldContent}
        onResolved={(data) => setState({'sortedItems': data})
   />
  …
}
...