Understanding Angular Pipes

Question 1: What are Angular Pipes and what is their purpose?

Answer: Angular Pipes are a feature that allows you to transform and format data in your templates without changing the underlying data. They are used to:

  • Transform data display format
  • Perform data conversions
  • Apply filters
  • Format dates, numbers, and text
  • Create reusable data transformations

Question 2: What are the built-in pipes in Angular and how do you use them?

Answer: Angular provides several built-in pipes. Here are the most commonly used ones with examples:

@Component({
  selector: 'app-pipe-demo',
  template: `
    <!-- Date Pipe -->
    <p>Date: {{ today | date: 'fullDate' }}</p>
    <p>Custom Date: {{ today | date: 'dd/MM/yyyy HH:mm' }}</p>

    <!-- Currency Pipe -->
    <p>Price: {{ price | currency: 'USD' }}</p>
    <p>Custom Currency: {{ price | currency: 'EUR':'code' }}</p>

    <!-- Decimal Pipe -->
    <p>Number: {{ number | number: '1.2-2' }}</p>

    <!-- Uppercase/Lowercase Pipes -->
    <p>{{ text | uppercase }}</p>
    <p>{{ text | lowercase }}</p>

    <!-- JSON Pipe -->
    <pre>{{ object | json }}</pre>

    <!-- Async Pipe -->
    <div>{{ observableData$ | async }}</div>

    <!-- Slice Pipe -->
    <p>{{ array | slice:1:3 }}</p>

    <!-- Percent Pipe -->
    <p>{{ 0.756 | percent:'1.1-2' }}</p>
  `
})
export class PipeDemoComponent {
  today = new Date();
  price = 42.99;
  number = 3.14159;
  text = 'Angular Pipes';
  object = { name: 'John', age: 30 };
  array = [1, 2, 3, 4, 5];
  observableData$ = of('Async Data').pipe(delay(1000));
}

Question 3: How do you create a custom pipe in Angular?

Answer: Here’s how to create and use a custom pipe:

// filter-list.pipe.ts
import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
  name: 'filterList',
  // Make it pure: false if you want it to update on all changes
  pure: true,
  // Available in standalone components
  standalone: true
})
export class FilterListPipe implements PipeTransform {
  transform(items: any[], searchText: string): any[] {
    if (!items || !searchText) {
      return items;
    }

    searchText = searchText.toLowerCase();
    
    return items.filter(item => 
      item.name.toLowerCase().includes(searchText)
    );
  }
}

// usage in component
@Component({
  selector: 'app-list',
  template: `
    <input [(ngModel)]="searchText" placeholder="Search...">
    <ul>
      @for (item of items | filterList:searchText; track item.id) {
        <li>{{ item.name }}</li>
      }
    </ul>
  `,
  // Import in standalone component
  imports: [FilterListPipe]
})
export class ListComponent {
  items = [
    { id: 1, name: 'Angular' },
    { id: 2, name: 'React' },
    { id: 3, name: 'Vue' }
  ];
  searchText = '';
}

Question 4: What is the difference between pure and impure pipes?

Answer: Pure and impure pipes differ in how they handle change detection:

// Pure Pipe (Default)
@Pipe({
  name: 'pure',
  pure: true // default
})
export class PurePipe implements PipeTransform {
  transform(value: any) {
    // Only executes when input value reference changes
    return value;
  }
}

// Impure Pipe
@Pipe({
  name: 'impure',
  pure: false
})
export class ImpurePipe implements PipeTransform {
  transform(value: any) {
    // Executes on every change detection cycle
    return value;
  }
}

Interview Tips 💡

  1. Performance Considerations

    • Pure pipes are more performant as they only run on reference changes
    • Use pure pipes by default unless you specifically need impure behavior
    • Be cautious with impure pipes as they can impact performance
  2. Built-in Pipes Best Practices

    // Chaining pipes
    {{ date | date:'shortDate' | uppercase }}
    
    // Using pipe parameters
    {{ number | number:'1.2-2' }}
    
    // Async pipe for automatic subscription handling
    {{ observable$ | async }}
  3. Common Use Cases

    • Date formatting
    • Number and currency formatting
    • Text transformation
    • Filtering lists
    • Handling async data
  4. Advanced Pipe Features

    // Parameterized pipe
    @Pipe({ name: 'exponential' })
    export class ExponentialPipe implements PipeTransform {
      transform(value: number, exponent = 1): number {
        return Math.pow(value, exponent);
      }
    }
    // Usage: {{ 2 | exponential:3 }} outputs 8
  5. Error Handling in Pipes

    @Pipe({ name: 'safe' })
    export class SafePipe implements PipeTransform {
      transform(value: any): any {
        try {
          // Transform logic
          return processedValue;
        } catch (error) {
          console.error('Pipe error:', error);
          return value; // Return original value on error
        }
      }
    }
  6. Testing Pipes

    describe('FilterListPipe', () => {
      const pipe = new FilterListPipe();
      
      it('should filter list by search text', () => {
        const items = [
          { name: 'Angular' },
          { name: 'React' }
        ];
        
        const filtered = pipe.transform(items, 'ang');
        expect(filtered.length).toBe(1);
        expect(filtered[0].name).toBe('Angular');
      });
    });

Remember: In interviews, focus on:

  • Understanding when to use pipes vs methods
  • Performance implications of pure vs impure pipes
  • Best practices for creating custom pipes
  • Knowledge of built-in pipes and their parameters
  • Async pipe benefits for memory management
  • Testing strategies for pipes
  • Error handling and edge cases

Test Your Knowledge

Take a quick quiz to test your understanding of this topic.

Test Your Angular Knowledge

Ready to put your skills to the test? Take our interactive Angular quiz and get instant feedback on your answers.