Обновление и повторное отображение значения в реагирующем компоненте TextField - PullRequest
0 голосов
/ 17 февраля 2020

Я создаю плагин для Excel, используя Javascipt API и React.

В настоящее время у меня есть компонент, который по существу создал список текстовых полей, которые отображают данные из самой электронной таблицы. Кроме того, я хотел бы, чтобы они были редактируемыми, а затем могли записывать данные обратно в саму электронную таблицу.

Почти все это уже так или иначе работает, но мне трудно заставить TextFields вести себя так, как я хочу.

По сути, мне нужен список текстовых полей для отображения данных из строки таблицы. Если я выберу другую строку таблицы, я хочу, чтобы значения текстовых полей обновлялись соответствующим образом.

Проблема, с которой я сталкиваюсь, заключается в том, как обеспечить, чтобы текстовые поля обновлялись каждый раз, когда я щелкаю новую строку, и как также убедиться, что они доступны для редактирования.

Если я использую параметр value с состоянием, то когда я нажимаю на новый элемент в таблице, старое состояние компонента не изменяется при вызове рендеринга и фактически не обновляется ,

Если я использую defaultValue, он также просто обновляется при первом вызове, а затем никогда.

Функция рендеринга, которая вызывается каждый раз, когда я выбираю новую строку в таблице:

  public render() {

    const { resource } = this.props;

    // Create concept list
    const myItems = []
    _.forEach(resource, (val) => {
      myItems.push(<ListItem resource={val} />)
    })

    return (
      <Stack tokens={{ childrenGap: 3 }}>
        {myItems}
      </Stack>
    );
  }
}

ListItem.tsx


import * as React from 'react';
import ReactHtmlParser from 'react-html-parser';
import { TextField, ITextFieldProps, Stack, IconButton, Callout, IStackTokens, } from 'office-ui-fabric-react';
import { getId, IRenderFunction } from 'office-ui-fabric-react/lib/Utilities';
import XbrlTaxonomyElementValue from '../../xbrl/XbrlTaxonomyElementValue';
import { writeValueToCell } from '../Tables';
import getLogger, { REMOTE_LOGGING } from '../../utils/logger';

export interface ListItemState {
  isCalloutVisible: boolean;
  multiline: boolean;
  textFieldValue: string;
}

var con = getLogger(REMOTE_LOGGING);

export interface ListItemProps {
  resource: XbrlTaxonomyElementValue;
}

const stackTokens: IStackTokens = {
  childrenGap: 10,
  maxWidth: 300
};

export default class ListItem extends React.Component<ListItemProps, ListItemState> {

  myInput: any;
  maxCharWidth: number;

  public state: ListItemState = {
    isCalloutVisible: false,
    multiline: false,
    textFieldValue: this.props.resource.value
  };

  constructor(props: Readonly<ListItemProps>) {
    super(props);
    this.myInput = React.createRef()
    this.maxCharWidth = 35;
  }

  componentDidMount() { }

  private _labelId: string = getId('label');
  private _descriptionId: string = getId('description');
  private _iconButtonId: string = getId('iconButton');

  public render() {
    // Controlled Component
    const { resource } = this.props;

    // if (this.state.textFieldValue != resource.value) {
    //   this.setState({ textFieldValue: resource.value });
    // }

    return (
      <TextField
        componentRef={this.myInput}
        required={resource.required}
        aria-labelledby={this._labelId}
        label={resource.title}
        defaultValue={resource.value}
        deferredValidationTime={400}
        onGetErrorMessage={resource.validator}
        description={resource.hint}
        onRenderDescription={this._onRenderDescripton}
        onRenderLabel={this._onRenderLabel}
        multiline={this.state.multiline}
        onChange={this._onChange}
        onBlur={this._onBlur}
      />
    );
  }

  private _onBlur = (_ev: any) => {
    const { resource } = this.props;
    writeValueToCell(resource.address.toString(), this.myInput.current.value);
  }

  private _onChange = (_ev: any, newText: string): void => {
    this.setState({ textFieldValue: _ev.target.value })
    const newMultiline = newText.length > this.maxCharWidth;
    if (newMultiline !== this.state.multiline) {
      this.setState({ multiline: newMultiline });
    }
  };

  private _onRenderLabel = (props: ITextFieldProps, defaultRender: IRenderFunction<ITextFieldProps>): JSX.Element => {
    /*
      We are using the TextField description as the callout text. If we don't provide any text, then 
      don't render the button, just render a default label. 
    */
    if (!props.description)
      return (defaultRender(props))

    return (
      <>
        <Stack horizontal verticalAlign="center">
          <span id={this._labelId}>{defaultRender(props)}</span>
          <IconButton
            id={this._iconButtonId}
            iconProps={{ iconName: 'Info' }}
            title="Info"
            ariaLabel="Info"
            onClick={this._onIconClick}
            styles={{ root: { marginBottom: -3 } }}
            tabIndex={-1} // Skip button when hitting the tab key
          />
        </Stack>
        {this.state.isCalloutVisible && (
          <Callout
            target={'#' + this._iconButtonId}
            setInitialFocus={true}
            onDismiss={this._onDismiss}
            ariaDescribedBy={this._descriptionId}
            role="alertdialog"
          >
            <Stack tokens={stackTokens} horizontalAlign="start" styles={{ root: { padding: 8 } }}>
              <span id={this._descriptionId}>{ReactHtmlParser(props.description)}</span>
              {/* <DefaultButton onClick={this._onDismiss}>Close</DefaultButton> */}
            </Stack>
          </Callout>
        )}
      </>
    );
  };


  private _onRenderDescripton = (): JSX.Element => {
    return <div></div> // Return nothing
  }

  private _onIconClick = (): void => {
    this.setState({ isCalloutVisible: !this.state.isCalloutVisible });
  };

  private _onDismiss = (): void => {
    this.setState({ isCalloutVisible: false });
  };
}

Я знаю, что это не так Это новая проблема, однако я пока не смог решить ее обычными методами и надеялся, что кто-то может указать мне правильное направление.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...