Angular 2 Http Post发送两个ajax请求而非一个

4

你好,我正在尝试理解Angular中可观察模式的实现,但似乎遇到了一些问题。以下是我的代码:

 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;
    }

}

这是我的在表单提交时被调用的代码:

@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>

现在我的问题是,当我点击提交按钮时,服务器将不会只收到一个ajax调用。我通过在服务器上设置断点来检查这个问题,并发现有两个调用到达。

注册函数仅在按钮被点击时调用一次。

我注意到问题出在这行代码上:

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

如果我只评论一次,那么只会向服务器发送一个ajax调用。

我的理解是,每当可观察的值发生变化时,每个订阅都会触发。

我在这里做错了什么?

更新:

问题显然也在获取调用中复制。 我应用程序中的所有获取调用都调用ths函数:

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;
}

你有检查过 register()onSubmit 事件处理程序)是否只被调用了一次吗? - Günter Zöchbauer
是的,它只被称为一次...我刚刚检查了所有遵循相同模式的get调用,它们都会触发两次。 - aleczandru
不要在你的服务中使用 EventEmitter。 - Eric Martinez
我认为请求是重复的,因为你同时使用了 (ngSubmit) 和 type="submit" 的按钮,他们都会发起请求..请尝试使用 type="button" 的按钮。 - Guido
1个回答

5

我猜你在POST可观察对象中订阅了两次,因为你在HttpServicepost方法中订阅了一次并返回它。你可能在应用程序的另一个部分再次订阅了此返回的可观察对象:

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;
}

由于 Observable 默认为 cold,因此相应的请求将会被执行两次(如果订阅了两次)。


有没有其他方法可以在结果返回时不订阅而执行代码? - aleczandru
在你的情况下,observable 是 httPost。 - Thierry Templier
嗨,Thierry!你的意思是说Angular 2文档中给出的代码示例有误吗?https://angular.io/docs/ts/latest/guide/server-communication.html#!#update ......因为我在所有的POST请求中都遇到了同样的问题,而在GET请求中没有遇到过。我也不明白Observable.do的用法——我在网上搜索了一个示例代码,但它对我也没用。你能否提供一个可行的示例代码或者告诉我该怎么做呢?我正在使用Angular 2.0.0-rc.1,请问你建议我立即升级到最新版本吗?谢谢。 - Abdeali Chandanwala
BDW我忘了说 - 我把所有的代码放在一个地方并订阅了一次,但它仍然发送两个ajax请求...请帮忙 - 谢谢。 - Abdeali Chandanwala

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接