1

The issue in my previous question was recently solved and has now created a new issue, where the values from my array are not displayed in the rendered dropdown list. Using the answer given to me in my previous question, populates the list with the correct keys, but I'm interested in the values from the array, not key values. I've listed my modified render method below, and an example of my classes datatype which was received by my classes prototype from another component in my app.

Edit: I found this source which does exactly what I want to do, but when trying their code, I get an error in the console stating "e.map is not a function". I posted the code I tried below as well.

Edit 2: To not get into much detail, I'm retrieving data from my SQL Server database, via an AJAX request when the component is initially mounted (component did mount function below). I do my server-side stuff via .Net/C#, and bring that data back client side into an array via xhttp.responseText and string.prototype.split. To make debugging faster, I'm skipping the ajax request all together to not rely on the database call each time (hence why its checking for the 404 error), and instead, I'm setting an explicitly declared array named 'n' as the classes state. My Dropdown component (the component in question) has a property named "classes" which is tied to the current state of classes (which is set as explained above), that code is posted below as well.

classes example:

['justin','tom','bob']

Render Method:

render: function(){

    return(
        <div>

         <select onChange = {this.change}>
         {
            Object.keys(this.props.classes).map((value, key) =>{

            return <option key = {key}>{value}</option>
            }
         )}
          </select>
        </div>

    )

}



});

New Code tried:

export default React.createClass({

    getInitialState: function(){
      return{classes: this.props.classes }  
    },

    render: function() {
        var names = this.state.classes;
        console.log(names);
        return (
            <select>
                {names.map(function(name, index){
                    return <option key={ index }>{name}</option>;
                  })}
            </select>
        )
    }
});

Edit 2 Code:

componentDidMount: function(){
      var xhttp; 
      var myStr;
      var user = window.x;
      console.log("the current user is "+ user);
     xhttp = new XMLHttpRequest();
     xhttp.onreadystatechange = function() {
    if (xhttp.readyState == 4 || xhttp.status == 404) {
    document.getElementById("test").innerHTML = xhttp.responseText;
    myStr = xhttp.responseText;
    //n = myStr.split("\n");
    n = ['justin', 'earl', 'samuels', 'tom'];
    console.log(n);
    this.setState({ classes: n });
    }
  }.bind(this);
  xhttp.open("GET", "/portals/0/js/hello.aspx?q="+user, true);
  xhttp.send();  
  },

Dropdown component:

<Dropdown classes = {this.state.classes} />
Community
  • 1
  • 1
Justin E. Samuels
  • 867
  • 10
  • 28

2 Answers2

1

See my working example with setTimeout to simulate the async call.

The important change is that you need to get names from props instead of state:

render: function() {
    var names = this.props.classes;
    console.log(names);
    return (
        <select>
            {names.map(function(name, index){
                return <option key={ index }>{name}</option>;
              })}
        </select>
    )
}

The following code:

export default React.createClass({

    getInitialState: function(){
      return{classes: this.props.classes }  
    },

    render: function() {
        var names = this.state.classes;
        console.log(names);
        return (
             <select>
                 {names.map(function(name, index){
                     return <option key={ index }>{name}</option>;
                   })}
             </select>
         )
     }
 });

is a anti-pattern. Because getInitialState is only invoked when the component is first created (with classes prop being an empty array) the state of component wasn't updated when it received classes prop (now array with data from server) after your async call succeeded.

Július Retzer
  • 1,055
  • 1
  • 10
  • 25
  • Hey, I was thinking the same thing, but I had console logged the array within the component and the array was available for manipulation. I got the answer from a friend (and it worked), and I'm about to post it now. It was really trival, I almost feel crazy for overthinking it. 1 sec – Justin E. Samuels May 15 '16 at 00:02
0

My friend Chris gave me the answer which was really trival in nature. Basically, since I was using Object.keys , I was getting only the specific key, and not the value upon execution. So to get the value, all I needed to add was {this.props.classes[value]}where I was expecting the value in my option JSX tag. Full code listed below.

Render Method using Object.keys:

render: function(){

    return(
        <div>

         <select onChange = {this.change}>
         {
            Object.keys(this.props.classes).map((value, key) =>{

            return <option key = {key}>{this.props.classes[value]}</option>
            }
         )}
          </select>
        </div>

    )

}
Justin E. Samuels
  • 867
  • 10
  • 28
  • This kind of answers different question that you asked, because in your question you provided an example of `classes` as an array, while here you iterate over object. Anyway, I'm glad you got it working now. – Július Retzer May 15 '16 at 00:19
  • 'classes' is an array, which is held in the this.props.classes object. So if you enumerate over the object, you'll get the amount of properties in the object (3 for example) and then you can use that access the array – Justin E. Samuels May 15 '16 at 00:22
  • Like seen here: http://stackoverflow.com/questions/29149169/how-to-loop-and-render-elements-in-react-js-without-an-array-of-objects-to-map – Justin E. Samuels May 15 '16 at 00:23