2

I have the requirement for create the input field which takes the numbers array(comma ','separated ) like [123,34,23,13].

I want when user copy this 123,34,23,13 into input field it should change in this below format based on comma.

enter image description here

Is there anyway to achieve this.

Later on I want to show the red flag also for incorrect number(which will be verify on submission of value).

Ankit saxena
  • 81
  • 1
  • 10

2 Answers2

2

Does this jsFiddle demo meet your requirements? (Click "Run" to start the demo.) If not, please let me know what is missing.

Notes

  1. The demo accepts only comma-separated integers (or a single integer) as input. No spaces are permitted.

  2. Duplicate values are displayed with a red chip and not included in the result set. So far duplicate values are the only validation criterion causing values to fail where the failure is shown to the user via red chips.

  3. Non numerical input fails silently.

index.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>

index.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 />
);

kofeigen
  • 1,331
  • 4
  • 8
  • 1
    I'd appreciate a codesandbox since it's not possible to play around if the jsfiddle consists of minified js – sm3sher Jul 27 '22 at 06:31
  • @sm3sher Sorry, I'm not a CodeSandbox user. In response to the question, all the necessary code is in my post. *index.jsx* just needs to be compiled into a bundle named *index.js* and placed into the same directory as *index.html*. The *import* statements tell you what libraries need to be installed: *react*, *react-dom*, *@mui/material*, and *uuid*. If you are unable to run the demo on your own server (e.g. localhost), or in CodeSandbox feel free to indicate what kind of changes you were thinking about, and I can tell you if I can update the demo accordingly. – kofeigen Jul 28 '22 at 05:53
  • Actually I am looking for example same but more on the individual component type where I can provide the input and onchange listener from another form component. – Ankit saxena Jul 28 '22 at 13:57
  • In your example I found one missing is: when you copy paste the value which is comma separate then it not taking all values: like 2,34,43,43 – Ankit saxena Jul 28 '22 at 14:17
0

This is I found till now : https://codesandbox.io/s/quirky-waterfall-5ebi3y?file=/src/Chips.jsx

There is missing part when the API return the wrong/Invalid array of input then it should convert into red flag

Ankit saxena
  • 81
  • 1
  • 10