【问题标题】:How to customize Material UI Chip component to be editable and copy paste content (comma separated)如何自定义Material UI Chip组件可编辑和复制粘贴内容(逗号分隔)
【发布时间】:2023-02-09 13:14:09
【问题描述】:

我有创建输入字段的要求,它采用数字数组(逗号','分隔),如 [123,34,23,13]。

我希望当用户将此 123,34,23,13 复制到输入字段时,它应该根据逗号更改为以下格式。

无论如何要实现这一点。

稍后我想为不正确的数字显示红旗(这将在提交值时进行验证)。

【问题讨论】:

    标签: reactjs material-ui components chips


    【解决方案1】:

    这个jsFiddle demo符合你的要求吗? (单击“运行”开始演示。)如果没有,请告诉我缺少什么。

    笔记

    1. 该演示仅接受逗号分隔的整数(或单个整数)作为输入。不允许有空格。

    2. 重复值以红色条显示,不包含在结果集中。到目前为止,重复值是导致值失败的唯一验证标准,其中失败通过红筹码显示给用户。

    3. 非数字输入静默失败。

      索引.html

      <!DOCTYPE html>
      <html>
      
          <head>
              <title>Material-UI Chip Input Field Test</title>
              <meta charset="utf-8">
              <meta name="viewport" content="width=device-width, initial-scale=1">
          </head>
      
          <body>
              <div id="testContainer" class="testContainer"></div>
              <script src="./index.js"></script>
              <noscript> Please enable javascript to view the site </noscript>
          </body>
      
      </html>
      

      索引.jsx

      import * as React from 'react';
      import { createRoot } from 'react-dom/client';
      const container = document.getElementById( 'testContainer' );
      const root = createRoot( container );
      
      import Chip from '@mui/material/Chip';
      import Autocomplete from '@mui/material/Autocomplete';
      import TextField from '@mui/material/TextField';
      import Stack from '@mui/material/Stack';
      
      import { v4 as uuidv4 } from 'uuid';
      
      let collator = new Intl.Collator( 'en', { numeric: true, sensitivity: 'base' } );
      
      const getSortedListAsArray = ( list ) => {
          let sortedList = list.sort( ( a, b ) => {
              return collator.compare( a.value, b.value );
          } );
          return sortedList;
      }
      
      export default function Tags() {
          const [ list, setList ] = React.useState( [] );
          const selectedItems = list.filter( ( item ) => item.isValid );
          const selectedLengthIndex = selectedItems.length - 1;
      
          let listById = {};
          for ( let item of list ) {
              listById[ item.id ] = item;
          }
      
          function updateList( items ) {
              let newList = [].concat( list, items );
              newList = getSortedListAsArray( newList );
              setList( newList );
          }
      
          function validateValue( value, validatedItems ) {
              let isValid = false;
              const valueInt = parseInt( value );
              const selectedValues = list.map( ( item ) => item.value );
              const validatedValues = validatedItems.map( ( item ) => item.value );
              if ( selectedValues.indexOf( valueInt ) === -1 &&
                  validatedValues.indexOf( valueInt ) === -1
              ) {
                  isValid = true;
              }
              return isValid;
          }
          
          function validateInput( event, inputs, reason ) {
              if ( 'createOption' == reason ) {
                  let validatedItems = [];
          
                  let values = inputs[ inputs.length - 1 ].split( ',' );
                  for ( let value of values ) {
      
                      // Test for positive integers. Fail silently.
                      if ( /[^0-9]+/.test( value ) || value.length == 0 ) {
                          continue;
                      } else {
                          let isValid = validateValue( value, validatedItems );
                          validatedItems.push( {
                              id: uuidv4(),
                              value: parseInt( value ),
                              isValid
                          } );
                      }
                  }
          
                  updateList( validatedItems );
              } else if ( 'removeOption' == reason ) {
                  let newList = inputs.map( ( id ) => listById[ id ] );
                  setList( newList );
              } else if ( 'clear' == reason ) {
                  setList( [] );
              }
          }
      
          /**
           * Return call adapted from Material-UI 'Multiple values' Autocomplete demo.
           * @see https://mui.com/material-ui/react-table/#sorting-amp-selecting
           * Code: @see https://github.com/mui/material-ui/blob/v5.9.2/docs/data/material/components/autocomplete/Tags.tsx
           *
           */
          return (
              <Stack spacing={ 3 } sx={ { width: 500 } }>
                  <Autocomplete
                      multiple
                      id='tags-filled'
                      filterSelectedOptions={ true }
                      options={ [] }
                      value={ list.map( ( item ) => item.id ) }
                      freeSolo
                      renderTags={ ( listIds, getTagProps ) =>
                          listIds.map( ( id, index ) => (
                              <Chip
                                  key={ index }
                                  variant='outlined'
                                  label={ listById[ id ].value }
                                  sx={ {
                                      color: ( theme ) => {
                                          let chipColor = '#fff';
                                          if ( typeof( listById[ id ] ) == 'object' ) {
                                              chipColor = listById[ id ].isValid
                                                  ? theme.palette.common.white 
                                                  : theme.palette.common.white
                                          }
                                          return chipColor;
                                      },
      
                                      backgroundColor: ( theme ) => {
                                          let chipColor = '#fff';
                                          if ( typeof( listById[ id ] ) == 'object' ) {
                                              chipColor = listById[ id ].isValid
                                                  ? theme.palette.primary.main 
                                                  : theme.palette.error.main
                                          }
                                          return chipColor;
                                      },
                                  
                                      [`& .MuiSvgIcon-root.MuiSvgIcon-fontSizeMedium.MuiChip-deleteIcon.MuiChip-deleteIconMedium.MuiChip-deleteIconColorDefault.MuiChip-deleteIconOutlinedColorDefault`]: {
                                          fill: ( theme ) => theme.palette.grey[200]                
                                      }
                                  } }
                                  { ...getTagProps( { index } ) }
                              />
                          ) )
                      }
                      renderInput={ ( params ) => (
                          <TextField
                              { ...params }
                              variant='filled'
                              label='Material-UI Chip Input Test'
                              placeholder='e.g. 12,73,902,23,41'
                              helperText='Enter comma separated integers (no spaces)'
                          />
                      ) }
                      onChange={ validateInput }
                  />
      
                  { /* Display list of unique integers. */ }
                  <div>
                      { selectedItems.map( ( item, index ) => {
                          let comma = null;
                          if ( selectedLengthIndex != index ) {
                              comma = ( <span key={ 'idx' + index }>, </span> );
                          }
      
                          return (
                              item.isValid
                                  ? <span key={ index }>{ item.value }{ comma }</span>
                                  : null
                          );
                      } ) }
                  </div>
              </Stack>
          );
      }
      
      /**
       * Inject component into DOM
       */
      root.render(
          <Tags />
      );
      
      

    【讨论】:

    • 我会很感激 codesandbox,因为如果 jsfiddle 由缩小的 js 组成,就不可能玩
    • @sm3sher 抱歉,我不是 CodeSandbox 用户。为了回答这个问题,所有必要的代码都在我的帖子中。索引.jsx只需要编译成一个名为索引.js并放置在与以下目录相同的目录中索引.html.这进口语句告诉您需要安装哪些库:反应,反应域,@mui/材质, 和uuid.如果您无法在自己的服务器(例如本地主机)或 CodeSandbox 中运行该演示,请随时指出您正在考虑进行何种更改,我可以告诉您是否可以相应地更新演示。
    • 实际上,我正在寻找相同但更多关于单个组件类型的示例,我可以在其中提供来自另一个表单组件的输入和 onchange 侦听器。
    • 在您的示例中,我发现缺少一个:当您复制粘贴以逗号分隔的值时,它不会采用所有值:例如 2,34,43,43
    【解决方案2】:

    这是我到目前为止发现的:https://codesandbox.io/s/quirky-waterfall-5ebi3y?file=/src/Chips.jsx

    当 API 返回错误/无效的输入数组时缺少部分,那么它应该转换为红旗

    【讨论】:

      猜你喜欢
      • 2019-04-18
      • 2019-01-16
      • 1970-01-01
      • 2019-07-16
      • 1970-01-01
      • 2017-09-28
      • 1970-01-01
      • 2012-09-05
      • 2017-06-13
      相关资源
      最近更新 更多