2

Background

I am trying to pass a css class name in a variable called styling to my className on the tr element. I think my problem here is that I have yet to grasp the concept of props.

Basically I have a component written in ES6 and I want to change the css class of a tr based on the value of the child td.

Problem

With my current code I get

styling not defined

But this does console.log all of the appropriate css class out so I know everything is good minus the actual class being added to className of the tr tag. For some reason it is not passing the variable inside from componentDidMount to render.

Question

Please explain to me how to pass variables throughout my React.js component / components?

Example

    class TableDisplay extends React.Component{
                    constructor(props) {
                    super(props);
                }
                componentDidMount() {
                    var styling = " ";
                var tCells = document.getElementsByTagName("td");
                for (var i = 0; i < tCells.length; i++) {
                        if(tCells[i].innerHTML == "Approved") {
                        console.log("bg-success");
                        styling = "bg-success";
                    } else if (tCells[i].innerHTML == "Denied") {
                        console.log("bg-danger");
                        styling = "bg-danger"; 
                    } else {
                        console.log("bg-plain");
                        styling = "bg-plain";
                    }
                }
                }
            render() {
                return <div><table className="table">
                        <tr className="seperate"><td>Title</td><td>Status</td><td>Created</td><td>Updated</td><td>Delete</td></tr>
                      {Object.keys(requests).map(function(key) {
// Problem appears to be here   
                           return <tr className={styling}>
                                <td>{requests[key].title}</td>
                                <td>{requests[key].status}</td>
                                <td>{requests[key].created_at.slice(0, 10)}</td>
                                <td>{requests[key].updated_at.slice(0, 10)}</td>
                                <td><a href="">Delete</a></td>
                              </tr>;

                                        })}
                    </table>
                   </div>;
           }
    }

What I Have Tried

I did think this could be a scope or closure issue. So I have tried.

Global

Making styling a global variable. That did not work.

This

Tried to use this.styling. That did not work either.

Moved Inside Render

I moved the loop inside render. When I did that it added the styling variable to the className but only the first initial declaration of styling = " ";. So basically it just made every tr have a space for the className.

2
  • Does your "Approved" and "Denied" text comes from requests[key].status or requests[key].title? If so have you tried moving it inside the render function but comparing with those variables instead of innerHTML? Commented Jan 14, 2017 at 23:10
  • I have tried moving it. At the bottom of my question I explain the outcome. Basically if I remove styling from the className it runs the app and it outputs all the correct data to the console. But when I move the loop inside render it just adds a space in the className spot for every tr tag Commented Jan 14, 2017 at 23:11

2 Answers 2

1

Assuming your "Approved" and "Denied" text is from requests[key].status. can't you just do something like this:

{Object.keys(requests).map(function(key) {  
    let styling = "bg-plain";

    if (requests[key].status === "Approved") {
        styling = "bg-success";
    } else if (requests[key].status === "Denied") {
        styling = "bg-danger";
    }

    return <tr className={styling}>
        <td>{requests[key].title}</td>
        <td>{requests[key].status}</td>
        <td>{requests[key].created_at.slice(0, 10)}</td>
        <td>{requests[key].updated_at.slice(0, 10)}</td>
        <td><a href="">Delete</a></td>
    </tr>;

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

4 Comments

Thanks lol. Jesus man. I'm spending so much time trying to figure out how react's scope works I glazed right over the obvious.
I must say though. I am still worried why I cant get scope or props to work. If you have any input into that let me know.
@wuno From your "Example Based On Answer" edit. I can see why this.state.styling isn't defined. Since you are not using the ES6 arrow function as callback, your this variable isn't in the outer scope. From ES5, people like to have var self = this outside then use self.state.foo in the callback. Maybe you should take a look at this: jsrocks.org/2014/10/arrow-functions-and-their-scope for this beautiful arrow functions.
Ok awesome thanks a lot man! So you mean I should of had an arrow function inside componentDidMount?? WOuld you mind showing me what you mean?
0

You'll want to use state in your component so that you can access these variables that are modified at different times during the component's lifecycle.

When you create TableDisplay set the initial state in the constructor like so:

class TableDisplay extends React.Component{
  constructor(props) {
    super(props);
    this.state = {styling: ""};
  }

and based on the conditional in your componentDidMount function above change this state by using the setState function like so:

this.setState({ styling: "what ever you want to change it to"});

and access this state by using this.state.styling in your render function like so:

<tr className={this.state.styling}>

The reason your render function couldn't use the styling variable because it's not in the same scope. Once componentDidMount was done running, the variable styling disappeared. So React's state allows you to access variables throughout your component.

1 Comment

I updated my question using your explanation. Please look at the bottom of my question and tell me if I am doing what you suggested. I am gettting state is not defined

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.