4

I have an AlertService which has confirm box. I am calling that from my service. If user hits Yes, then I want to call a REST service. But I am getting this error:

I believe since I am calling from inside alertService.confirm(), and alertService does not have http declared, I am gettgn this error. But I am not sure what the appropriate way to resolve this.

ERROR TypeError: Cannot read property 'http' of undefined
    at inspection.service.ts:91
    at Object.siFn (alert.service.ts:53)
    at Object.eval [as handleEvent] (AlertComponent.html:25)
    at handleEvent (core.es5.js:11998)
    at callWithDebugContext (core.es5.js:13467)
    at Object.debugHandleEvent [as handleEvent] (core.es5.js:13055)
    at dispatchEvent (core.es5.js:8614)
    at core.es5.js:9228
    at HTMLAnchorElement.<anonymous> (platform-browser.es5.js:2648)
    at ZoneDelegate.webpackJsonp../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:421)

inspection.component.ts

import {Component, OnInit, Input, ViewChild} from "@angular/core";
import {Headers, Http} from "@angular/http";
import {Router} from "@angular/router";
import {NgModel, FormGroup} from "@angular/forms";
    sendMesage(inspection) {
          this.inspectionService.sendMesage(inspection);
    }

inspection.service.ts

import {Headers, Http}  from "@angular/http";
import {Observable} from 'rxjs/Observable';
import {Subject} from "rxjs";
import {of} from 'rxjs/observable/of';
import {HttpClient, HttpHeaders} from '@angular/common/http';
import {Injectable}     from "@angular/core";
import {Component, OnInit, ViewChild} from "@angular/core";
import {Router} from "@angular/router";
import 'rxjs/add/operator/toPromise';
import 'rxjs/add/operator/map';
    constructor(private http: Http,
                    private router: Router,
                    private alertService: AlertService) {
      }

        sendMesage(inspection: Inspection) {
             this.alertService.confirm("Threshold reached for Rank " + inspection.rankName + ". Do you want send message ?",function(){
                alert("1...");
                const url = '/api/inspection/sendmessage/';
                 this.http
                    .post(url, JSON.stringify(inspection), {headers: this.headers})
                    .toPromise()
                    .then(response => {
                        let data = response.json();
                        return response.json() as Inspection;
                })
                .catch(error => {
                    alert("error");
                });
            },function(){
              alert("No clicked"); 
            })
        }

app.module.ts

import {BrowserModule} from '@angular/platform-browser';
import {NgModule} from '@angular/core';
import {FormsModule} from '@angular/forms';
import {HttpModule} from '@angular/http';
import { HttpClientModule } from '@angular/common/http';

import {AppRoutingModule } from './app-routing.module';

import {InspectionService} from './inspection/inspection.service';
import {AlertService} from './alert/alert.service';

import {AppComponent} from './app.component';
import {AlertComponent} from './alert/alert.component';
import {NavigationComponent} from './navigation/navigation.component';
import { InspectionComponent } from './inspection/inspection.component';

@NgModule({
    imports: [
        BrowserModule,
        HttpClientModule,
        FormsModule,
        HttpModule,
        AppRoutingModule
    ],
    providers: [
        AlertService,
        InspectionService,
    ],
    declarations: [
        AppComponent,
        AlertComponent,
        NavigationComponent,
        InspectionComponent,
    ],
    bootstrap: [AppComponent]
})
export class AppModule {
}

alert.service.ts

import {Injectable} from '@angular/core';
import {Router, NavigationStart} from '@angular/router';
import {Observable} from 'rxjs';
import {Subject} from 'rxjs/Subject';

import { AlertComponent } from './alert.component';

@Injectable()
export class AlertService {
  private subject = new Subject<any>();
  private keepAfterNavigationChange = false;

  constructor(private router: Router) {
    // clear alert message on route change
    router.events.subscribe(event => {
      if (event instanceof NavigationStart) {
        if (this.keepAfterNavigationChange) {
          // only keep for a single location change
          this.keepAfterNavigationChange = false;
        } else {
          // clear alert
          this.subject.next();
        }
      }
    });
  }

  success(message: string, keepAfterNavigationChange = false) {
    this.keepAfterNavigationChange = keepAfterNavigationChange;
    this.subject.next({type: 'success', text: message});
  }

  error(message: string, keepAfterNavigationChange = false) {
    this.keepAfterNavigationChange = keepAfterNavigationChange;
    this.subject.next({type: 'error', text: message});
  }

  getMessage(): Observable<any> {
    return this.subject.asObservable();
  }

  confirm(message: string,siFn:()=>void,noFn:()=>void){
    this.setConfirmation(message,siFn,noFn);
  }

  setConfirmation(message: string,siFn:()=>void,noFn:()=>void) {
        let that = this;
        this.subject.next({ type: "confirm",
                    text: message,
                    siFn:
                    function(){
                        that.subject.next(); //this will close the modal
                        siFn();
                    },
                    noFn:function(){
                        that.subject.next();
                        noFn();
                    }
        });

  }
}
SK.
  • 1,390
  • 2
  • 28
  • 59
  • Please, post your AlertComponent.html (line 25) too, as indicated by the console. – Maicon Heck Apr 17 '18 at 16:16
  • In your module are you importing `HttpClientModule` or `HttpModule`? – Alexander Staroselsky Apr 17 '18 at 16:17
  • the entire code (actually almost) is here: https://stackoverflow.com/questions/49868519/angular-4-cant-resolve-all-parameters-for-alertcomponent?noredirect=1#comment86753574_49868519 – SK. Apr 17 '18 at 16:19
  • 1
    Possible duplicate of [How to access the correct \`this\` inside a callback?](https://stackoverflow.com/questions/20279484/how-to-access-the-correct-this-inside-a-callback) – ConnorsFan Apr 17 '18 at 16:19
  • @AlexanderStaroselsky: Updated my code. Added dimports – SK. Apr 17 '18 at 16:21
  • Please show how you are importing the module in your `@NgModule({})`. You are importing both Angular 2 and Angular 4+ Http modules in this component, it's unclear which version's Http you should be using. The import in the `NgModule` will help clarify that. – Alexander Staroselsky Apr 17 '18 at 16:22
  • @AlexanderStaroselsky: In app.module.ts it is like this: import {NgModule} from '@angular/core'; – SK. Apr 17 '18 at 16:23
  • Update your question to show the module. – Alexander Staroselsky Apr 17 '18 at 16:24
  • I did not downvote anything but the question title seems to indicate that `this` is undefined. That happens when callbacks are defined with `function() { ... }` instead of `() => { ... }`. See [this post](https://stackoverflow.com/questions/20279484/how-to-access-the-correct-this-inside-a-callback) for more details. – ConnorsFan Apr 17 '18 at 16:31
  • @ConnorsFan: Yes, I am reading that now. Thank you! – SK. Apr 17 '18 at 16:33
  • Regardless of the downvote, I'd recommend to NOT import both `HttpModule` and `HttpClientModule`. I'd stick with just `HttpClientModule` especially as you are in territory of Angular 4+. Thanks! – Alexander Staroselsky Apr 17 '18 at 16:33
  • Change `function() {}` in your `alertService.confirm` to `() => {}`. `this` in `this.http` inside of `function() {}` is the scope of the callback itself where `Http` is undefined, not the instance of the Component. Changing to `() => {}` ensures `this` takes on the instance of the Component => you will have access to the dependencies injected in the component's constructor – Chau Tran Apr 17 '18 at 17:26
  • @ChauTran: Honestly I am not an expert in this type of function calling. I am not getting how I can use ()=> as I have to pass total 3 paramaeters to confir() function. Would you mind to provide the code. I believe I have posted all my code. – SK. Apr 17 '18 at 19:10
  • What's your AlertService look like? – Chau Tran Apr 17 '18 at 19:11
  • added alert.service.ts in the question – SK. Apr 17 '18 at 19:13
  • just change `function () {}` to `() => {}` – Chau Tran Apr 17 '18 at 19:21
  • where ? in alert.service.ts ? is it like this? confirm(message: string,siFn:()=>void,noFn:()=>void) => { this.setConfirmation(message,siFn,noFn); } – SK. Apr 17 '18 at 19:48
  • @SK checkout my answer as you commented on https://stackoverflow.com/questions/41684114/angular-2-easy-way-to-make-a-confirmation-dialog/46463619?noredirect=1#comment86781771_46463619 – Nasiruddin Saiyed Apr 18 '18 at 06:16
  • While changing `function () {}` to `() => {}` might fix the issue it is, IMHO, misusing a side effect of `() => {}` instead of addressing the problem. It's not fixing the issue it's working around it, which is not the same thing and a terrible solution, IMHO – Nope Apr 18 '18 at 08:29

1 Answers1

6

When using javascript callback function declare

var that = this;

then use that.http as your this.http as below in your

inspection.service.ts

sendMesage(inspection: Inspection) {
         var that = this;
         this.alertService.confirm("Threshold reached for Rank " + inspection.rankName + ". Do you want send message ?",function(){
            alert("1...");
            const url = '/api/inspection/sendmessage/';
             that.http
                .post(url, JSON.stringify(inspection), {headers: that.headers})
                .toPromise()
                .then(response => {
                    let data = response.json();
                    return response.json() as Inspection;
            })
            .catch(error => {
                alert("error");
            });
        },function(){
          alert("No clicked"); 
        })
    }
Nasiruddin Saiyed
  • 1,438
  • 1
  • 13
  • 31