1

On this example, the promise that i created works ok.

But the promise from the google api don't work.

It says that the this.youtube is undefined

index.html
<script src="https://apis.google.com/js/api.js"></script>

app.component.html

<button (click)="customClick()">custom Promise</button>
<hr>

<hello name="{{ youtube }}"></hello>
<button (click)="youtubeClick()">youtube Promise</button>

app.component.ts

import { Component } from '@angular/core';
import {  } from '@types/gapi.client.youtube';
import {  } from '@types/gapi.auth2';


export class AppComponent  {

  name = 'Angular 5';
  youtube = 'youtube';

  egPromise(){
    return new Promise<void>((resolve, reject) => {
      setTimeout(function(){
        resolve();
      }, 1000);
    });
  }

  customPromise(){
    this.egPromise().then( () => {
      this.name = 'from .then angular 5'
    });
  }

  customClick(){
    this.customPromise();
  }
/****************************************************/

youtubePromise(){
  gapi.client.init({
        apiKey: 'key',
        clientId: 'id',
        scope: "https://www.googleapis.com/auth/youtube.readonly",
        discoveryDocs: [
            "https://www.googleapis.com/discovery/v1/apis/youtube/v3/rest"
        ]
        }).then(() => {
      this.youtube = 'from .then youtube'
    });
}

youtubeClick(){
  gapi.load('client:auth2', this.youtubePromise);
}

Edit: Solution/Explanation

With the help of @vivek-doshi

I found this post searching "bind this"

https://www.sitepoint.com/bind-javascripts-this-keyword-react/

And as the post explain

"it’s not always clear what this is going to refer to in your code, especially when dealing with callback functions, whose callsites you have no control over."

Since I'm working with the google API and i have no control over that code.

"This is because when the callback to the promise is called, the internal context of the function is changed and this references the wrong object."

And the function to load the library use a callback function, and don't even crossed my mind that the first callback was the problem.

So using the ES2015 Fat Arrows function, as the post says.

"they always use the value of this from the enclosing scope." ... "Regardless of how many levels of nesting you use, arrow functions will always have the correct context."

So instead of creating binding and self and that and wherever, I think that is more clean the use of =>

Other thing that it was confunsing me is that the google api aks for a callback with no argument.

So if you try to use const that = this; gapi.load('client:auth2', this.start(that) );

It will complain.

But using gapi.load('client:auth2', () => this.start() ); I'm not passing an argument.

This things could be simple for a lot of people, but since I'm learning, I will try to make it simple for others that are learning too.

Thanks everyone.

Mateus Silva
  • 756
  • 2
  • 8
  • 20
  • Please post the relevant parts of your code here – Daniel Hilgarth Mar 16 '18 at 06:58
  • sorry, posted the wrong link, now it's ok – Mateus Silva Mar 16 '18 at 07:01
  • 1
    Still, you should post all relevant parts here for future viewers as the link may go down. In addition, you are very welcome to post the link for people to play around with it, but everything needed to answer your question should be here on StackOverflow – Daniel Hilgarth Mar 16 '18 at 07:04
  • Helpful reading about `this`: https://stackoverflow.com/questions/20279484/how-to-access-the-correct-this-inside-a-callback – AT82 Mar 16 '18 at 07:07
  • @daniel-hilgarth it's possible to post angular 5 project here? The code snippet only has 1.2.23 – Mateus Silva Mar 16 '18 at 08:06
  • @MateusSilva: No, and you are not supposed to. You should post the *relevant parts* of your code. It's not necessary to be able to RUN here on SO – Daniel Hilgarth Mar 16 '18 at 08:07

2 Answers2

1

this is always the object the method is called on. However, when passing the method to then(), you are not calling it! The method will be stored somewhere and called from there later.

If you want to preserve this, you you need to preserve this before:

var that = this;
// ...
.then(function() { that.method() })
1

Here you are losing the scope of this by calling :

gapi.load('client:auth2', this.youtubePromise);

Change above code to :

gapi.load('client:auth2', () => this.youtubePromise()); // ES6 Way
// OR
gapi.load('client:auth2', this.youtubePromise.bind(this)); // Traditional old way of doing

WORKING DEMO

Vivek Doshi
  • 56,649
  • 12
  • 110
  • 122
  • ok, so this worked `gapi.load('client:auth2', () => this.youtubePromise());` but i don't completely understand why. can you point something to read about it, because I don't even know what to search, I did a lot of research before posting and don't came across any code similar to that. – Mateus Silva Mar 16 '18 at 07:22
  • @MateusSilva , this kind of issue happens most of the react side , on time of event binding , you can search via react if you want to get something more about this , for more details just google `binding this` – Vivek Doshi Mar 16 '18 at 07:25
  • @MateusSilva , will you please also accept the answer also :) – Vivek Doshi Mar 16 '18 at 07:26
  • I will, but I gonna try to edit the post and put more useful information about the problem and the answer. thanks @vivek-doshi – Mateus Silva Mar 16 '18 at 07:28
  • @MateusSilva , Thanks , Happy Coding BTW :) – Vivek Doshi Mar 16 '18 at 07:29