Ad

Clearing Dynamically Added Input Fields

- 1 answer

I am creating an app, where users should compose a correct sentence from shuffled one. Like on the following picture. The problem is that I am not implementing the app in a right way. For example, I do not change inputs through state. And my main question is how to clear input of a particular line (a bunch of inputs) ? I need it when a user types something wrong and needs to start again. I know that input field should be controlled through state, but it is impossible since all inputs are generated according to number of words. And in one line there maybe more than one input. Let me explain how my code works, so that you have an idea my implementation.

This is where I get data from.

export default {
    id:'1',
    parts:[
    {
        speaker:'Speaker1',
        words:'Hello how are you?'
    },
    {   speaker:'Speaker2',
        words:'I am OK, thanks'
    },
    {   speaker:'Speaker1',
        words:'What are your plans for Saturday?'
    }
    ]
}

import React, { Component } from 'react';
import {CopyToClipboard} from 'react-copy-to-clipboard';
import { MdDoneAll } from "react-icons/md";


// This is the array where data from inputs is pushed to
var pushArr = [];

// Initial points 
var points = 0;

class DialogueShuffleFrame extends Component {
    constructor(props) {
        super(props)

        this.state = {
            // Variable to show correct or incorrect notification
            showCorrect:false
        }

        this.writeSometihng = this.writeSometihng.bind(this)
    }

    // Function that is triggered when a tick is clicked
    // Pushes value to the pushArr array when onBlur function is triggered

    writeSometihng(e) {
        e.preventDefault()
        pushArr.push(e.target.value)
        console.log(pushArr)
    }

    // Function check if array of value from input matches to an array from
    // initial data source
    checkLines(arr, lines) {
        let joinedStr = arr.join(' ');
        //console.log(joinedStr);
        lines[0].parts.map((obj) => {
            let line = obj.words
            if (joinedStr === line) {
                this.setState({
                    showCorrect:true
                })
                pushArr = [];
                points += 80;
            } else {
                pushArr = [];
            }

        })
    }

    // Resets pushArr array
    reset() {
        pushArr.length = 0
        console.log('clicked')
    }
    // Shuffles words 
    formatWords(words) {
        const splittedWords = words.split(' ')
        const shuffledArray = this.shuffle(splittedWords)
        return (
            shuffledArray.map((word, index) => (
                <>
                    <input className="word-to-drop-input" id={index} onBlur={this.writeSometihng} size={2} />
                    <CopyToClipboard text={word}>
                        <span key={uid(word)} value={word} className="word-to-drop">{word}</span>
                    </CopyToClipboard>
                </>
            ))
        )
    }

    shuffle(a) {
        var j, x, i;
        for (i = a.length - 1; i > 0; i--) {
            j = Math.floor(Math.random() * (i + 1));
            x = a[i];
            a[i] = a[j];
            a[j] = x;
        }
        return a;
    }

    render() {
        const {lines} = this.props
        const shuffles = lines[0].parts && (
            lines[0].parts.map((element,i) => (
                <>
                    <li className="line" key={i}><span>{element.speaker}{": "}</span><span>{this.formatWords(element.words)}</span></li>
                    <MdDoneAll type="button" onClick={() => {this.checkLines(pushArr, lines)}} style={{color:'white'}}/>
                </>
            ))
        )

        return (
                <>
                    <h1 className="centered" style={{color:'white'}}>Dialogue shuffle frame</h1>
                    <ul className="lines-container">
                        {shuffles}
                    </ul>
                    {<div className="reactangular">{this.state.showCorrect ? 'Correct' : 'Incorrect'}</div>} 
                    <div>{points}</div> 
                    <div className="reactangular" onClick={() => this.reset()}>Reset</div>
                </>
        )
    }
}

export default DialogueShuffleFrame;

enter image description here

Ad

Answer

I'd recommend to use proper data structure with state management, but that's a different story.

To solve your specific issue of clearing input elements, you can use ReactDOM.findDOMNode to access the DOM node and traverse the input elements and set the value to empty string.

Something like this:

class App extends React.Component {
  
  check = (ref) => {

    const inputElements = ReactDOM.findDOMNode(ref.target).parentNode.getElementsByTagName('input');
    
    [...inputElements].forEach(el => el.value = '')
    
  }
  
  render() {
    return (
      <div>
        <ul>
          <li>
            <input />
            <input />
            <button onClick={this.check}>Check</button>
          </li>
          <li>
            <input />
            <input />
            <input />
            <button onClick={this.check}>Check</button>
          </li>
        </ul>
      </div>
    );
  }
  
}

ReactDOM.render(<App />, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

<div id="app"></div>

Ad
source: stackoverflow.com
Ad