Meteor + React how to set the value of a lot of input elements and modify them after

- 1 answer

Ad

I'm new to meteor and react. Let's say I have this in my react component:

getMeteorData() {
    var myForm = ProjectForm.findOne({_id:this.props.router.params._id});
    var projects = ProjectForm.find({});
    return {myForm:myForm,projects:projects};
    // doing a console.log(myForm); would give you something like
    /*
    input1:my text 1
    input2:some other text
    input3:something else
    etc....
    */
  },
  renderListProjects() {

    return this.data.projects.map(function(projectform,i) {
      return <li key={"li"+i}><a href={Meteor.absoluteUrl()+'project/' + projectform.username +'/' +projectform._id} key={"a"+i}>Project {projectform._id}</a></li>;
    });
  },
  getInitialState() {
     return Projects.findOne({this.props.router.params._id}, {sort: {createdAt: -1}});
  },
  render() {
    return (
      <div>
      <ul>{this.renderListProjects()}</ul>
      <form>
         <span>Hello this is some text</span>
         <input type="text" ref="input1" />
         <p>Blah blah this is boring</p>
         <input type="text" ref="input2" />
         <img src="image-of-a-kangaroo.png" />
         <input type="text" ref="input3" />
         <ul>
            <li>Buy brocolli</li>
            <li>Buy oregano</li>
            <li>Buy milk</li>
         </ul>
         <input type="text" ref="input4" />
         ...
         <textarea ref="input100"></textarea>
         <input type="text" ref="input101" />
         <p><strong>Yes, I like pizza!</strong>  But my porcupine gets sick eating pizza.</p>
         ...
      </form>
      </div>
    );

What I want to do is assign the values of this.data.myForm to each of the form fields in the render() function. But when I do something like <input type="text" ref="input1" value={this.data.myForm.input1} />, and I go to my web browser and put my cursor on that field, I am NOT able to modify the value. Pressing the keys on my keyboard will not change the value of that input field. Additionally, I have about 250 input fields in this html form. I really don't want to do any data entry. I would much rather just use some kind of loop to iterate through the this.data.myForm and assign it to the corresponding form fields. But when I tried to do this, I get problems about the DOM not being found or it's not loaded. So I tried writing some code in componentDidMount(), but then I got other errors.

Can anyone point me in the right direction on how to efficiently bind all my this.data.myForm data to my form fields AND allow me to edit the form fields after?

Additional Requirements

  1. If someone clicks on link1 from the renderListProjects then clicks on link2 from the renderlistProjects, then the form must show the value of link2's projectform._id.

  2. In the DOM, an target="_blank" rel="nofollow noreferrer" target="_blank" rel="nofollow noreferrer" href="project/_id" attribute must exist for SEO and for WCAG compliance.

Attempts

I tried to redefine renderListProjects as

  renderListProjects() {
    var pj = this
    return this.data.projects.map(function(projectform,i) {
      return <li key={"li"+i}><a onClick={pj.click(projectform._id)} href={Meteor.absoluteUrl()+'project/' + projectform.username +'/' +projectform._id} key={"a"+i}>Project {projectform._id}</a></li>;
    });
  },
click(id) {
    var currentApp = ProjectForm.findOne({_id:id}, {sort: {createdAt: -1}});
    this.setState({input36:input36});
  },

But when I run my meteor+react project, my browser crashes because some kind of infinite loop is happening.

Ad

Answer

Ad

This code solved the problem

getMeteorData() {
    var myForm = ProjectForm.findOne({_id:this.props.router.params._id});
    var projects = ProjectForm.find({});
    return {myForm:myForm,projects:projects};
    // doing a console.log(myForm); would give you something like
    /*
    input1:my text 1
    input2:some other text
    input3:something else
    etc....
    */
  },
  clickLoadForm(appId)
  {
    var currentApp = Projects.findOne({appId}, {sort: {createdAt: -1}});
    var state = new Object();
    var refs = this.refs;
    Object.keys(refs).map(function(prop,index){
      state[prop] = typeof currentApp[prop] == 'undefined' ? "" : currentApp[prop];
    });
    this.setState(state);
  },
  handleChange: function(e) {
    if(!e.target.id) return;
    if(typeof e.target.id == 'undefined') return;
    var state = new Object();
    state[e.target.id] = e.target.value;

    this.setState(state);
  },
  renderListProjects() {

    return this.data.projects.map(function(projectform,i) {
      return <li key={"li"+i}><a onClick={_this.clickLoadForm.bind(_this,projectform._id)} href={Meteor.absoluteUrl()+'project/' +projectform._id} key={"a"+i}>Project {projectform._id}</a></li>;
    });
  },
  getInitialState() {
     return Projects.findOne({this.props.router.params._id}, {sort: {createdAt: -1}});
  },
  render() {
    return (
      <div>
      <ul>{this.renderListProjects()}</ul>
      <form>
         <span>Hello this is some text</span>
         <input type="text" ref="input1" id="input1" onChange={this.handleChange} />
         <p>Blah blah this is boring</p>
         <input type="text" ref="input2" id="input2" onChange={this.handleChange} />
         <img src="image-of-a-kangaroo.png" />
         <input type="text" ref="input3" id="input3" onChange={this.handleChange} />
         <ul>
            <li>Buy brocolli</li>
            <li>Buy oregano</li>
            <li>Buy milk</li>
         </ul>
         <input type="text" ref="input4" id="input4" onChange={this.handleChange} />
         ...
         <textarea ref="input100" id="input100" onChange={this.handleChange}/>
         <input type="text" ref="input101" id="input101" onChange={this.handleChange} />
         <p><strong>Yes, I like pizza!</strong>  But my porcupine gets sick eating pizza.</p>
         ...
      </form>
      </div>
    );

To summarize, my changes were:

  1. created a renderListProjects() function
  2. created the clickLoadForm() function and used it in the renderListProjects()
  3. created the handleChange() function and made sure it's references via onChange for each element in render()
  4. made sure every element in render() has an id that's the same as the ref
Ad
source: stackoverflow.com
Ad