2

I created a function to sort a state array of objects according to one of the key: value pairs. Here's what it looks like: It's currently working.

State:

class Employee extends Component {
state = {
  employeeData: [],
  filteredEmployeeData: [],
  search: '',
  sort: 'asc',
  error: '',
}

Working function:

  sortFirstName = () => {
    console.log('SORTING!!!!')
    const {employeeData} = this.state
    const sorted = employeeData.sort((a, b) => {
          if (a.name.first < b.name.first){
            return -1
        } else if (a.name.first > b.name.first){
            return 1
        } else {
          return 0
        }
    })
    console.log('Sorted List: ', sorted)
    this.setState({filteredEmployeeData: sorted})
}

Render:

  render () {
    return (
      <div>
        <Container style={{ minHeight: "80%" }}>
        <br/>
          <h1 className="text-center">Search For An Employee</h1>
          <Alert
            type="danger"
            style={{ opacity: this.state.error ? 1 : 0, marginBottom: 10 }}
          >
            {this.state.error}
          </Alert>
          <SearchForm
            handleInputChange={this.handleInputChange}
            search={this.state.search}
          />
        </Container>
        <Container>
        <table className="table table-hover">
        <thead>
            <tr>
            <th scope="col" >Image</th>
            <th scope="col" value="firstName" onClick={(this.sortFirstName)}>First Name</th>
            <th scope="col" value="lastName">Last Lame</th>
            <th scope="col" value="email">Email</th>
            <th scope="col" value="phoneNumber">Phone Number</th>
            <th scope="col" value="city">City</th>
            <th scope="col" value="SSN">SSN</th>
            </tr>
        </thead>
        <tbody>
        {this.state.filteredEmployeeData.map(ee => (
          <EmployeeData
            id={ee.login.uuid}
            key={ee.login.uuid}
            img={ee.picture.thumbnail}
            firstName={ee.name.first}
            lastName={ee.name.last}
            email={ee.email}
            phone={ee.cell}
            city={ee.location.city}
            ssn={ee.id.value}
          />
        ))}
        </tbody>
        </table>
        </Container>
      </div>
    );
  }}

What I'd like to do is update the function to be dynamic so that any of my table headers can be clicked and the data will sort accordingly. I tried it as something like this but I can't quite figure out a way to do it.

My attempt at creating a dynamic sort function (doesn't work):

  sort = (header) => {
    console.log('SORTING!!!!')
    const {employeeData} = this.state
    const sorted = employeeData.sort((a, b) => {
          if (a.header < b.header){
            return -1
        } else if (a.header > b.header){
            return 1
        } else {
          return 0
        }
    })
    console.log('Sorted List: ', sorted)
    this.setState({filteredEmployeeData: sorted})
}

Render with dynamic sorts (doesn't work)

        <thead>
            <tr>
            <th scope="col" >Image</th>
            <th scope="col" value="firstName" onClick={(this.sort('name.first')}>First Name</th>
            <th scope="col" value="lastName" onClick={(this.sort('name.last')}>Last Lame</th>
            <th scope="col" value="email" onClick={(this.sort('email')}>Email</th>
            <th scope="col" value="phoneNumber" onClick={(this.sort('cell')}>Phone Number</th>
            <th scope="col" value="city" onClick={(this.sort('city')}>City</th>
            <th scope="col" value="SSN" onClick={(this.sort('ssn')}>SSN</th>
            </tr>
        </thead>

Any help here would be appreciated.

2 Answers 2

1

For "name.first" and "name.last", there is a little bit of work. You need to make it into a single word to access it. For nested object I prefer this solution from this post:

function fetchFromObject(obj, prop) {

    if(typeof obj === 'undefined') {
        return false;
    }

    var _index = prop.indexOf('.')
    if(_index > -1) {
        return fetchFromObject(obj[prop.substring(0, _index)], prop.substr(_index + 1));
    }

    return obj[prop];
}
sort = (header) => {
    console.log('SORTING!!!!')
    const {employeeData} = this.state
    const sorted = employeeData.sort((a, b) => {
          const x = fetchFromObject(a, header);
          const y = fetchFromObject(b, header); 
          if (x < y){
            return -1
        } else if (x > y){
            return 1
        } else {
          return 0
        }
    })
    console.log('Sorted List: ', sorted)
    this.setState({filteredEmployeeData: sorted})
}
Sign up to request clarification or add additional context in comments.

3 Comments

Thanks! I got the first part to work, but I'm having trouble getting the nested object part to work. How would I call that function via onClick with sort?
@Valborg I have updated my answer. fetchFromObject can handle all cases
How do I upvote you twice? hahaha thanks!
0

As per my understanding you want something like this.

This is dynamic sorting with the string dot notation accessing the object

sort = (header) => {
         const {employeeData} = this.state;
       
    const sorted = employeeData.sort((a, b) => {
      a = getDescendantProp(a, header);
      b = getDescendantProp(b, header);
          if (a < b){
            return -1
        } else if (a> b){
            return 1
        } else {
          return 0
        }
    })
    console.log('Sorted List: ', sorted)
    this.setState({filteredEmployeeData: sorted})
}



function getDescendantProp(obj, desc) {
    var arr = desc.split(".");
    while(arr.length && (obj = obj[arr.shift()]));
    return obj;
}

Comments

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.