Abubakar Oluyinka
Abubakar Oluyinka

Reputation: 351

Change position of element to top or botton with clicks

I am practising react and I have this task to build an interface where a button can add elements, another button can remove element and two oter butttons can move each element up or down stepwise like this:

enter image description here

I have been able to make buttons add and remove element but changing positions of elements has been giving me some headache. Below is my code:

const [inputList, setInputList] = useState([{ inputBox: '' }]);
  const handleInputChange = (e, index) => {
    const { name, value } = e.target;
    const list = [...inputList];
    list[index][name] = value;
    setInputList(list);
  };

  const handleRemoveClick = (index) => {
    const list = [...inputList];
    list.splice(index, 1);
    setInputList(list);
  };

  const handleAddClick = () => {
    setInputList([...inputList, { inputBox: '' }]);
  };

  const upPosition = () => {
    console.log('up');
  };

  const downPosition = () => {
    console.log('down');
  };

  return (
    <div>
      <h3>Add Elements</h3>
      <button onClick={handleAddClick}>+</button>
      {inputList.map((x, i) => {
        return (
          <div className='box inputBox' key={i}>
            <input
              name='inputBox'
              value={x.inputBox}
              onChange={(e) => handleInputChange(e, i)}
            />
            <button onClick={() => upPosition()}>
              <i className='fas fa-long-arrow-alt-up'></i>
            </button>
            <button onClick={() => downPosition()}>
              <i className='fas fa-long-arrow-alt-down'></i>
            </button>
            <button className='mr10' onClick={() => handleRemoveClick(i)}>
              <i className='fas fa-times'></i>
            </button>
          </div>
        );
      })}
    </div>
  );

Upvotes: 0

Views: 600

Answers (3)

derrmru
derrmru

Reputation: 61

I think you can achieve with destructuring:

const [inputList, setInputList] = useState([{ inputBox: '' }]);
  const handleInputChange = (e, index) => {
    const { name, value } = e.target;
    const list = [...inputList];
    list[index][name] = value;
    setInputList(list);
  };

  const handleRemoveClick = (index) => {
    const list = [...inputList];
    list.splice(index, 1);
    setInputList(list);
  };

  const handleAddClick = () => {
    setInputList([...inputList, { inputBox: '' }]);
  };

  const upPosition = (i) => {
    if (i > 0) {
      const temp = [...inputList];
      [temp[i], temp[i - 1]] = [temp[i - 1], temp[i]];
      setInputList(temp);
    }
  };

  const downPosition = (i) => {
    if (i < inputList.length - 1) {
      const temp = [...inputList];
      [temp[i], temp[i + 1]] = [temp[i + 1], temp[i]];
      setInputList(temp);
    }
  };

  return (
    <div>
      <h3>Add Elements</h3>
      <button onClick={handleAddClick}>+</button>
      {inputList.map((x, i) => {
        return (
          <div className="box inputBox" key={i}>
            <input
              name="inputBox"
              value={x.inputBox}
              onChange={(e) => handleInputChange(e, i)}
            />
            <button onClick={(e) => upPosition(i)}>
              <i className="fas fa-long-arrow-alt-up"></i>
            </button>
            <button onClick={() => downPosition(i)}>
              <i className="fas fa-long-arrow-alt-down"></i>
            </button>
            <button className="mr10" onClick={() => handleRemoveClick(i)}>
              <i className="fas fa-times"></i>
            </button>
          </div>
        );
      })}
    </div>
  );

Upvotes: 0

DecPK
DecPK

Reputation: 25408

You can make use of splice here

Beside the shifting, you have to handle the 2 cases also, where you can't go up if the index is 0 and you can't go down if the index is inputList.length - 1

NOTE: To handle the both cases, I've disabled the buttons because that would be more meaningful to let the end user know that this button is disable so you can't go up or down.

Live Demo

Codesandbox Demo

const upPosition = ( index ) => {
    const copy = { ...inputList[index] };
    setInputList( ( oldState ) => {
        const newState = oldState.filter( ( o, i ) => i !== index );
        newState.splice( index - 1, 0, copy );
        return newState;
    } )
};

const downPosition = (index) => {
    const copy = { ...inputList[index] };
    setInputList( ( oldState ) => {
        const newState = oldState.filter( ( o, i ) => i !== index );
        newState.splice( index + 1, 0, copy );
        return newState;
    } )
};

Upvotes: 1

Gabriele Petrioli
Gabriele Petrioli

Reputation: 195992

You should use the splice method which can do insertions as well

  const upPosition = (indexToMove) => {
    if (indexToMove === 0) return;
    const list = [...inputList];
    const itemToMove = list.splice(indexToMove, 1)[0];
    list.splice(indexToMove-1, 0, itemToMove)
    setInputList(list)
  };

  const downPosition = (indexToMove) => {
    if (indexToMove === inputList.length - 1) return;
    const list = [...inputList];
    const itemToMove = list.splice(indexToMove, 1)[0];
    list.splice(indexToMove+1, 0, itemToMove)
    setInputList(list)
  };

Upvotes: 0

Related Questions