4

I have a simple reducer, how do I bind this from outside to use that inside the reducer this.teacherInstance?

this.teachersDropMenu = this.plans.reduce(function (teacherIdArr, teacher) {
  if (teacherIdArr.indexOf(teacher.teacherId) == -1) {
     teacherIdArr.push(this.teacherInstance.getTeacherModelById(teacher.teacherId));
  }
  return teacherIdArr;
}, []);
11684
  • 7,356
  • 12
  • 48
  • 71
POV
  • 11,293
  • 34
  • 107
  • 201
  • 1
    Have you tried using an arrow function `=>` instead of the `function` keyword? – Kokodoko Dec 28 '18 at 14:59
  • 2
    Bind it to the function by using `.bind(this)` after the function. Or use a `var self = this;` outside of the reduce loop and use `self.teachInstance`. Or use an arrow function. Or alternatively, turn the logic around and use `.map()`, which supports a `this` argument as the second parameter and filter out the duplicates after. You could also make the reduction function a method of `this` so you can use `this.plans.reduce( this.findTeacherModels );` or something. – Shilly Dec 28 '18 at 15:01
  • @OPV see this https://hacks.mozilla.org/2015/06/es6-in-depth-arrow-functions/ – Sagar P. Ghagare Dec 28 '18 at 15:05
  • are you sure, that `this.teacherInstance.getTeacherModelById` returns a single id? which is possible to use with `indexOf`? – Nina Scholz Dec 28 '18 at 15:13

3 Answers3

8

Using explicit binding with Function.prototype.bind:

this.teachersDropMenu = this.plans.reduce(function (teacherIdArr, teacher) {
   if (teacherIdArr.indexOf(teacher.teacherId) == -1) {
      teacherIdArr.push(this.teacherInstance.getTeacherModelById(teacher.teacherId));
   }
   return teacherIdArr;
}.bind(this), []);

Using a closure/reference:

const self = this;
this.teachersDropMenu = this.plans.reduce(function (teacherIdArr, teacher) {
   if (teacherIdArr.indexOf(teacher.teacherId) == -1) {
      teacherIdArr.push(self.teacherInstance.getTeacherModelById(teacher.teacherId));
   }
   return teacherIdArr;
}, []);

Using an ES6 arrow function that doesn't have a this of its own, preserving the "outer" this:

this.teachersDropMenu = this.plans.reduce((teacherIdArr, teacher) => {
   if (teacherIdArr.indexOf(teacher.teacherId) == -1) {
      teacherIdArr.push(this.teacherInstance.getTeacherModelById(teacher.teacherId));
   }
   return teacherIdArr;
}, []);
connexo
  • 53,704
  • 14
  • 91
  • 128
2

Use an ES6 arrow function as they work in lexical scope, so this is determined depending on "where" it is written:

this.teachersDropMenu = this.plans.reduce((teacherIdArr, teacher) => {
   if (teacherIdArr.indexOf(teacher.teacherId) == -1) {
        teacherIdArr.push(this.teacherInstance.getTeacherModelById(
          teacher.teacherId));
   }
       return teacherIdArr;
}, []);

Also have a look here: How to access the correct `this` inside a callback?

Mohamed Ibrahim Elsayed
  • 2,734
  • 3
  • 23
  • 43
2

If you can't use arrow functions you can simply use the bind method with the anonymous function like this:

this.teachersDropMenu = this.plans.reduce(function (teacherIdArr, teacher) {
   if (teacherIdArr.indexOf(teacher.teacherId) == -1) {
        teacherIdArr.push(this.teacherInstance.getTeacherModelById(
          teacher.teacherId));
   }
       return teacherIdArr;
}.bind(this), []);

Another approach would be to store this in another variable and use the lexical scope:

var that = this;
this.teachersDropMenu = this.plans.reduce(function (teacherIdArr, teacher) {
   if (teacherIdArr.indexOf(teacher.teacherId) == -1) {
        teacherIdArr.push(that.teacherInstance.getTeacherModelById(
          teacher.teacherId));
   }
       return teacherIdArr;
}, []);

Both approaches are fine.

Rodrigo Ferreira
  • 1,091
  • 8
  • 11