0

I have the following class. I would like to convert the filterOutEmails function to use the array.some instead of the current code.

export class UsertableComponent {
  dataSource: MatTableDataSource<TrialUser>;


  createTableFromServer = (data: TrialUsers[], emailDomains:string) => {
    this.dataSource = new MatTableDataSource(data);
    this.dataSource.filterPredicate = this.filterOutEmails
  } 

  filterOutEmails = (row: TrialUser, emailDomains: string): boolean => {
    const listofFilters = emailDomains.split(',');
    for (let i = 0; i < listofFilters.length; i++){
      if (row.email.toLowerCase().includes(listofFilters[i].trim())){
        return true;
      };
    }
    return false;
  }
}

I tried doing the following, but it gave this was null, when I tried to use an arrow function, I couldn't pass in the row. (If I don't set this: TrialUser as a parameter then, "this" corresponds to Type UsertableComponent, the class the function is in, even though I'm passing in row to some as the thisObject)

private determineIfRowShouldBeShown(this: TrialUser, domain: string): boolean {
  const row: TrialUser = this;
  return !row.email.toLowerCase().includes(domain.trim());
}

private filterOutEmails= (row: TrialUser, emailDomains: string): boolean {
  const listofFilters = emailDomains.split(',');
    return listofFilters.some(this.determineIfRowShouldBeShown, row) ;
  }
}

Putting the 'determineIfRowSHouldBeShown' as an inline fat arrow function works, but I would like to keep the function definition separate.

Jethro Larson
  • 2,337
  • 1
  • 24
  • 24
Bob
  • 1,605
  • 2
  • 18
  • 33
  • 1
    Possible duplicate of [How to access the correct \`this\` inside a callback?](https://stackoverflow.com/questions/20279484/how-to-access-the-correct-this-inside-a-callback) – Jared Smith Oct 10 '19 at 19:27
  • The suggested answer in that question doesn't work for typescript and the `some` function. – Bob Oct 10 '19 at 20:26

1 Answers1

2

If you use an arrow function this becomes lexically bound even when passed as an argument:

// If you're gonna abuse `this` I wouldn't put the function in a class as it's really confusing for `this` to not be the instance. You also can't use arrow functions in this case as they prevent rebinding the context.
function determineIfRowShouldBeShown(domain: string): boolean {
    return !this.email.toLowerCase().includes(domain.trim());
}

export class UsertableComponent {
  dataSource: MatTableDataSource<TrialUser>;

  createTableFromServer = (data: TrialUsers[], emailDomains:string) => {
      this.dataSource =  new MatTableDataSource(data);
      this.dataSource.filterPredicate = this.filterOutEmails
  }
  // I don't think this is a good name since it doesn't actually filter anything.
  filterOutEmails(row: TrialUser, emailDomains: string): boolean{
    return emailDomains.split(',').some(determineIfRowShouldBeShown, row);
  }
}

This can be done a couple other ways as well:

Using manual binding of the function:

...
filterOutEmails(row: TrialUser, emailDomains: string){
  emailDomains.split(',').some(determineIfRowShouldBeShown.bind(row));
}

Using currying/partial-application (my preference)

const determineIfRowShouldBeShown = (row: TrialUser) => (domain: string): boolean => !row.email.toLowerCase().includes(domain.trim());
...
filterOutEmails(row: TrialUser, emailDomains: string){
  emailDomains.split(',').some(determineIfRowShouldBeShown(row));
}
Jethro Larson
  • 2,337
  • 1
  • 24
  • 24
  • The typescript compiler doesn't like this: `ERROR in app/trialusers/usertable/usertable.component.ts:65:18 - error TS2339: Property 'email' does not exist on type 'UsertableComponent'. return !this.email.toLowerCase().includes(domain.trim());` UserTableComponent is the class this function is sitting in. – Bob Oct 10 '19 at 21:46
  • I think I may be misunderstanding what classes these methods are in and how they relate. Can you give more context? – Jethro Larson Oct 10 '19 at 22:35
  • Updated the context. – Bob Oct 10 '19 at 23:56
  • Thanks. The currying solution is what I was looking for. Surprisingly, using bind results in the same compiler error if you don't do a forced casting on the thisArg. – Bob Oct 12 '19 at 20:45