8

I have created a helper function that creates elements dynamically within my component when I click a button. However it's not displaying half of the html I'm trying to append to the parent div.

It adds the label correctly as html, but the rest is just in plain text. Can anyone see why?

The function used to dynamically create content:

function addElement(parentId, elementTag, elementId, html) {
    let parentElement = document.getElementById(parentId);
    let elementToAdd = document.createElement(elementTag);
    elementToAdd.setAttribute('id', elementId);
    elementToAdd.innerHTML = html;
    parentElement.appendChild(elementToAdd);
}

My function within my component:

static addMatch() {
    let html = "<div className=\"form-group\"><label className=\"control-label\">Add Match</label>" +
        "<DatePickerselected={this.state.startDate}onChange={this.handleChange.bind(this)}/></div>";
    addElement('fixture-parent', 'newMatch', uuid(), html);
}

My full react component is below:

import React, {Component} from "react";
import DatePicker from "react-datepicker";
import {addElement} from "../../helpers/DynamicElementsHelper";
import moment from "moment";
const uuid = require('uuid/v1');

require('react-datepicker/dist/react-datepicker.css');

class Fixtures extends Component {

    constructor() {
        super();
        Fixtures.addMatch = Fixtures.addMatch.bind(this);
        this.state = {
            startDate: moment()
        };
    }

    handleChange(date) {
        this.setState({
            startDate: date
        });
    }

    static addMatch() {
        let html = "<div className=\"form-group\"><label className=\"control-label\">Add Match</label>" +
            "<DatePicker selected={this.state.startDate} onChange={this.handleChange.bind(this)} /></div>";
        addElement('fixture-parent', 'newMatch', uuid(), html);
    }

    render() {
        return (
            <div className="tray tray-center">
                <div className="row">
                    <div className="col-md-8">
                        <div className="panel mb25 mt5">
                            <div className="panel-heading">
                                <span className="panel-title">Fixtures</span>
                                <p>A list of fixtures currently on the system, pulled in via ajax from Ratpack</p>
                            </div>
                            <div className="panel-body p20 pb10">
                                <div id="fixture-parent" className="form-horizontal">
                                    <div className="form-group">
                                        <label className="control-label">Add Match</label>
                                        <DatePicker
                                            selected={this.state.startDate}
                                            onChange={this.handleChange.bind(this)}/>
                                    </div>
                                </div>
                            </div>
                            <button onClick={Fixtures.addMatch }>Add Match</button>
                        </div>
                    </div>
                </div>
            </div>
        );
    }

    }

    export default Fixtures;
3
  • In React, it is recommended to not interact with the DOM directly. Instead, you should modify the JSX depending on data that you have. Would you mind adding more code to see the React part of the question? Commented May 9, 2017 at 15:11
  • 1
    Added my full react component. Commented May 9, 2017 at 15:22
  • 1
    I would assume it's because the DatePicker is a react component, and not html, so rendering that html string will not render the component, only the string. Regardless, this method of updating the DOM is pretty much anti-react and can cause big problems. You should let react handle creating the additional elements. Commented May 9, 2017 at 16:42

2 Answers 2

3

In React, it is recommended to not interact with the DOM directly. Instead, you should modify the JSX depending on data that you have. For your code, instead of adding an HTML tag with data from the state that changes, you should change the state and display information based on that:

addMatch() {
    //Add a start date to the list of starting dates
    this.setState({
        listOfStartDates: [...this.state.listOfStartDates, newDate]
    }); 
}

render(){
    //For each starting date, generate a new 'match' as you called them
    // note: this is the same as the stringyfied HTML tag OP had in the question
    let listOfMatches = this.state.listOfStartDates.map((date)=>{
        return (
            <div className="form-group">
                <label className="control-label">
                    Add Match
                </label>
                <DatePicker selected={date} onChange={this.handleChange.bind(this)} />
            </div>
        );
    /* then in here your returned JSX would be just as OP originally had, with the exception that you would have {listOfMatches} where OP used to have the inserted list of HTML tags */
    return //...
}

Since the component will re-render every time the state changes, the component will always have as many matches as you have starting dates.

Hope that helps!

Sign up to request clarification or add additional context in comments.

Comments

1

Put a space between DatePicker and selected.

 "<DatePicker selected={this.state.startDate}onChange={this.handleChange.bind(this)}/></div>";

2 Comments

Didn't work, think it may be because the DatePicker is a react thing, so when it renders in the HTML, it renders differently
@NickPocock right, at first glance that's what I saw, can you post some of the rendered HTML?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.