Using Typescript: How to pass a function as an argument in another function

In my angular application, I am working on the following setup:

this.myServiceOne.getDataOne().subscribe((res => {this.variableOne= res}));
this.myServiceTwo.getDataTwo().subscribe((res => {this.variableTwo= res}));
this.myServiceThree.getDataThree().subscribe((res => {this.variableThree= res}));
this.myServiceFour.getDataFour().subscribe((res => {this.variableFour= res}));

My goal is to create a more generic function like this:

  loadData(myVariable, myserviceMethod){
    serviceMethod().subscribe((res => {pefVar = res}));
  }

and update my code as follows:

this.loadData(this.variableOne, this.myServiceOne.getDataOne);

Unfortunately, it seems that this part of the code (this.myServiceOne.getDataOne) is causing an issue and not functioning properly.

Any suggestions on how to fix this?

Answer №1

In order to assign the value of a local variable through delegation, you will need to either provide a callback function (similar to how you currently do in your subscribe method) or specify the property name that needs to be updated.

The effort saved by making it generic is minimal unless there is some repeated code, which is not present in your example.

If you truly wish to create a generic function, consider these approaches:

Using a Callback

The object returned from the observable is of a generic type. The callback function takes a single argument of the same type.

loadData<T>(serviceMethod: Observable<T>, action: (value: T) => void) {
  serviceMethod.subscribe((res: T) => action(res));
}

You can invoke this function as follows:

this.loadData(this.myServiceOne.getDataOne(), res => this.variableOne = res);

Using Property Name

TKey must be a named key within AppComponent.

TValue represents the type of the named key and the type of object returned by the observable.

loadData2<TKey extends keyof AppComponent, TValue extends AppComponent[TKey]>(    
  serviceMethod: Observable<TValue>, 
  key: TKey
): void {
  const component: AppComponent = this;
  serviceMethod.subscribe((res: TValue) => {      
    component[key] = res;
  });
}

You can call this function like so:

this.loadData(this.myServiceOne.getDataOne(), 'variableOne');

Using Fully Generic Property Name

T represents the component type.

TKey must be a named key within T.

TValue represents the type of the named key and the type of object returned by the observable.

loadData2<T, TKey extends keyof T, TValue extends T[TKey]>(    
  component: T,
  serviceMethod: Observable<TValue>, 
  key: TKey
): void {
  serviceMethod.subscribe((res: TValue) => {      
    component[key] = res;
  });
}

You can use this function as shown below:

this.loadData(this, this.myServiceOne.getDataOne(), 'variableOne');

Using Promises

You could also convert the observable to a promise and utilize async/await, but this may not be necessary.

DEMO: https://stackblitz.com/edit/angular-btfqng

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

The onChange event seems to be failing to activate during a jQuery / Ajax form submission

Differences in Form Submission Methods The onChange event functions correctly with the traditional Type and Action method in both Firefox and Chrome. <form name="frmname" action="./add_p.php" method="POST"> <div> <select name=" ...

Injecting dynamic variables into JSON objects using JavaScript

I am facing a challenge with populating values dynamically from an array of elements. Below is the primary array that I am working with. list = [{name: 'm1'}, {name: 'm2'},{name: 'm3'},{name: 'm4'},{name: 'm5&ap ...

Firebase and Angular 7 encountered a CORS policy block while trying to access an image from the origin

I am attempting to convert images that are stored in Firebase storage into base64 strings in order to use them in offline mode with my Angular 7/Ionic 4 application! (I am using AngularFire2) However, I encountered an error message stating: Access to i ...

What is the best way to locate an item reference for a specific DOM element?

Imagine a vast DOM structure with approximately 10,000 HTML elements, including 1,000 span tags. None of the span elements have any identifiers and are buried deep within other objects with long, complex Xpath paths that are not user-friendly for selectio ...

How can I retrieve the express Application within a REST API?

After reviewing Massive's documentation and learning that saving the connection object to Express's application settings can help reduce database connection execution time, I encountered a problem. How can one access the Express app variable when ...

What could be the reason for the bootstrap carousel failing to load on Angular 17 SSR?

Using bootstrap, I copied a snippet from the bootstrap page and made some modifications to utilize @for because my image is coming from a service. Below is the code I used: <div class="container"> <div class="carousel"> ...

Manipulating State in React: How to add a property to an object within an array within a component's state

Currently, I am retrieving an array of objects stored in the state, and I am attempting to include a new property to each of these objects. However, I am encountering a problem where even though I can see the new property being added to each object, when ...

Enhancing the functionality of Angular 2's ngModel directive with the utilization of observables

Working with Angular 2's ngModel directive involves variables and functions, such as: <input [ngModel]="myVar" (ngModelChange)="myFunc($event)" /> I am interested in using BehaviorSubjects instead of variables and functions: ...

Error in THREE.js: Unable to access property 'lib' from an undefined source (THREE.ShaderUtils.lib["normal"])

I have been working on the challenges provided in the WebGL introductory book by Oreilly. Encountered a runtime error with the following code snippet. After searching online, it seems like I am the only one facing this issue. Could you please assist me in ...

Is there a way to programmatically fetch files from a MySql / Node.js server?

I've been working on my CRUD app and I'm currently focusing on downloading files from a MySql Nodejs server. Here are the steps I have accomplished so far: I created a function in userContoller.js to query the MySql database for the id=179 (just ...

Challenges with Scaling HTML5 Video onto Canvas

Attempting to extract a frame from an html5 video to generate a thumbnail, but encountering peculiar outcomes when the image is rendered onto canvas. The issue lies in the fact that the canvas displays only a greatly magnified portion of the video! Refer ...

Utilizing Backbone script for fetching data from an external JSON source

I am seeking assistance on how to utilize a Backbone script to display data from a JSON file. Here is the structure of the HTML Page: <!DOCTYPE html> <html> <head> <meta charset="ISO-8859-1"> <title>Insert title here</tit ...

Uncovering the Solution: Digging into a Nested ng-repeat to Access an Array in AngularJS

I am working with a recursive array in JavaScript: [{ type: 'cond', conditionId: 1, conditions: undefined }, { type: 'cond', conditionId: 2, conditions: undefined }, { type: 'group', conditionId: undefined, ...

What is the method for comparing fields within an input type in type graphql with the assistance of class validator decorators?

I am working with the following example input type: @InputType() class ExampleInputType { @Field(() => Number) @IsInt() fromAge: number @Field(() => Number) @IsInt() toAge: number } Can I validate and compare the toAge and fromAge fields in th ...

Creating an effective follow-following system in Node.js

I have built a Node.js application that features a basic follow system, allowing users to receive the latest articles from those they follow. The current implementation involves creating an array called followers, which stores the userIDs of all users fol ...

Jest: A guide on mocking esModule methods

In my code, I have a function that utilizes the library jszip to zip folders and files: // app.ts const runJszip = async (): Promise<void> => { const zip = new Jszip(); zip.folder('folder')?.file('file.txt', 'just som ...

Is it possible to minimize the number of accessors needed for reactive forms?

Currently, I am dealing with a reactive form that consists of 20 different inputs. An example of one input is shown below: <input formControlName="name" matInput> For each input, I find myself needing to write an accessor function like the ...

Display the dropdown selected value within a Laravel Blade template

I am facing an issue with passing the selected value from a drop-down to another Blade file in Laravel. I have tried using Ajax and jQuery, but it doesn't seem to work for me. I want to display the selected value on the content.blade.php page without ...

Refining keys within an array of objects

If I have an array of objects retrieved from a Node Repository like this: data = [ { title: "JavaScript Basics", author: "John Smith", year: 2020 }, { title: "Node.js Essentials", ...

Is using Javascript objects a better alternative to Redux?

I'm in the process of creating my initial application with React and have opted to integrate Redux into it. Since incorporating Redux, it appears that setting a component state to a basic global JavaScript object would be a simpler approach. I unders ...