via
via

Reputation: 503

change color depending on value with javascript

I'm using React and want to change text color depends on the value. The code looks like this:



const ProductCard = (props) => {
    const classes = useStyles();

    useEffect(() => {
        const category = document.getElementById('category');

        if(props.category === "youtube"){
            category.style.color="#DC143C";
        }
        if(props.category === "blog"){
            category.style.color="#00FFFF";
        }
        if(props.category === "instagram"){
           category.style.color="#FF88FF";
        }
        if(props.category === "twitter"){
            category.style.color="#3366FF";
        }
    }, []);

    return (
        <Card className={classes.root}>
            <CardContent className={classes.content}>
                <Typography id="category" className={classes.category} component="p">
                    {props.category}
                </Typography>
            </CardContent>
        </Card>
    )
}

export default ProductCard

With this code, only the first value of the element is changed, the rest are not. What I'm doing wrong?

Upvotes: 2

Views: 921

Answers (3)

Kishieel
Kishieel

Reputation: 2053

First - you should avoid querying dom inside react app. You can create state for holding your class or styles and then pass it to component.

Second - remove empty array from useEffect it should help.

Upvotes: 1

buzatto
buzatto

Reputation: 10382

your code only runs on mount with empty array dependency, hence any change on props won't be reflected. that's the most likely the problem here.

fwiw your code is rather complicated and it's better to avoid manipulating the DOM directly, it would much simpler if you create a dictionary to apply your style to your element like:

    const colors = {
      youtube: "#DC143C", 
      blog: "#00FFFF", 
      instagram: "#FF88FF", 
      twitter: "#3366FF", 
    }

    const ProductCard = ({ category }) => {
      const classes = useStyles();
  
      return (
          <Card className={classes.root}>
              <CardContent className={classes.content}>
                  <Typography id="category" style={{ color: colors[category] }} className={classes.category} component="p">
                      {category}
                  </Typography>
              </CardContent>
          </Card>
      )
  }
  
  export default ProductCard

Upvotes: 1

Nick
Nick

Reputation: 6362

When you get an element by id, only one element is returned.

const category = document.getElementById('category'); // referring to this line

That's because technically, ids should be unique. Only one element should have the id category on the page. So when you set the style on container, only one element is changed because it is only one element.

Additionally, ids are not scoped to a specific component. So if you have multiple ProductCard components, getElementById will always return the category of the first ProductCard component.

Solutions

I'm not familiar with your exact components, so not all of these will work for you. But at least one should.

Use a color prop

If your Typography component accepts a color or style prop, use that. Then, you're telling React "this specific component should have this color".

const colors = {
    youtube: "#DC143C", 
    blog: "#00FFFF", 
    instagram: "#FF88FF", 
    twitter: "#3366FF", 
}

const ProductCard = (props) => {
    const classes = useStyles();

    return (
        <Card className={classes.root}>
            <CardContent className={classes.content}>
                <Typography id="category" className={classes.category} component="p" style={{ color: colors[props.category] }}>
                    {props.category}
                </Typography>
            </CardContent>
        </Card>
    )
}

export default ProductCard

Use a wrapper component

You may be able to wrap a div around just the typography and set the text color that way. Not the best option, but it will work.

const colors = {
    youtube: "#DC143C", 
    blog: "#00FFFF", 
    instagram: "#FF88FF", 
    twitter: "#3366FF", 
}

const ProductCard = (props) => {
    const classes = useStyles();

    return (
        <Card className={classes.root}>
            <CardContent className={classes.content}>
                <div style={{ color: colors[props.category] }}>
                    <Typography id="category" className={classes.category} component="p" style={{ color: colors[props.category] }}>
                        {props.category}
                    </Typography>
                </div>
            </CardContent>
        </Card>
    )
}

export default ProductCard

Upvotes: 0

Related Questions