Search code examples
javascriptangularclosuresstore

How can I access a method from a closure?


Seeking some guidance on a problem modifying an object within a closure function. I'm rewriting a program in Angular 5. My program uses a store to manage a form wizard, where some questions are answered using svg elements/buttons. Once clicked an object property is set. The code below is a skeleton version of what I'm having a problem with.

I've read other closure posts but I did not come across one that fits my scenario.

Thanks for answers and/or suggestions to refactor.

class Builder {
  object:any;

  constructor(){
    this.object = {
       car:'blue'
    }
  }

  init(){
    //Short cutting to click commands.. Using lodash
    _.forEach(database, (o)=>{
      console.log(this.object.car); // 'blue' to console
      ((function(){
         button.click(function(){
            this.object.car = 'red';
            console.log(this.object.car); //Cannot read property 
                                              'object' of undefined
         });

       })(),false)
    }
  }

}

Update to original post

I think I need to add a bit more info to my questions for others that may run into this problem. The code I provided was a skeleton of my overall code.

Before testing I did refactor the function() calls using ()={} arrow notation (in different combinations) and this did not solve the problem, because it further broke methods requiring (this).element as a result of the button.click().


Solution

  • Thanks to everyones' comment and submitted answer. I want to state that the answer provided by @LGson is a solid answer and works. But I felt I needed to clean up this post a bit and share what I did to solve this issue for my situation which uses a canvas framework to generate the UI elements that rely on (this) on the element within the button.click() event and where I could not access the outside object.

    Here is how I was able to get this to work.

    1. I changed the outer function to the arrow notation format and left the button.click() call as stated in the problem.
    2. I added a variable for self that points to the object I need to access.
    3. I added a getter method in the object to return the value of the internal reference needed and used self.car and self.getter to set and retrieve the value that I needed. And the library method continues to work as expected.

      class Builder {
       object:any;
      
       constructor(){
        this.object = {
          car:'blue',
          get value():{ return this.car;}
         }
        }
      
       init(){
        var self = this.object;
      
        _.forEach(database, (o)=>{
        console.log(this.object.car); // 'blue' to console
        ((()=>{
          button.click(function(){
               self.car = 'red';
               console.log(self.value); // red
      
          });
      
         })(),false)
      

      } } }