4

Hi I am trying to wrap my head around the observable pattern implementation of angular and I seem to be having some sort of issues.Here is my code:

 import 'rxjs/Rx';
import {Injectable, EventEmitter} from 'angular2/core';
import {Http, Response, RequestOptions, Headers, URLSearchParams} from 'angular2/http';
import {Observable} from 'rxjs/Observable'
import {GuidService} from './guid.service';

@Injectable()
export class HttpService {
    private http: Http;
    private guidService: GuidService;
    public ajaxStarted: EventEmitter<string> = new EventEmitter();
    public ajaxCompleted: EventEmitter<string> = new EventEmitter(); 

    constructor(http: Http, guidService: GuidService) {
        this.http = http;
        this.guidService = guidService;
    }

    public post(url: string, model: any): Observable<Response> {
        let headers = new Headers({ 'Content-Type': 'application/json' });
        let options = new RequestOptions({ headers: headers });

        //Create unique id for each ajax call
        let httpCallId = this.guidService.new();

        //Let Loading Box components that an ajax call has been triggered
        this.ajaxStarted.emit(httpCallId);

        let httpPost = this.http.post(url, JSON.stringify(model), options);

        //Let Loadinc Box Component know that ajax call has been completed
        httpPost.subscribe(success => this.ajaxCompleted.emit(httpCallId), error => this.ajaxCompleted.emit(httpCallId));

        return httpPost;
    }

}

And this is my code that gets called on form submit:

@Component({
    selector: 'register',
    templateUrl: './app/account/components/register.view.html',
    directives: [ROUTER_DIRECTIVES]
})
export class RegisterComponent {
    private accountDataService: AccountDataService

    public registerViewModel: AccountViewModel.UserRegistrationViewModel;

    constructor(accountDataService: AccountDataService) {
        this.accountDataService = accountDataService;
        this.registerViewModel = <AccountViewModel.UserRegistrationViewModel>{};
    }

    public register() {
        this.accountDataService.register(this.registerViewModel).subscribe(x => {
            console.log(x);
        })
    }
}     

<form (ngSubmit)="register()" #userRegistrationForm="ngForm">
            <div class="form-group">
                <input class="form-control" 
                       type="email" 
                       placeholder="Email Address"
                       [(ngModel)]="registerViewModel.userName" />
            </div>
            <div class="form-group">
                <input class="form-control" 
                       type="password" 
                       placeholder="Password"
                       [(ngModel)]="registerViewModel.password" />
            </div>
            <div class="form-group">
                <input class="form-control" 
                       type="password" 
                       placeholder="Password Confirmation"
                       [(ngModel)]="registerViewModel.confirmPassword" />
            </div>
            <div class="form-group">
                <button type="submit" 
                        class="btn btn-fluid btn-primary"
                        [disabled]="!userRegistrationForm.form.valid">Register</button>
            </div>
        </form>

Now my problem is that when I click the submit button instead of one ajax calls to get sent to the server.I have checked this by putting a brakepoint on the server and two calls arive.

The register function gets called only oance on button clicked.

I have noticed that my problem is this line:

  httpPost.subscribe(success => this.ajaxCompleted.emit(httpCallId), error => this.ajaxCompleted.emit(httpCallId));

If I comment it only one ajax call gets sent to the server.

The way that I understand observables is that each subscribe gets triggered when ever the observable value changes.

What am I doing wrong here?

UPDATE:

The issue apparently replicates also in the get calls. All the get calls in my app call ths function:

public get(url: string, model: any = {}): Observable<Response> {
    let httpCallId = this.guidService.new();

    this.ajaxStarted.emit(httpCallId);

    let httpGet = this.http.get(url, new RequestOptions({
        headers: this.getHttpHeaders(),
        search: this.createURLSearchParams(model)
    }));

    httpGet.subscribe(success => this.ajaxCompleted.emit(httpCallId), error => this.ajaxCompleted.emit(httpCallId));

    return httpGet;
}
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
aleczandru
  • 5,319
  • 15
  • 62
  • 112
  • Did you check if `register()` (`onSubmit` event handler) is only called once? – Günter Zöchbauer Mar 20 '16 at 19:32
  • Yes it is called only oance... I just checked all my get calls which follow the same pattern they all fire twice – aleczandru Mar 20 '16 at 19:32
  • [Don't use EventEmitter in your services](http://stackoverflow.com/questions/36076700/what-is-the-proper-use-of-an-eventemitter) – Eric Martinez Mar 20 '16 at 20:08
  • I think that the request is duplicated because you have (ngSubmit) and button type submit..so both do the request.. try with a button type button. – Guido Sep 13 '16 at 16:34

1 Answers1

5

I guess that you subscribe twice to your POST observable because you subscribe once within the post method of the HttpService and return it. You probably subscribe again on this returned observable in another part of your application:

public post(url: string, model: any): Observable<Response> {
    let headers = new Headers({ 'Content-Type': 'application/json' });
    let options = new RequestOptions({ headers: headers });

    //Create unique id for each ajax call
    let httpCallId = this.guidService.new();

    //Let Loading Box components that an ajax call has been triggered
    this.ajaxStarted.emit(httpCallId);

    let httpPost = this.http.post(url, JSON.stringify(model), options);

    //Let Loadinc Box Component know that ajax call has been completed
    httpPost.subscribe(success => { // <-------
        this.ajaxCompleted.emit(httpCallId);
    }, error => {
       this.ajaxCompleted.emit(httpCallId);
    });

    return httpPost;
}

Since observables are cold by default, the corresponding request will be executed twice (if subscribed twice).

Thierry Templier
  • 198,364
  • 44
  • 396
  • 360
  • Is there any other way to execute code without subscribing when the resul returns? – aleczandru Mar 20 '16 at 20:02
  • In you case observable is httPost – Thierry Templier Mar 20 '16 at 20:06
  • Hey Thierry ! ... so do you mean that the code sample given on angualr 2 docs is wrong is some way ... https://angular.io/docs/ts/latest/guide/server-communication.html#!#update ....... Because I am getting same problem on all post request and not on Get request ... I also didnt got observable.do things - I searched on net and got a sample code - but that also didnt worked for me. Can you please post a working sample or what shall I do ?? I am using Angular 2.0.0-rc.1 - let me know if you recommend me update to latest version immediately or no - thank you – Abdeali Chandanwala Aug 11 '16 at 08:38
  • BDW i forgot to say - that I took all the code in one place and subscribed it once and tried it but it still sends two ajax request ... please do help - TY – Abdeali Chandanwala Aug 11 '16 at 08:59