What is the best way to reach the scope of a constructor that wraps an Angular2 observable?

Below is the code snippet in question:

import { Injectable }     from '@angular/core';
import { Http, Response, Headers, RequestOptions, URLSearchParams } from '@angular/http';
import { Observable } from "rxjs/Observable";
import { Document } from "../api-objects/document";
import { ErrorService } from "../error/error.service";

@Injectable()
export class QuestionsService {
  private questionsUrl = '/api/questions';  // URL to web API
  headers= new Headers({
    'Content-Type': 'application/vnd.api+json',
    'Accept': 'application/vnd.api+json' });
  public newQnsCount: Observable<number>;
  private time:Date;

  constructor (
    private http: Http,
    private errorService:ErrorService
  ) {
      var self = this;
      this.newQnsCount = new Observable(
        (observable) => {
          //configure parameters
          let params = new URLSearchParams();
          //add filter options to query
          params.set("filters", JSON.stringify([{
              name: "date",
              op: "gt",
              val: self.getTime().toISOString()
            }]));
          //add functions[query] to query
          params.set("functions", JSON.stringify([{
              name: "count",
              field: "id"
            }]));
          //to prevent returning from cache
          params.set("rand", Math.random()+"");
          //create options
          var options = new RequestOptions({
            headers:self.headers,
            search: params
          });
          //create the http observable
          var resp = self.http.get(self.questionsUrl, options)
            .map(self.extractData)
            .catch(self.handleError);
          //create an interval that monitors the number of new questions
          let interval = setInterval(() => {
            resp.subscribe(
              //return the count of new questions since the last get time
              data => {observable.next(data[0])},
              //handle errors
              (error) => {
                self.errorService.handle401(error);
                observable.onError(error);
              }
            )
          });
          //return the observable's destroyer function
          return () => {clearInterval(interval);}
        }
      );
  }

  getTime():Date{
    return this.time;
  }

  addQuestion(question:Document):Observable<Document>{
    let body = JSON.stringify(question);
    let options = new RequestOptions({headers:this.headers});

    var resp = this.http.post(this.questionsUrl, body, options)
      .map(this.extractData)
      .catch(this.handleError);
    resp.subscribe(()=>{}, error => this.errorService.handle401(error));
    return resp;
  }

  getQuestions():Observable<Document>{
    let params = new URLSearchParams();
    //to prevent returning from cache
    params.set("rand", Math.random()+"");
    //create options
    var options = new RequestOptions({
      headers: this.headers,
      search: params
    });
    this.time = new Date();
    return  this.http.get(this.questionsUrl, options)
      .map(this.extractData)
      .catch(this.handleError);
  }

  private extractData(res: Response):Document {
    let body = res.json();
    return body || { };
  }

  private handleError (error: any):Observable<Document>{
    // In a real world app, we might use a remote logging infrastructure
    // We'd also dig deeper into the error to get a better message
    let errMsg = (error.message) ? error.message :
      error.status ? `${error.status} - ${error.statusText}` : 'Server error';
    return Observable.throw(error.json());
  }
}

I am facing difficulties accessing the scope of the QuestionsService within the observable creation function. The issue appears to relate to the getTime() function as it triggers the following error message:

EXCEPTION: Error: Uncaught (in promise): EXCEPTION: Error in :0:0
ORIGINAL EXCEPTION: TypeError: self.time is undefined
...

I attempted using the self variable to resolve the problem but encountered the same error. Any guidance on resolving this would be highly appreciated.

Answer №1

To maintain the scope of this, it is recommended to use arrow functions like

.map((data) => this.extractData(data))

instead of

.map(this.extractData)

This ensures that the context of this is not lost.

There is no requirement for using self.

Answer №2

Place the declaration let self = this; outside of the constructor function

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

How can you navigate to the left within a component by scrolling?

My Panel component is equipped with an overflow-x: scroll; feature for horizontal scrolling. Given the large amount of data it contains, I am looking for a way to enable horizontal scrolling within the panel. What is the best approach to achieve this? Is ...

Is the variable not being initialized outside of the function?

I'm really struggling with this async issue. I can't seem to get it to work because the summonerData array is not being set. I have a feeling it has something to do with async, but I'm not sure how to troubleshoot it. var summonerName = req ...

Resolving negative margin issues in Material UI components through detailed textual guidance

Having an issue with the paragraphs in material-ui components. The problem arises when the text exceeds the dimensions of the component, causing it to spill over as shown in the image below. <Grid container wrap="nowrap" css={[borde,{ ...

What is the most effective way to incorporate JavaScript into a PHP function?

Hey there, I'm currently working on a PHP function that returns HTML/JS content. However, I feel like the approach I'm taking is inefficient and not the best way to do it. Do you have any suggestions for a better method? Here is a simplified ver ...

The attribute "JSON" is not found within the Object type

When attempting to parse a JSON configuration file using the code below: this.http.get('assets/env/env.json').pipe(map( res => res.json())).pipe(catchError((error: any): any => { console.log('Configuration file "env.json" c ...

Guide to utilizing the XHR API in a Node.js environment

I am writing to elaborate on a previous discussion I had found here. Imagine that I have some javascript code that functions smoothly on the client side (within a browser). This particular code involves numerous XHR calls using the browser API. My curren ...

Tips for making objects rotate vertically on their axis and orbit around another object in three.js

Thank you in advance for all the support as I've been asking a lot of questions about my project. My project involves creating a simulation where a planet earth and moon rotate around a sun. (They're not exactly rotating around the sun, but more ...

Extracting a particular field from a Meteor collection document in a JavaScript file and removing any HTML tags

In my Meteor Collections, I have a group of Projects each with a title and description. My goal is to extract the rich text content from the description field using a Template helper. I attempted the following code snippet to retrieve the description for ...

script code to limit selection of dates within a predefined range

I'm seeking assistance to limit my customers from selecting a date beyond 10 days in advance. Although I previously had a code that functioned properly when there were more than 10 days left in the current month, it is now ineffective. This is becaus ...

As the user types input in real time, automatically adjust the form's value before submission

I'm looking for assistance in dynamically updating the value of a form submit button as the user types into an input field. <form> <input type="text" name="number" id="number" value = 0 /> <input type="submit" id="submit"> ...

Can you please provide the Jquery alternative to this?

Can you provide a sleek jQuery solution for this problem? $('A').append(str); ...

Customize the text that appears when there are no options available in an Autocomplete component using React

Recently, I came across this Autocomplete example from MaterialUI that caught my attention. https://codesandbox.io/s/81qc1 One thing that got me thinking was how to show a "No options found" message when there are no search results. ...

What is the best way to transform an array of lists into a neatly organized state?

I recently received a list of breweries from an API call and I am trying to format it into my React state container. Here is what I have so far: state = { breweries: [ {name: Foo, long: 45, lat: -39.239}, ...

Exploring the implementation of useMediaQuery within a class component

Utilizing functions as components allows you to harness the power of the useMediaQuery hook from material-ui. However, there seems to be a lack of clear guidance on how to incorporate this hook within a class-based component. After conducting some researc ...

The issue with Visual Studio not properly supporting Angular development

After cloning my Angular app from one machine to another, I encountered an issue when trying to run it with debugging in Visual Studio. Instead of opening a separate command line and executing ng serve or npm start, it simply launched a web browser page on ...

Practical steps for programmatically adding or removing md-disable-backdrop in md-sidenav

Can the md-disable-backdrop attribute be removed from HTML? The issue arises when opening the side navigation as the md-sidenav does not have the md-disable-backdrop attribute. After making a selection from the form displayed in the side navigation, I now ...

The 'X' property is not found in the DefaultRootState type, even though it is declared in the corresponding Interface

Below is the Interface being used in conjunction with mapStateToProps: export interface IStore { cache?: any; dataManager?: IUR; userPrefs: IUP; IModal?: IfingerprintModal; } export interface IModal { cbCancel: IFModalFn | null; cbTryAgain?: I ...

bulk upload with the ability to remove files

I'm in the process of creating a multiple file upload with delete option, similar to the design shown in this image: https://i.sstatic.net/RomOR.jpg I have been following an example on this JS Fiddle demo. My goal is to eliminate the button with the ...

Tips for understanding nested JSON or array data structure?

My data is stored in a constant called translations and it looks like this: { "item-0": { "_quote-translation": "translation Data", "_quote-translation-language": "English", "_quote-trans ...

Angular alert: The configuration object used to initialize Webpack does not conform to the API schema

Recently encountered an error with angular 7 that started popping up today. Unsure of what's causing it. Attempted to update, remove, and reinstall all packages but still unable to resolve the issue. Error: Invalid configuration object. Webpack ini ...