Tips for monitoring the loading of data in TypeScript with observers?

One of the methods in my class is responsible for fetching information from the server:

public getClassesAndSubjects(school: number, whenDate: string) {
    this.classService.GetClassesAndSubjects(school, whenDate).subscribe(data => {
      if (!data.hasOwnProperty('errors')) {
        this.classesSubjects = data;

      }
    }, error => {
      console.log("ERROR loading GetClassesAndSubjects: " + error);
    });
  }

When successful, it populates the object: this.class Subjects.

Another method is used to return this data:

public getClasses() {
    return this.classesSubjects;
  }

Therefore, I consistently utilize it like this:

let a = new ClassObj();
a.getClassesAndSubjects(1,'2018-01-01');
a.getClasses();

However, when I call a.getClasses();, an empty object is returned because the previous method has not received a response from the server.

Answer №1

Quick tip:

To solve the issue, ensure that getClassesAndSubjects returns an Observable. Simply subscribe to getClassesAndSubjects() whenever you need access to the data stored in classesSubjects.

While this approach may work syntactically, it might not always be the most optimal solution. The best choice depends on your specific requirements.

In-depth explanation:

The root of the problem lies in asynchronous code execution.

In JavaScript/TypeScript, there are various methods to handle asynchronous operations depending on your use case:

I recommend delving into tutorials and experimenting with these approaches before altering your code. Understanding these fundamental concepts beforehand can prevent future debugging woes and enhance your coding proficiency.

Answer №2

It is recommended to modify the getClassesAndSubjects function in order to make it return an Observable instead of using subscribe. This change will make the function composable.

getClassesAndSubjects(school: number, whenDate: string) {
  return this.classService.getClassesAndSubjects(school, whenDate)
    .map(data => {
      if ('errors' in data) { // type guard
        throw Error(data.errors);
      }
      return data;
    });
}

const c = new ClassObj();

c.getClassesAndSubjects(1,'2018-01-01').subscribe(classesAndSubjects => {
  this.classesAndSubjects = classesAndSubjects;
}, handleError);


// It was determined that the method <code>getClasses was unnecessary and confusing due to its naming in relation to getClassesAndSubjects.

Addendum:

async/await provides a more elegant solution for asynchronous programming compared to callbacks. Here's how it can be implemented with async/await over standard Promises.

import 'rxjs/add/operator/toPromise';
// ...

async getClassesAndSubjects(school: number, whenDate: string) {
  const data = await this.classService.getClassesAndSubjects(school, whenDate)
    .toPromise();
  if ('errors' in data) { // type guard
    throw Error(data.errors);
  }
  return data;
}

// ...

const c = new ClassObj();

try {
  this.classesAndSubjects = await this.getClassesAndSubjects(1,'2018-01-01');
}
catch (e) {
  handleError(e);
}

The benefits of using async/await include straightforward syntax, linear control flow, and simplified error handling. By utilizing this approach, we eliminate the need for deciding between subscribe and return, making the code more cohesive and easier to manage.

Answer №3

The method getClassesAndSubjects initiates an asynchronous process, meaning that when you call getClasses, the operation is still ongoing. It is crucial to return an observable or a promise from getClassesAndSubjects:

public getClassesAndSubjects(school: number, whenData: string): Observable<your-type> {
    const observable = this.classService.GetClassesAndSubjects(school, whenDate);
    observable.subscribe(data => {
      if (!data.hasOwnProperty('errors')) {
        this.classesSubjects = data;

      }
    }, error => {
      console.log("ERROR loading GetClassesAndSubjects: " + error);
    });

    return observable;
}

Now:

a.getClassesAndSubjects(1,'2018-01-01').subscribe(value => {
     a.getClasses();
});

If a function involves asynchronous tasks, any subsequent actions relying on the outcomes of said operations must be patient and wait for them to complete.

You may also opt for using async/await. Here, the asynchronous function needs to return a Promise:

public async getClassesAndSubjects(school: number, whenData: string): Promise<your-type> {
    const observable = this.classService.GetClassesAndSubjects(school, whenDate);
    observable.subscribe(data => {
      if (!data.hasOwnProperty('errors')) {
        this.classesSubjects = data;

      }
    }, error => {
      console.log("ERROR loading GetClassesAndSubjects: " + error);
    });

    return observable.toPromise();
}

Then, wherever it's needed:

async function whatever() {
    // ...
    await a.getClasseandSubjects(1, '2018-01-01');
    a.getClasses();
}

By employing this approach, the execution of the function whatever pauses until the promise derived from a.getClassesAndSubjects either resolves or rejects, permitting the availability of data when executing a.getClasses. Although the function appears 'suspended,' the application remains operational as the async function is internally segmented and processed within a Promise.then structure by the compiler, delivering a refined solution.

It's important to note that any function leveraging await should be marked with async.

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

Issue with MongoDB $push within an Array of Arrays: The shorthand property 'elements' does not have a value available in scope

I am encountering an issue while trying to insert data into Elements in MongoDB using TypeScript. Any suggestions on how to resolve this problem? Attempt 1 Error: I am receiving an error message stating "No value exists in scope for the shorthand property ...

Bringing @angular/code into a directory that is not within an Angular project

Currently, I have an Angular 2 project folder with a separate service folder named "auth.service.ts" located outside of it. Within this service file, I am importing `Injectable` from `@angular/core`. However, due to the service being located outside of t ...

Can TypeScript support promise chaining in a functional way?

It appears that in the realm of JavaScript, one has the capability to execute: function extendPromise(promise) { return promise.then(new Promise(() => {})); } However, when incorporating types into the mix, such as function extendTypeScriptPromis ...

Angular 7 TypeScript code not updating value

UPDATE: I'm having trouble with my code not updating the selected value with the new one entered in the input field "newVb". The error message says 'this.newVarde' is undefined when it reaches the line 'this.selectedVarde = this.newVard ...

Stop Node Modules from Referencing Global Location

Recently, I ran into an issue after updating my project from Git. The problem arose when trying to use ngx-material-timepicker in conjunction with the luxon library. (It's important to note that ngx-material-timepicker isn't a new addition to th ...

Can I combine tuple types in Typescript?

type A1 = ['x','y','z'] type A2 = ['u','v','w'] type AN = [.., .., ..] type C = Combine<A1,A2,...,AN> //or Combine<[A1,A2,...,AN]> //resulting in ['x','y','z& ...

What is the best way to identify property errors in a React/Typescript project using ESLint?

I'm currently in the process of transitioning a Typescript project created with create-react-app to the latest version. As part of this update, I am moving from tslint to eslint which has posed some challenges. The main issue I'm facing is gettin ...

What data structure is used to store HTML elements in TypeScript?

Currently, I am dealing with a typescript variable that holds the outcome of a query on the DOM: let games = document.getElementsByTagname("game"); My uncertainty lies in identifying the appropriate type for the resulting array. Should I expect an array ...

I am looking to enhance my array of objects by implementing a filter. It is important that the filter does not allow for duplicate checkboxes with the

My website : On the left-hand side of my webpage, there is a set of checkboxes with some repeated names that I don't want. For example, "Rice" is repeated twice but I only want it to display once. When checking the Rice checkbox, it should show all c ...

Display issues with deeply nested components

I'm facing an issue with displaying the third nested component. Expected: Hello App Component Hello Nest-A Component Hello Nest-1 Component Hello Test-Z Component Actual: Hello App Component Hello Nest-A Component Hello Nest-1 Component Why ...

How to include subdirectories in a TypeScript npm module

I am in the process of developing a package for npm and I would like it to be imported in the following manner: import myPackage from 'my-package'; import { subFunction1, subFunction2 } from 'my-package/subfunctions'; Upon trying to u ...

What is the process for creating a unique Vee-Validate rule in TypeScript?

I am in the process of developing a unique VeeValidate rule for my VueJS component written in TypeScript. This rule is designed to validate two fields simultaneously, following the guidelines outlined in VeeValidate - Cross Field Validation. Here is a snip ...

Is it considered poor practice to specify the type explicitly when it can be easily inferred by Tslint?

When using VSCode, the linter tslint may raise an issue when the following code is added with a specific type: serverId: number = 10; This will trigger the following message: [tslint] Type number trivially inferred from a number literal, remove type ...

"Error: The specified object does not have the capability to support the property or method 'includes'." -[object Error]

Recently, I developed a method that utilizes both indexOf() and includes(). However, I encountered an error message stating "Object doesn't support property or method 'includes'". I have attempted to run the method on both Internet Explorer ...

How to Add a Rule to an Existing Application Load Balancer Listener using AWS CDK

When I inherited a project, I discovered an application load balancer with a HTTPS Listener that was set up before I began using CDK. This listener currently has 13 rules in place that route requests based on hostname to different fargate instances, with ...

Validation of passwords containing special characters in Angular2

I am working on setting up password validation requirements to ensure the field contains: Both uppercase letters, lowercase letters, numbers and special characters This is my current progress: passwordValueValidator(control) { if (control.value != u ...

The name 'Firebase' is not recognized by Typescript

Encountering typescript errors while building a project that incorporates angularfire2 and firebase. Here are the packages: "angularfire2": "^2.0.0-beta.0", "firebase": "^2.4.2", Listed below are the errors: [10:58:34] Finished 'build.html_css&apos ...

What is the reason for Jest attempting to resolve all components in my index.ts file?

Having a bit of trouble while using Jest (with Enzyme) to test my Typescript-React project due to an issue with an alias module. The module is being found correctly, but I believe the problem may lie in the structure of one of my files. In my jest.config ...

Returns false: CanActivate Observable detects a delay during service validation

Issue with Route Guard in Angular Application: I encountered an issue with my route guard in my Angular application. The problem arises when the guard is active and runs a check by calling a service to retrieve a value. This value is then mapped to true or ...

Is it possible to compile using Angular sources while in Ivy's partial compilation mode?

Error: NG3001 Unsupported private class ObjectsComponent. The class is visible to consumers via MasterLibraryLibModule -> ObjectsComponent, but is not exported from the top-level library entrypoint. 11 export class ObjectsComponent implements OnInit { ...