Javascript [SOLVED]: React.js – Show/Hide dynamically generated elements from component

Javascript [SOLVED]: React.js – Show/Hide dynamically generated elements from component

Home Forums Scripting Javascript Tutorials Javascript [SOLVED]: React.js – Show/Hide dynamically generated elements from component

Viewing 2 posts - 1 through 2 (of 2 total)
  • Author
    Posts
  • #245685

    Cloudy Point
    Keymaster

    QuestionQuestion

    I’m generating form field elements using a component template importing an array of data. I want to be able to hide some of these elements and show them when some other’s element’s criteria has been met; this is fairly common in form fields, e.g. When you select item A, form field X appears, when you select item B, form field X is hidden.

    I’ve read a fair bit on conditional rendering on the React docs site but these examples don’t really work for what I’m doing although the Preventing Component from Rendering section is close.

    I made a Codepen demoing my setup, what I want to do is show the second field if the criteria for the first field is met (in this example, the first field should have 5 characters entered). I’ve passed through a prop to set the initial hiding but how can I find that specific hidden element and unhide it?

    // Field data
    const fieldData = [{
        "type": "text",
        "label": "First",
        "name": "first",
        "placeholder": "Enter first name",
        "hidden": false
      }, {
        "type": "text",
        "label": "Surname",
        "name": "surname",
        "placeholder": "Enter surname",
        "hidden": true
      }];
    
      // Get form data
      class FormData extends React.Component {
        constructor(props) {
          super(props);
          this.state = {
            items: props.data
          };
        }
    
        render() {
          let els = this.state.items;
    
          return els.map((el, i) => {
              return <Input key={i} params={el} />
          });
        }
      }
    
      // Input builder
      class Input extends React.Component {
          constructor(props) {
              super(props);
    
              // Keep state value
              this.state = {
                  value: '',
                  valid: false,
                  hidden: this.props.params.hidden
              };
    
              this.handleChange = this.handleChange.bind(this);
          }
    
          handleChange(e) {
              this.setState({
                  value: e.target.value,
                  valid: e.target.value.length < 5 ? false : true
              });
          }
    
          render() {
              // Element attributes
              const {type, label, name, placeholder, hidden} = this.props.params;
              const isValid = this.state.valid === true ? <span>Valid! Should show Surname field.</span> : <span>Not valid. Should hide Surname field.</span>;
    
              if (!hidden) {
                return (
                <div>
                    {label ? <label htmlFor={name}>{label}</label> : null}
                    <input
                        type={type}
                        name={name}
                        placeholder={placeholder || null}
                        value={this.state.value}
                        onChange={this.handleChange}
                    />
                    {isValid}
                </div>
                );
              } else {
                return null;
              }
          }
      }
    
      // App
      class App extends React.Component {
    
        render() {
          return (
            <div>
                <h1>Show/Hide test</h1>
                <p>What we want here is the surname to appear when firstname has a value (say, it has 5 characters) and hide surname when firstname doesn't.</p>
                <FormData data={fieldData} />
            </div>
          );
        }
      }
    
    
      ReactDOM.render(
          <form>
            <App />
          </form>,
          document.getElementById('app')
      );
    

    #245686

    Cloudy Point
    Keymaster

    Accepted AnswerAnswer

    You can lift the state up so a parent of the Input will handle the state and validations.
    You can conditionally invoke the “validator” of the surname property or any other property only if it exists and do a convention with yourself that a validate method will get the name of: propertNameValidator .
    So for example when you do the loop over the inputs, you could check if there is
    a validate method named surnameValidator and invoke it against the hidden prop that you will pass the Input, if it is not exists then just pass false.

    Here is a small example with your code:

    // Field data
    const fieldData = [
      {
        type: "text",
        label: "First",
        name: "first",
        placeholder: "Enter first name",
        hidden: false
      },
      {
        type: "text",
        label: "Surname",
        name: "surname",
        placeholder: "Enter surname",
        hidden: true
      }
    ];
    
    // Get form data
    class FormData extends React.Component {
      constructor(props) {
        super(props);
        this.state = {
          items: props.data.map(el => ({...el, value: ''})) // add the value property
        };
      }
    
      onInputChange = (inputId, value) => {
        const { items } = this.state;
        const nextState = items.map((item) => {
          if (inputId !== item.name) return item;
          return {
            ...item,
            value,
          }
        });
        this.setState({ items: nextState });
      }
    
      surnameValidator = () => {
        const { items } = this.state;
        const nameElement = items.find(item => item.name === 'first');
        return nameElement && nameElement.value.length >= 5
      }
    
      render() {
        let els = this.state.items;
    
        return (
          <div>
            {
              els.map((el, i) => {
                const validator = this[`${el.name}Validator`];
                return (
                  <Input
                    key={i}
                    {...el}
                    inputId={el.name}
                    hidden={validator ? !validator() : el.hidden}
                    onInputChange={this.onInputChange}
                  />
                );
              })
            }
          </div>
        )
      }
    }
    
    // Input builder
    class Input extends React.Component {
    
      handleChange = ({ target }) => {
        const { inputId, onInputChange } = this.props;
        onInputChange(inputId, target.value);
      }
    
      render() {
        // Element attributes
        const { type, label, name, placeholder, hidden, value } = this.props;
        return (
          <div>
            {
              hidden ? '' : (
                <div>
                  {label ? <label htmlFor={name}>{label}</label> : null}
                  <input
                    type={type}
                    name={name}
                    placeholder={placeholder || null}
                    value={value}
                    onChange={this.handleChange}
                  />
                </div>
              )
            }
          </div>
        );
      }
    }
    
    // App
    class App extends React.Component {
      render() {
        return (
          <div>
            <h1>Show/Hide test</h1>
            <p>
              What we want here is the surname to appear when firstname has a value
              (say, it has 5 characters) and hide surname when firstname doesn't.
            </p>
            <FormData data={fieldData} />
          </div>
        );
      }
    }
    
    ReactDOM.render(
      <form>
        <App />
      </form>,
      document.getElementById("app")
    );
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
    <div id="app"></div>

    If you already created the element and you just want to hide / show it, then you can conditionally add or remove a CSS class that hides it.

    <input className={`${!isValid && 'hide'}`} />
    

    Source: https://stackoverflow.com/questions/48022334/react-js-show-hide-dynamically-generated-elements-from-component
    Author: Sagiv b.g
    Creative Commons License
    This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.

Viewing 2 posts - 1 through 2 (of 2 total)

You must be logged in to reply to this topic.