Newsletter Subscription Template in Angular

author-image  By Dhiraj, 03 December, 2018   0K

In this article, we will be developing a sample newsletter subscription template in an Angular app using material design. To do so, first, we will generate a sample angular 7 app with Angular CLI. The app will have routing added. Then we will be integrating material design in it. We will make use of material MatDialogModule to create a custom dialog and then apply some CSS and add scripts to function it as a newsletter subscription template.

In my last article - Angular Material Dialog, we had a detailed explanation of creating custom dialog using MatDialogModule. Hence, you can surely visit that article for a better understanding of MatDialogModule and share data with the dialog component. Below is the screenshot of the final product that we will be building here.

angular-material-newsletter-subcription

Angular 7 Project Generation

Traverse to your folder of choice and execute following commands to generate and run the Angular 7 app. While generating the project with CLI, you will be prompted to add routing and stylesheet format you like to use. We will be using indigo-pink.css in this example.

ng new angular-material-newsletter

You can visit my another article for a Full Stack Angular 7 CRUD App.

Now, let us add angular material to it. To do so, you can cd inside angular-material-newsletter and run below command to add material in it.

ng add @angular/material

Now, let us create a new module which will have all the material modules imported into it and we will import this module in our main module app.module.ts.

material.module.ts
import {NgModule} from'@angular/core';
import { CommonModule } from '@angular/common';
import {
  MatButtonModule, MatInputModule, MatToolbarModule, MatDialogModule, MatTableModule, MatIconModule, MatMenuModule, MatFormFieldModule,
} from '@angular/material';

@NgModule({
  imports: [CommonModule, MatButtonModule, MatToolbarModule, MatInputModule, MatDialogModule, MatTableModule, MatIconModule,
    MatMenuModule, MatFormFieldModule],
  exports: [CommonModule, MatButtonModule, MatToolbarModule, MatInputModule, MatDialogModule, MatTableModule, MatIconModule,
    MatMenuModule, MatFormFieldModule],
})
export class CustomMaterialModule { }

Now, let us generate our components. We will be creating 2 components i.e. user and newsletter. User component will have a tabular data and newsletter related stuffs will be implemented in newsletter component.

ng g component user --module app.module.ts
ng g component newsletter --module app.module.ts

App Module Configuration

Below is our app.module.ts where routing module, our custom material module and reactive forms module is implemented. We can see that the NewsLetterComponent is included inside entryComponents and providers. This is required to load the newsletter component in a dialog.

app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from'./app.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { UserComponent } from './user/user.component';
import {CustomMaterialModule} from "./material.module";
import { NewsletterComponent } from './newsletter/newsletter.component';
import {FormsModule, ReactiveFormsModule} from "@angular/forms";

@NgModule({
  declarations: [
    AppComponent,
    UserComponent,
    NewsletterComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    BrowserAnimationsModule,
    CustomMaterialModule,
    FormsModule,
    ReactiveFormsModule
  ],
  entryComponents: [NewsletterComponent],
  providers: [NewsletterComponent],
  bootstrap: [AppComponent]
})
export class AppModule { }

app.routing.ts
import { NgModule } from '@angular/core';
import{ Routes, RouterModule } from '@angular/router';
import {UserComponent} from "./user/user.component";

const routes: Routes = [
  { path: 'user', component: UserComponent },
  { path: '', component: UserComponent }
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }

Angular 7 User Component

User component has a very simple implementation of material table. It is very similar to existing implementation available on Official website here.

user.component.html
<mat-toolbar color="primary">
  <mat-toolbar-row>
    <span><a href="/" style="color: #FFF">Devglan</a></span>
    <span class="fill-remaining-space"></span>
    <span class="">
    <button type="button" mat-button [matMenuTriggerFor]="adminMenu">
      <mat-icon>more_vert</mat-icon></button>
    <mat-menu #adminMenu="matMenu">
        <a mat-menu-item>About Us</a>
      <a mat-menu-item>Contact Us</a>
    </mat-menu>
    </span>
  </mat-toolbar-row>
</mat-toolbar>
<div class="user-container">
  <table mat-table [dataSource]="dataSource" class="mat-elevation-z8">

    <ng-container matColumnDef="position">
      <th mat-header-cell *matHeaderCellDef> No. </th>
      <td mat-cell *matCellDef="let element"> {{element.position}} </td>
    </ng-container>

    <ng-container matColumnDef="name">
      <th mat-header-cell *matHeaderCellDef> Name </th>
      <td mat-cell *matCellDef="let element"> {{element.name}} </td>
    </ng-container>

    <ng-container matColumnDef="weight">
      <th mat-header-cell *matHeaderCellDef> Weight </th>
      <td mat-cell *matCellDef="let element"> {{element.weight}} </td>
    </ng-container>

    <ng-container matColumnDef="symbol">
      <th mat-header-cell *matHeaderCellDef> Symbol </th>
      <td mat-cell *matCellDef="let element"> {{element.symbol}} </td>
    </ng-container>

    <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
    <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
  </table>
</div>
user.component.ts
import { Component, OnInit } from '@angular/core';

@Component({
  selector : 'app-user',
  templateUrl : './user.component.html',
  styleUrls : ['./user.component.css']
})
export class UserComponent {

  displayedColumns: string[] = ['position', 'name', 'weight', 'symbol'];
  dataSource = ELEMENT_DATA;

}

export interface PeriodicElement {
  name: string;
  position: number;
  weight: number;
  symbol: string;
}

const ELEMENT_DATA: PeriodicElement[] = [
  {position: 1, name: 'Hydrogen', weight: 1.0079, symbol: 'H'},
  {position: 2, name: 'Helium', weight: 4.0026, symbol: 'He'},
  {position: 3, name: 'Lithium', weight: 6.941, symbol: 'Li'}
];

NewsLetter Component Implementation

Let us first prepare our HTML code for the newsletter. It will have some text and a form having an input field for email address. We will be using a reactive form module. If the email is a valid email then only the subscribe button will be enabled.

newsletter.component.html
<div class="modal-newsletter">
  <h4 mat-dialog-title>Subscribe to our monthly newsletter</h4>

  <div mat-dialog-content>
    <mat-icon color="warn" class="icon-box">email</mat-icon>
    <p>Join our subscriber's list to get the latest updates and articles delivered directly in your inbox.</p>
    <form>
      <div class="newsletter-form-field">
        <mat-form-field class="newsletter-input">
          <mat-label>Email</mat-label>
          <input matInput [formControl]="newsletterForm">
          <mat-error *ngIf="newsletterForm.hasError('email') && !newsletterForm.hasError('required')">
            Please enter a valid email address
          </mat-error>
          <mat-error *ngIf="newsletterForm.hasError('required')">
            Email is <strong>required</strong>
          </mat-error>
        </mat-form-field>
        <button mat-raised-button color="primary" mat-dialog-close (click)="subscribe()"  [disabled] = "!newsletterForm.valid">Subscribe</button>
      </div>
    </form>
  </div>
</div>

Similarly, we have a newsletter.component.ts. We have a method subscribe() defined that will be called on the click of subscribe button. Here, we are just printing the email in the console. You can actuallly call your backend service to persist the email in the DB.

newsletter.component.ts
import {Component, OnInit} from '@angular/core';
import {MatDialogRef} from "@angular/material";
import {FormControl, Validators} from "@angular/forms";

@Component({
  selector: 'app-newsletter',
  templateUrl: './newsletter.component.html',
  styleUrls: ['./newsletter.component.css']
})
export class NewsletterComponent implements OnInit {

  newsletterForm: FormControl;

  constructor(private dialogRef: MatDialogRef) {

  }

  public closeDialog() {
    this.dialogRef.close();
  }

  subscribe() {
    if(this.newsletterForm.valid) {
      console.log(this.newsletterForm.value);
    }

  }

  ngOnInit(): void {

    this.newsletterForm = new FormControl('', [
      Validators.required,
      Validators.email,
    ]);
  }

}

Our newsletter subscription template is ready now. But we want our newsletter to be shown for the first time a user lands on our website and once the user subscribes to our newsletter by entering the email addresss, it should not be shown again. For this, we will be using setTimeout() to open the dialog automatically if the user is still not subscribed to our newsletter.

Below is the implementation to achieve this in app.component.ts

import { Component } from '@angular/core';
import {MatDialog} from "@angular/material";
import {NewsletterComponent} from "./newsletter/newsletter.component";

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'angular-material-newsletter';

  constructor(public dialog: MatDialog) {
    setTimeout(() => {
      if (!window.sessionStorage.getItem('newsletter')) {
        this.dialog.open(NewsletterComponent, {
          width: '600px',
          data: ''
        });
      }
    }, 10000);
  }
}

newsletter.component.css
.modal-newsletter {color: #999;font-size: 15px; display: flex;flex-direction: column; text-align: center}
.modal-newsletter h4 {color: #000;font-size: 30px;margin: 0;font-weight: bold;text-align: center}
.icon-box {font-size:80px;z-index: 9;text-align: center;margin: 10px 0;}
.hint-text {margin: 100px auto;text-align: center;}
.newsletter-form-field {display: flex; flex-direction: row;justify-content: space-evenly}
.newsletter-input {flex-basis: 40%}

Conclusion

This is a simple implementation of a newsletter template using Angular 7 material design. You can visit this page for all the Angular tutorials posted on Devglan.

About The Author

author-image

Further Reading on Angular JS

1. Material Sidenav Example

2. Spring Boot Angular Captcha

3. Angular 6 Example

4. Rxjs Tutorial

5. Building Angular Application

If You Appreciate What We Do Here On Devglan, You Should Consider: