Material-ui: [Table]: Hover and stripedRows not working if Row in another Component

Created on 19 Jun 2016  路  9Comments  路  Source: mui-org/material-ui

Problem description

I have a Table with several projects and their status. When My rows are rendered via a seperate component, the hover and striped effects are not applied

Steps to reproduce

My TableBody looks like this:

            <TableBody
              displayRowCheckbox={false}
              showRowHover={true}
              stripedRows={true}
            >
            {projects.valueSeq()}
            </TableBody>

My Projects currently look like this:

    const projects = props.projects.map(
      (p) => (<ProjectRow project={p} key={p.get('id')}/>)
     );

With my ProjectRow as a separate component, the hover and stripe styles are not applied.

As soon as I directly render my Row, it would work:

    const projects = props.projects.map(
      (p) => {
        return(
        <TableRow>
          <TableRowColumn className={classes.name_column}>{project.get('name')}</TableRowColumn>
          <TableRowColumn>{total}</TableRowColumn>
          <TableRowColumn>{done}</TableRowColumn>
          <TableRowColumn>{progress}</TableRowColumn>
          <TableRowColumn>{not_sure}</TableRowColumn>
          <TableRowColumn>{problem}</TableRowColumn>
          <TableRowColumn>{dont_know}</TableRowColumn>
        </TableRow>
         )
    });

Versions

  • Material-UI: 0.15.0
  • React: 15.0.0
  • Browser: Chrome

Most helpful comment

@coco-napky Hello!
Even by using a class the concept is the same.
In your render:

render() {
  const { project, ...otherProps } = this.props
  return (
    <TableRow {...otherProps}>
      <TableRowColumn>{project.name}</TableRowColumn>
      <TableRowColumn>{project.date}</TableRowColumn>
    </TableRow>
  )
}

If you take a look at the _createRows_ function of TableBody you'll see that it enhances it own children rows with some props (displayRowCheckbox etc) because it expect that its children are just <TableRow> components.

And here comes into play your ...otherProps: it will catch the props passed from <TableBody> to your TableRowWrapper and pass it to the TableRow.

<TableBody> // It passes to its children (TableRowWrappers) some props 
   <TableRowWrapper project={p} key={p.get('id')}> // It passes the received props to its children (catched by ...otherProps)
    <TableRow> 
   </TableRow>
   </TableRowWrapper>
</TableBody>

Hope it is clear now... and hope it helps and work for you! Let me know 馃尀

All 9 comments

This happens because TableBody clones its own children and injects the additional props into them 馃悜
To fix it in ProjectRow pass all the other props to TableRow this way:

const ProjectRow = ({ project, ...otherProps }) => {
  return (
    <TableRow {...otherProps}>
      <TableRowColumn>{project.name}</TableRowColumn>
      <TableRowColumn>{project.date}</TableRowColumn>
    </TableRow>
  )
}

It should be enough, let me know.

@mmazzarolo I defined my TableRowWrapper Component as a class. I couldnt find any props that I could pass from my class to TableRow Component.

@coco-napky Hello!
Even by using a class the concept is the same.
In your render:

render() {
  const { project, ...otherProps } = this.props
  return (
    <TableRow {...otherProps}>
      <TableRowColumn>{project.name}</TableRowColumn>
      <TableRowColumn>{project.date}</TableRowColumn>
    </TableRow>
  )
}

If you take a look at the _createRows_ function of TableBody you'll see that it enhances it own children rows with some props (displayRowCheckbox etc) because it expect that its children are just <TableRow> components.

And here comes into play your ...otherProps: it will catch the props passed from <TableBody> to your TableRowWrapper and pass it to the TableRow.

<TableBody> // It passes to its children (TableRowWrappers) some props 
   <TableRowWrapper project={p} key={p.get('id')}> // It passes the received props to its children (catched by ...otherProps)
    <TableRow> 
   </TableRow>
   </TableRowWrapper>
</TableBody>

Hope it is clear now... and hope it helps and work for you! Let me know 馃尀

@mmazzarolo I got it to work!

Only thing to notice is that I had to take the checkbox out of the otherProps.children array and render it explicitly.

const {name, category, quantity, maxPrice, ...otherProps} = this.props;   
    return (
  <TableRow  {...otherProps}>

       //  -> *** Checkbox in children array *** <-
        {otherProps.children[0]}             

        <TableRowColumn  >{name}</TableRowColumn>
        <TableRowColumn  style={centered}>{category}</TableRowColumn>
        <TableRowColumn  style={centered}>{quantity}</TableRowColumn>
        <TableRowColumn  style={centered}>{maxPrice}</TableRowColumn>
        <TableRowColumn>
            <IconButton>
                <FontIcon className="fa fa-pencil"  hoverColor={blue500}/>
            </IconButton>
        </TableRowColumn>
        <TableRowColumn>
            <IconButton>
                <FontIcon className="fa fa-times"  hoverColor={blue500}/>
            </IconButton>
        </TableRowColumn>
        <TableRowColumn>
         <IconButton >
            <FontIcon className="fa fa-search"  hoverColor={blue500}/>
        </IconButton>
        </TableRowColumn>
    </TableRow>
);

Thanks again for your time and lending out a hand.

@coco-napky no worries, glad it worked!

Yes thanks for pointing that out. Worked for me as well.

Forgive me but I need to write something. I have the same problem: I have TableRowColumn wrapped into Row, because it is the only way to make onClick work (after clicking users Row it routes us to detailed user view). My code looks like this

class Row extends React.Component {
  render() {
    const { id, names, surname, birth_date, pesel } = this.props
    return (
      <TableRow  onClick={this.props.onClickEvent}>
        <TableRowColumn style={styles.idColumn}>{id}</TableRowColumn>
        <TableRowColumn>{names}</TableRowColumn>
        <TableRowColumn>{surname}</TableRowColumn>
        <TableRowColumn>{birth_date}</TableRowColumn>
        <TableRowColumn>{pesel}</TableRowColumn>
      </TableRow>
    )
  }
}

function UsersTableRow(props) {
  return (
    <Row
      id={props.id}
      names={props.names}
      surname={props.surname}
      birth_date={props.birth_date}
      pesel={props.pesel}
      onClickEvent={props.onUserClick}/>
  )
}

But when I want to add ...otherProps into const in class, it gives me an error. Any ideas?

What kind of error?
Does this work?

class Row extends React.Component {
  render() {
    const { id, names, surname, birth_date, pesel } = this.props
    return (
      <TableRow  onClick={this.props.onClickEvent} {...this.props}> // !!!
        <TableRowColumn style={styles.idColumn}>{id}</TableRowColumn>
        <TableRowColumn>{names}</TableRowColumn>
        <TableRowColumn>{surname}</TableRowColumn>
        <TableRowColumn>{birth_date}</TableRowColumn>
        <TableRowColumn>{pesel}</TableRowColumn>
      </TableRow>
    )
  }
}

function UsersTableRow(props) {
  return (
    <Row
      id={props.id}
      names={props.names}
      surname={props.surname}
      birth_date={props.birth_date}
      pesel={props.pesel}
      onClickEvent={props.onUserClick}
      {...props}/> //!!!
  )
}

Right now it gives me:

Unknown props names, surname, birth_date, pesel, onClickEvent, onUserClick on tag. Remove these props from the element:
in tr (created by TableRow)
in TableRow (created by Row)
in Row (created by UsersTableRow)
in UsersTableRow (created by UsersTableRowContainer)
in UsersTableRowContainer (created by UsersTable)
in tbody (created by TableBody)
in ClickAwayListener (created by TableBody)
in TableBody (created by UsersTableHeader)
in table (created by Table)
in div (created by Table)
in div (created by Table)
in Table (created by UsersTableHeader)
in UsersTableHeader (created by UsersTable)
in UsersTable (created by RouterContext)
in div (created by Paper)
in Paper (created by Main)
in MuiThemeProvider (created by Main)
in Main (created by RouterContext)
in RouterContext (created by Router)
in Router

And hover effect still is not working. I will try to mess around with it

Was this page helpful?
0 / 5 - 0 ratings

Related issues

iamzhouyi picture iamzhouyi  路  3Comments

sys13 picture sys13  路  3Comments

zabojad picture zabojad  路  3Comments

ghost picture ghost  路  3Comments

revskill10 picture revskill10  路  3Comments