简体   繁体   中英

Angular 4 http calls executed twice

I have a express server and Angular 4 application that cohabitate in one project. It is based upon this starter: https://github.com/vladotesanovic/angular2-express-starter

The issue I am having is that when Angular does a post or get, it fires twice.
在此处输入图片说明

You can imagine how this is an issue when doing a post!

This is my component:

import { Component, OnInit } from '@angular/core';
import { Settings } from '../shared/settings/settings';
import { SettingsService } from '../shared/settings/settings.service';
import { Observable } from 'rxjs/Observable';

@Component({
    templateUrl: './welcome.component.html',
    styleUrls: ['./welcome.component.scss']
})
export class WelcomeComponent implements OnInit {
    settings:  Observable<Settings[]>;
    error: any;

    constructor(
        private settingsService: SettingsService) {
    }

    ngOnInit() {
        this.getSettings();
    }

    getSettings() {
        this.settings = this.settingsService.getSettings();
      }
}

The service is:

import { Injectable } from '@angular/core';
import { Headers, Http, Response } from '@angular/http';
import 'rxjs/add/operator/catch';
import { Settings } from './settings';
import {Observable} from 'rxjs/Rx';
import { ErrorComponent } from '../error/error.component';
import { MdDialog, MD_DIALOG_DATA } from '@angular/material';

@Injectable()
export class SettingsService {
  constructor(private http: Http,  private dialog: MdDialog) { }

extractData(res: Response) {
    return res.json();
}

getSettings(): Observable<Settings[]> {
    return this.http.get('/api/getSettings').map(this.extractData).catch(error => this.handleError(error));
}


private handleError(error: any): Promise<any> {
    const dialog = this.dialog.open(ErrorComponent, {
        data: {
            error: error
        }
    });

    return Promise.reject(error.message || error);
}
}

The app.module is:

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { HttpModule } from '@angular/http';
import { MaterialModule } from '@angular/material';
import 'hammerjs';
import { AppRoutingModule } from './app-routing.module';
import { FlexLayoutModule } from '@angular/flex-layout';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';

import { SettingsService } from './shared/settings/settings.service';

import { AppComponent } from './app.component';
import { WelcomeComponent } from './welcome/welcome.component';
import { OrderComponent } from './order/order.component';
import { ErrorComponent } from './shared/error/error.component';
import { SuccessComponent } from './shared/success/success.component';

import { TextMaskModule } from 'angular2-text-mask';
import { LoadingBarHttpModule } from '@ngx-loading-bar/http'; //https://github.com/aitboudad/ngx-loading-bar
import {enableProdMode} from '@angular/core';



@NgModule({
    declarations: [
        AppComponent,
        WelcomeComponent,
        OrderComponent,
        ErrorComponent,
        SuccessComponent
    ],
    imports: [
        BrowserModule,
        HttpModule,
        MaterialModule,
        AppRoutingModule,
        FlexLayoutModule,
        BrowserAnimationsModule,
        FormsModule,
        ReactiveFormsModule,
        TextMaskModule,
        LoadingBarHttpModule
    ],
    providers: [
        SettingsService
    ],
    bootstrap: [
        AppComponent
    ],
    entryComponents: [
        ErrorComponent,
        SuccessComponent
    ]

})
export class AppModule { }

For the server side, I can add more code or post the entirety to GitHub, but the proxy.conf.json and package.json are essentially the same as his starter. My guess is that a module is being double loaded or perhaps I am using Observables wrong?

package.json:

"scripts": {
    "start": "concurrently --kill-others \"npm run _server:run\" \"ng serve --aot=false --progress=false --proxy-config proxy.conf.json\"",
    "lint:client": "ng lint",
    "lint:server": "tslint './server/**/*.ts' -c ./server/tslint.json --fix",
    "test:client": "ng test",
    "e2e:client": "ng e2e",
    "build": "ng build --prod --sm=false --aot --output-path=dist/client && npm run _server:build",
    "_server:run": "tsc -p ./server && concurrently \"tsc -w -p ./server\" \"nodemon --delay 5 dist/server/bin/www.js\" ",
    "_server:build": "tsc -p ./server",
    "postinstall": "npm run build"
  },

proxy.json.conf:

{
  "/api": {
    "target": "http://localhost:4300",
    "secure": false
  }
}

Edit to show a different approach.

Even if I do this with Promises, I still have the same issue, which makes me think it is something in the router or app.module still.

export class WelcomeComponent implements OnInit {
    settings: Settings[];
    error: any;

    constructor(
        public dialog: MdDialog,
        private router: Router,
        private settingsService: SettingsService) {
        console.log('calling constructor');
    }


    async ngOnInit(): Promise<void> {
        console.log('calling onInit');
        this.getSettings();
    }


    async getSettings(): Promise<void> {
        this.settingsService.getSettings()
            .then(result => this.settings = result)
            .catch(error => this.handleError(error));
    }

}

Here is the service

async getSettings(): Promise<Settings[]> {
      console.log('calling SettingsService');
      try {
          const response = await this.http
              .get('/api/getSettings')
              .toPromise();
          return response.json() as Settings[];
      } catch (error) {
          await this.handleError(error);
      }
  }

在此处输入图片说明

The fact you are seeing the call firing twice in the chrome dev tools means that the issue is on the client side.

My suggestion is to subscribe to the call instead of assigning the returned observable to a local property. Then you can make a break point at entry point of you method that calls the service. Once hit, have a look at the call stack to see who is firing the call. I would guess that you will see the OnInit method calling getSettings() twice. To which case I would assume that your component is being created twice for some reason in your application.

The culprit turned out to be a 3rd party: https://github.com/aitboudad/ngx-loading-bar

If you are using ngx-loading-bar, LoadingBarHttpModule will cause this behavior. I haven't managed to get LoadingBarHttpClientModule to work yet.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM