2

I want to use array.filter(my_func()) when processing 5 different arrays of user inputs to elegantly return the array without the element the user just deleted, with a private filterInput class variable. However, my_func() when used as an inner call doesn't have "this" context.

Is there a better way to do this? Would rather not write the same filter function in 5 different callers just to keep scope.

MyClass
    private inputArray1: string[];
...
    private filterInput: string;
...
    private filterFunc(element, index, array) {
        return (element !== this.filterInput);
    }
...
    public caller1(input: string) {//this is called from the onclick() in the HTML
        this.filterInput = input;
        this.inputArray1 = this.inputArray1.filter(this.filterFunc());
    }

Anyone know how to accomplish this without scrapping the filter utility and just writing my own using search then return slice1 + slice2?

patrickjp93
  • 399
  • 4
  • 20
  • 2
    Look into lambdas ("arrow functions") – Jakub Judas Mar 03 '19 at 06:25
  • 1
    Do you really need to store the `.filterInput` on your instance at all? – Bergi Mar 03 '19 at 15:07
  • @Bergi, not necessarily if there's a better way to do it (which the parameterised double return solution below looks to be). It's just the first thing that came to mind. I am an Angular novice on a big project with a tight timeline just doing what feels natural in other languages I've used. Primary backgrounds are Java and C++. I'm always open to learning though. – patrickjp93 Mar 03 '19 at 21:51
  • @patrickjp93 Thanks, I adjusted my answer below. The fourth snippet in malbarmawi's answer (if that's what you mean by "double return") is close, but you wouldn't even make a separate method to create the closure. – Bergi Mar 03 '19 at 22:06

3 Answers3

2

You can use functions bind method to fix this reference

public caller1(input: string) {
  this.filterInput = input;
  this.inputArray1 = this.inputArray1.filter(this.filterFunc.bind(this));
}

or you can use javascript arrow function

public caller1(input: string) {
  this.filterInput = input;
  this.inputArray1 = this.inputArray1.filter((elm,idx,arr) => this.filterFunc(elm,idx,arr));
}

another way be javascript functions closure ‍♂️

private filterFunc() {
    const filterInput = this.filterInput;
    return function (element, index, array) {
         return (element !== filterInput);
}

public caller1(input: string) {
    this.inputArray1 = this.inputArray1.filter(this.filterFunc());
}

but I do prefer to use parameter like this to set the filter value

private filterFunc(filterInput) {
    return function (element, index, array) {
         return (element !== filterInput);
}

public caller1(input: string) {
    this.inputArray1 = this.inputArray1.filter(this.filterFunc(this.filterInput));
}

Closures

Muhammed Albarmavi
  • 23,240
  • 8
  • 66
  • 91
0

For general solutions of how to solve this, see How to access the correct `this` inside a callback?, but for the filter method specifically just pass the context as the second argument:

this.inputArray1 = this.inputArray1.filter(this.filterFunc, this);
//                                                          ^^^^

This is relatively unidiomatic though. You wouldn't make the filterFunc an instance method at all, you'd just define a local function inside the caller1 method and make it a closure over the input parameter:

public caller1(input: string) {
    function filterFunc(element, index, array) {
        return (element !== input);
//                          ^^^^^
    }
    this.inputArray1 = this.inputArray1.filter(filterFunc);
//                                             ^^^^^^^^^^
}

or doing the same, but more concisely by defining the function inline as an expression, using arrow syntax and omitting the unneeded parameters:

public caller1(input: string) {
    this.inputArray1 = this.inputArray1.filter(element => element !== input);
}
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • I'm going with the closure answer to return the result of an inner function since it's more reusability. Thanks though. – patrickjp93 Mar 03 '19 at 23:35
0

Another possible way is to write your "filterFunc" like this (ts compiler will not put it on a prototype):

private filterFunc = (element, index, array) => {
    return (element !== this.filterInput);
}

And use it like this:

this.inputArray1 = this.inputArray1.filter(this.filterFunc);
robert
  • 5,742
  • 7
  • 28
  • 37