What is the best way to execute a function on the output of *ngFor directive in Angular 2?

Imagine having a list of all the users within your system:

  allUsers = {
    a: {name:'Adam',email:'<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="39585d5854794d5c4a4d5a56175a56...
    f: {name:'fred',email:'<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="e187938485a195849295828ecf82...

  }

Now, envision having another list that contains the users involved in a specific project:

usersList = ['a','b','d','f'];

To simplify the process, you can utilize a function that takes a user ID and retrieves additional user details:

  getUser(userId){
    console.log('Getting User with Id:', userId);
    if(allUsers[userId]) return allUsers[userId];
  }

However, when utilizing *ngFor to iterate through the users in the list within the template, there seems to be an issue retrieving the complete set of user details:

<tr *ngFor="#userId in usersList" #user="getUser(userId)">
  <td>{{user.name}}</td>
</tr>

This method doesn't seem optimal as it calls the getUser function repeatedly. Is there a simpler way to access the userId variable and define it as a local variable?

Feel free to check out this plunker for my current experimentations

Answer №1

While the ngFor template directive allows for creating a variable, it is limited to values such as index, even, odd, and last.

In cases where you need to manipulate data, using a custom pipe can be helpful. By passing usersList and allUsers to a custom @Pipe called getUsers, you can create a filter similar to Angular1.

Example Usage:

<tr *ngFor="let user of usersList | getUsers: allUsers">
  <td>
    {{user.name}}
  </td>
  <td>
    {{user.email}}
  </td>
  <td>
    {{user.level}}
  </td>
  <td>
    {{user.group}}
  </td>
</tr>

Code Implementation:

@Pipe({
  name: 'getUsers',
  pure: false
})
export class GetUserPipe implements PipeTransform {
  constructor(){
    this.test = 'Test';
  }
  transform(array:Array<string>, object: any) : any {
    // Using a for..in loop
    let output = [];
    for (var num in array)
    {
      // Accessing object properties with array elements
      output.push(object[0][array[num]]);
    }
    console.log(output)
    return output;
  }
}

View Demo on Plunkr

Answer №2

I enjoy using

<td>{{getMember(memberId).name}}</td>

That method works well for me. It's much simpler than having to create a pipe or filter.

Even if there was an option to use a local template variable, I think it would still be re-evaluated for each item in the list during every change detection cycle, similar to the HTML code mentioned above.

For more information, check out ng2: How to create variable in ngFor loop. One suggestion is to create a child component and pass getMember(memberId) as an input property for that component.

Answer №3

Here is an example of how you can structure your markup:

<tr *ngFor="theUser in getTheUsers(usersList)" >
   <td>{{theUser.name}}</td>
</tr>

The getTheUsers() function should look something like this:

getTheUsers(usersList:string[]){
  return usersList.map(user=> this.allUsers[user]); 
}

Answer №4

Take a look at another method I developed that utilizes ng-container, *ngIf with let. It eliminates the need for a subcomponent and instead creates an object through the *ngIf expression (which is always truthy, resulting in the content being rendered consistently). The computed value is stored in a property of this object, which is then assigned to a local variable using the *ngIf syntax.

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

What is the best way to ensure that multiple queries are returned in the correct sequence?

In the interface below, there is a search input box along with data displayed. As you type in the search input, the data below filters accordingly. Each letter typed triggers a request to retrieve the relevant data. For instance, if you type "folder," the ...

Trouble with using the date pipe in Angular specifically for the KHMER language

<span>{{ value | date: 'E, dd/MM/yyyy':undefined:languageCode }}</span> I am facing a challenge where I need to identify the specific locale code for the KHMER language used in Cambodia. Despite trying various cod ...

Upon receiving data from the Api, the data cannot be assigned to the appropriate datatype within the Angular Object

I am encountering an issue with the normal input fields on my page: https://i.stack.imgur.com/qigTr.png Whenever I click on the "+" button, it triggers an action which in turn calls a service class with simple JSON data. My intention is to set selectionC ...

Can you explain the concept of static in Typescript?

Exploring the distinctions between the static and instance sides of classes is addressed in the Typescript documentation on this page. The static and instance sides of classes: understanding the difference In object-oriented programming languages like ...

utilize Angular's interface-calling capabilities

In the backend, I have an interface structured like this: export interface DailyGoal extends Base { date: Date; percentage: number; } Now, I am attempting to reference that in my component.ts file import { DailyGoal } from '../../interfaces' ...

Issue with Promise not resolving in Node when using Edge

As I explore the best way to utilize my C# dlls with Edgejs for Node, I encountered a situation where one proxy function in Node appears like this (a class method in Typescript): readSettings(args: ReadSettingsParams) : Promise<response> { let $ ...

No overload error encountered with TypeScript function call

I am working on an async function that communicates with the backend and I need it to handle axios error messages. My goal is to display these messages in a form. export async function register( prevState: string | undefined, formData: FormData ) { t ...

Developing Angular PWAs with a focus on microfrontends

I have set up multiple microfrontends using an "app-shell" type of application for the domain root, with each microfrontend on the first path element. Each app is constructed as a standalone angular application utilizing shared libraries to reuse common co ...

Unleashing the full potential of Azure DevOps custom Tasks in VS Code and TypeScript: A guide to configuring input variables

Scenario: I have developed a custom build task for Azure DevOps. This task requires an input parameter, param1 The task is created using VS Code (v1.30.1) and TypeScript (tsc --version state: v3.2.2) Issue During debugging of the task, I am unable to pr ...

Problem with moving functions from one file to another file via export and import

I currently have the following file structure: ---utilities -----index.ts -----tools.ts allfunctions.ts Within the tools.ts file, I have defined several functions that I export using export const. One of them is the helloWorld function: export const hel ...

Filtering an observable using criteria from another source

I'm currently facing a challenge where I need to map observables by filtering them based on events emitted from other observables. The main question at hand is: Is there a way to pass a property of an event to a filter function? In the following exa ...

Variables within Angular2 services are resetting when the route changes

I have been utilizing a service to monitor the status of my model. I have several components that need to access the variables and properties of this service. The issue arises when the first component initializes, sets the model, but upon trying to access ...

Discovering Virtual Directories within IIS using port 4200 in Angular

Having configured an IIS virtual directory with various photos, I am facing difficulty accessing it from my Angular App. A 404 NOT FOUND error is displayed when trying to access the directory. On the other hand, I can successfully access the folder using a ...

How can I change an icon and switch themes using onClick in react js?

I have successfully implemented an icon click feature to change the colorscheme of my website (in line 21 and changeTheme). However, I also want the icon to toggle between FaRegMoon and FaRegSun when clicked (switching from FaRegMoon to FaRegSun and vice v ...

Angular 7 router navigate encountering a matching issue

I created a router module with the following configuration: RouterModule.forRoot([ {path: 'general', component: MapComponent}, {path: 'general/:id', component: MapComponent}, {path: '', component: LoginComponent} ]) Sub ...

Tips for declaring a non-reactive instance property in Vue.js with TypeScript

I am currently in the process of transitioning my Vue.js components to TypeScript. In accordance with the recommendations provided in the documentation, I attempted to utilize Vue.extend() for my component implementation. The code snippet for my component ...

Angular 4's OrderBy Directive for Sorting Results

I've been working on implementing a sorting pipe based on the code provided in this resource: The issue I'm facing revolves around handling undefined values within my data. The sorting pipe functions correctly when there are no undefined values ...

Generate a placeholder payload for CdkDragDrop event

I am looking to perform unit testing on a method in angular using jest: drop(event: CdkDragDrop<string[]>) { if (event.previousContainer === event.container) { moveItemInArray(event.container.data, event.previousIndex, event.currentIndex) ...

An error occurred with the datepicker: Unable to connect to 'bsValue' as it is not recognized as a property of 'input'

Despite importing DatepickerModule.forRoot() in my Angular unit test, I am encountering the following error: Error: Template parse errors: Can't bind to 'bsConfig' since it isn't a known property of 'input'. (" ...

Why won't my fetch API function properly in my Next.js project?

import { GetServerSideProps } from 'next'; type Product = { //Product variables id: number; title: string; price: number; thumbnail: string; }; interface ProductsProps { products: Product[]; } export default function Products({ produ ...