3

I have an problem with the .subscribe function. First I have an function to send a request to the server. That's it.

protected sendRequest(data:string,url:string):Observable<any>{

    let headers = new Headers({ 'Content-Type': 'application/x-www-form-urlencoded' });
    let options = new RequestOptions({ headers: headers });

    //let body = 'email=' + 'email' + '&password=' + 'password';
    return this.http.post(url, data, options).map(response => response.json());
}

Now the user.service delegates the sendResquest to this file, I have injected the server.service in the user.service and so on.

public login(email:string, password:string):Observable<any>{
    //format data to send
    let data:string = 'email=' + email + '&password=' + password;
    //let body = 'email=' + 'email' + '&password=' + 'password';

    let serverReturn:Observable<any> = this.sendRequest(data,"server/request/signin.php");
    //Log the server return
    //console.log(serverReturn);

    serverReturn.subscribe(
        //set the token and session elements of a logged user
        function(data){
            //console.log(data);
            //console.log(data.isSigned);
            if(data.isSigned == "true"){
                sessionStorage.setItem("isSigned","true");
                sessionStorage.setItem("userToken", data.userToken);
            } else if(data.userBlocked == "true"){
                sessionStorage.setItem("isSigned", "false");
            } else {
                sessionStorage.setItem("isSigned", "false");
            }
        }
    );
    return serverReturn;
}

Now what I whant is get this serverReturn in the componentLogin, so there I have to know what to do based on the response for this calling. But the callback from .subscribe seems not to have access to the properties of this class. I'm following this answer There I learned that:

Usually, you take the results from the success callback and assign it to your variable.

Finally this is my login component witch call the login from user.service

import { Component, ElementRef, ViewChild } from '@angular/core';
import { ModalComponent } from '../../ui/modal/modal.component';

import { UserService } from '../../utils/user.service';

@Component({
selector: 'login',
templateUrl: 'app/system/login/tpl.html',
styleUrls: ['app/system/login/style.css'],
directives: [ModalComponent],
providers: [UserService]
})
export class LoginComponent {
constructor(private userService:UserService, private elementRef:ElementRef){

}
private result:Array<any>;
@ViewChild(ModalComponent) modal:ModalComponent;
private signin():void{

    let email:string =  this.elementRef.nativeElement.querySelector("#email").value;
    let password:string = this.elementRef.nativeElement.querySelector("#password").value;

    this.userService.login(email, password).subscribe(data => this.result = data);
    console.log(this.result);

    //this.modal.showModal('Login ','Login');
}
}

The problem is that any variable or change that I try to do within the success callback I get an undefined return. If I call a method, any method from the subscribe this get me an error too. For example, if I try to do this.

this.userService.login(email, password).subscribe(
        function(data){
            this.modal.showModal('Login ','Login');
        }
    );

I get an error:

EXCEPTION: TypeError: Cannot read property 'showModal' of undefined

What I get wrong? I'll try to set the result to an class variable. Why that all I call within the subscribe callback function seems to be undefined? I'll appreciate any help on this. Thanks.

Community
  • 1
  • 1
David Vale
  • 136
  • 1
  • 7
  • When you use 'function', it changes the value of `this` inside. Try using a lambda, i.e. `data => this.modal.showmodal('Login ','Login')` – Jason Goemaat Aug 06 '16 at 07:05
  • This really works to call the showmodal method. But then if I try to set the variable with the response data `data => this.result = data` I still get an undefined in the console. Why ? – David Vale Aug 06 '16 at 07:12
  • For debugging, set a window variable and log this to the console where you are getting the error: `window['mythis'] = this; console.log(this);` Try setting a local variable in your function before subscribing and log that too (or use it) i.e. `var self = this;` then in your callback `self.result = data;` – Jason Goemaat Aug 06 '16 at 09:26
  • I figured out what the problem is. It's happens because this is an async code, then if you log a variable before subscribe the code is continue to run and the sucess callback is executed only when the response is done. But then, the result will be "undefined" when the code after the subscribe is executed. Thanks to your suggestion and a lot more on research now I know what causes this. The question know is: How to make sure that some code is executed only if the data is allready received ? I can't passa a undefined value and then wait for server response. – David Vale Aug 06 '16 at 20:03
  • You need to execute that code in your callback to use the data. If you want to be able to let other components or services have access to it, then you can create your own observable and return that, then provide a value to that observable in your callback which will send it to any subscribers. That seems to be what you're doing with `userService.login`. Can you give a clearer example of what you want to do but can't? – Jason Goemaat Aug 07 '16 at 01:17
  • I will update the question. – David Vale Aug 08 '16 at 04:58

1 Answers1

0

As Jason Goemaat already mentioned, you need to use lambdas to access class properties.

The reason why you won't see them in the debugger is that in the transpiled code this is assigned to _this. You will see a line

var _this = this;

and for the rest of the lambda _this is used. That's why the debugger doesn't know any this. variables inside lambdas.

Try WebStorm for example. That IDE comes with a debugger that is aware of that issue and compensates for it automatically. However, it works with chrome only, as it is dependent on a chrome add-on.

hholtij
  • 2,906
  • 6
  • 27
  • 42
  • If I use lambda, it should work right ? But even in that case the code for `data => this.result = data` does not work. I should have access to the class properties. I don't know what's happening in that specific action, and if I log the `this.result` outside the subscribe I still get the undefined error. But now I have access to modal and other methods too. That is the problem now. – David Vale Aug 06 '16 at 07:56