Angular Examples

Angular integration examples using the Metigan SDK. Learn how to send emails, manage contacts, forms, and audiences in your Angular applications using RxJS Observables.

Installation

terminalTerminal
1
2
3
npm install @metigan/angular
# or
yarn add @metigan/angular

Module Configuration

app.module.tsTypeScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HttpClientModule } from '@angular/common/http';
import { MetiganModule } from '@metigan/angular';

import { AppComponent } from './app.component';

@NgModule({
  declarations: [AppComponent],
  imports: [
    BrowserModule,
    HttpClientModule,
    // Configure Metigan SDK
    MetiganModule.forRoot({
      apiKey: 'your-api-key-here',
      timeout: 30000,
      retryCount: 3
    })
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

Basic Component Usage

email.component.tsTypeScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
import { Component, OnInit } from '@angular/core';
import { MetiganService } from '@metigan/angular';

@Component({
  selector: 'app-email',
  template: `
    <div>
      <button (click)="sendEmail()" [disabled]="loading">
        {{ loading ? 'Sending...' : 'Send Email' }}
      </button>
      <div *ngIf="message" class="success">{{ message }}</div>
      <div *ngIf="error" class="error">{{ error }}</div>
    </div>
  `
})
export class EmailComponent implements OnInit {
  message = '';
  error = '';
  loading = false;

  constructor(private metigan: MetiganService) {}

  ngOnInit() {
    // Initialize if not done via module
    if (!this.metigan.isInitialized()) {
      this.metigan.initialize({
        apiKey: 'your-api-key-here'
      });
    }
  }

  sendEmail() {
    this.loading = true;
    this.message = '';
    this.error = '';

    this.metigan.email.sendEmail({
      from: 'Your Company <noreply@yourcompany.com>',
      recipients: ['customer@email.com'],
      subject: 'Welcome!',
      content: '<h1>Hello!</h1><p>Thank you for signing up.</p>'
    }).subscribe({
      next: (response) => {
        this.message = `Email sent! ${response.message}`;
        this.loading = false;
      },
      error: (error) => {
        this.error = `Error: ${error.message}`;
        this.loading = false;
      }
    });
  }
}

Using Async Pipe

contacts.component.tsTypeScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import { Component, OnInit } from '@angular/core';
import { MetiganService } from '@metigan/angular';
import { Observable } from 'rxjs';

@Component({
  selector: 'app-contacts',
  template: `
    <div *ngIf="contacts$ | async as contacts">
      <h2>Contacts</h2>
      <div *ngFor="let contact of contacts.contacts">
        <p>{{ contact.email }} - {{ contact.firstName }} {{ contact.lastName }}</p>
      </div>
      <p>Total: {{ contacts.pagination.total }}</p>
    </div>
  `
})
export class ContactsComponent implements OnInit {
  contacts$!: Observable<any>;

  constructor(private metigan: MetiganService) {}

  ngOnInit() {
    if (!this.metigan.isInitialized()) {
      this.metigan.initialize({ apiKey: 'your-api-key' });
    }

    this.contacts$ = this.metigan.contacts.list({
      audienceId: 'audience-123',
      page: 1,
      limit: 50
    });
  }
}

Form Submission

form.component.tsTypeScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
import { Component } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { MetiganService } from '@metigan/angular';

@Component({
  selector: 'app-contact-form',
  template: `
    <form [formGroup]="form" (ngSubmit)="onSubmit()">
      <input formControlName="email" type="email" placeholder="Email" />
      <input formControlName="name" placeholder="Name" />
      <textarea formControlName="message" placeholder="Message"></textarea>
      <button type="submit" [disabled]="form.invalid || loading">
        {{ loading ? 'Submitting...' : 'Submit' }}
      </button>
      <div *ngIf="successMessage">{{ successMessage }}</div>
      <div *ngIf="errorMessage" class="error">{{ errorMessage }}</div>
    </form>
  `
})
export class ContactFormComponent {
  form: FormGroup;
  loading = false;
  successMessage = '';
  errorMessage = '';

  constructor(
    private fb: FormBuilder,
    private metigan: MetiganService
  ) {
    this.form = this.fb.group({
      email: ['', [Validators.required, Validators.email]],
      name: ['', Validators.required],
      message: ['', Validators.required]
    });
  }

  onSubmit() {
    if (this.form.invalid) return;

    this.loading = true;
    this.errorMessage = '';
    this.successMessage = '';

    this.metigan.forms.submit({
      formId: 'your-form-id',
      data: {
        'field-email': this.form.value.email,
        'field-name': this.form.value.name,
        'field-message': this.form.value.message
      }
    }).subscribe({
      next: (response) => {
        this.successMessage = response.message;
        this.form.reset();
        this.loading = false;
      },
      error: (error) => {
        this.errorMessage = error.message;
        this.loading = false;
      }
    });
  }
}

Creating Contacts

create-contact.component.tsTypeScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
import { Component, OnDestroy } from '@angular/core';
import { MetiganService } from '@metigan/angular';
import { Subscription } from 'rxjs';

@Component({
  selector: 'app-create-contact',
  template: `
    <form (ngSubmit)="createContact()">
      <input [(ngModel)]="email" type="email" placeholder="Email" required />
      <input [(ngModel)]="firstName" placeholder="First Name" />
      <input [(ngModel)]="lastName" placeholder="Last Name" />
      <button type="submit" [disabled]="loading">Create Contact</button>
    </form>
  `
})
export class CreateContactComponent implements OnDestroy {
  email = '';
  firstName = '';
  lastName = '';
  loading = false;
  private subscription = new Subscription();

  constructor(private metigan: MetiganService) {}

  createContact() {
    if (!this.email) return;

    this.loading = true;

    const sub = this.metigan.contacts.create({
      email: this.email,
      firstName: this.firstName,
      lastName: this.lastName,
      audienceId: 'audience-123',
      tags: ['subscriber']
    }).subscribe({
      next: (contact) => {
        console.log('Contact created:', contact);
        this.loading = false;
        // Reset form
        this.email = '';
        this.firstName = '';
        this.lastName = '';
      },
      error: (error) => {
        console.error('Error creating contact:', error);
        this.loading = false;
      }
    });

    this.subscription.add(sub);
  }

  ngOnDestroy() {
    this.subscription.unsubscribe();
  }
}

Email with Attachments

email-attachment.component.tsTypeScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
import { Component } from '@angular/core';
import { MetiganService } from '@metigan/angular';

@Component({
  selector: 'app-email-attachment',
  template: `
    <div>
      <input type="file" #fileInput multiple (change)="onFileSelected($event)" />
      <button (click)="sendEmailWithAttachments()" [disabled]="loading || files.length === 0">
        Send Email with Attachments
      </button>
      <div *ngFor="let file of files">{{ file.name }}</div>
    </div>
  `
})
export class EmailAttachmentComponent {
  files: File[] = [];
  loading = false;

  constructor(private metigan: MetiganService) {}

  onFileSelected(event: Event) {
    const input = event.target as HTMLInputElement;
    if (input.files) {
      this.files = Array.from(input.files);
    }
  }

  sendEmailWithAttachments() {
    if (this.files.length === 0) return;

    this.loading = true;

    this.metigan.email.sendEmail({
      from: 'sender@example.com',
      recipients: ['recipient@example.com'],
      subject: 'Email with Attachments',
      content: '<p>Please find the attachments below.</p>',
      attachments: this.files
    }).subscribe({
      next: (response) => {
        console.log('Email sent with attachments:', response);
        this.files = [];
        this.loading = false;
      },
      error: (error) => {
        console.error('Error:', error);
        this.loading = false;
      }
    });
  }
}

Error Handling

error-handling.component.tsTypeScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
import { Component } from '@angular/core';
import { MetiganService, MetiganError, ValidationError, ApiError } from '@metigan/angular';

@Component({
  selector: 'app-error-handling',
  template: `
    <div>
      <button (click)="sendEmail()">Send Email</button>
      <div *ngIf="error" class="error">{{ error }}</div>
    </div>
  `
})
export class ErrorHandlingComponent {
  error = '';

  constructor(private metigan: MetiganService) {}

  sendEmail() {
    this.error = '';

    this.metigan.email.sendEmail({
      from: 'invalid-email', // This will cause a validation error
      recipients: ['recipient@example.com'],
      subject: 'Test',
      content: '<p>Test</p>'
    }).subscribe({
      next: (response) => {
        console.log('Success:', response);
      },
      error: (error) => {
        if (error instanceof ValidationError) {
          this.error = `Validation Error: ${error.message}`;
        } else if (error instanceof ApiError) {
          this.error = `API Error (${error.statusCode}): ${error.message}`;
        } else if (error instanceof MetiganError) {
          this.error = `Metigan Error: ${error.message}`;
        } else {
          this.error = `Unknown error: ${error.message}`;
        }
      }
    });
  }
}

Service Injection Pattern

service-example.tsTypeScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import { Injectable } from '@angular/core';
import { MetiganEmailService } from '@metigan/angular';
import { Observable } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class EmailService {
  constructor(private metiganEmail: MetiganEmailService) {
    // Initialize the service
    this.metiganEmail.initialize('your-api-key');
  }

  sendWelcomeEmail(userEmail: string, userName: string): Observable<any> {
    return this.metiganEmail.sendEmail({
      from: 'noreply@yourapp.com',
      recipients: [userEmail],
      subject: 'Welcome to Our App!',
      content: `<h1>Welcome ${userName}!</h1><p>Thank you for joining us.</p>`
    });
  }
}

// Use in component
@Component({
  selector: 'app-user',
  template: ''
})
export class UserComponent {
  constructor(private emailService: EmailService) {}

  onUserSignup(userEmail: string, userName: string) {
    this.emailService.sendWelcomeEmail(userEmail, userName).subscribe({
      next: () => console.log('Welcome email sent'),
      error: (error) => console.error('Error:', error)
    });
  }
}
RxJS Observables

All Metigan service methods return RxJS Observables. Always subscribe to handle responses and errors. Don't forget to unsubscribe in ngOnDestroyor use the async pipe in templates.

API Key Security

Store your API key in environment variables or a configuration service. Never hardcode API keys in your source code. Use Angular's environment files for different environments.