loading...
Cover image for QR Code Event Registration App - Angular PWA

QR Code Event Registration App - Angular PWA

devpato profile image Pato Updated on ・7 min read

In this tutorial I'm going to show you how to create a simple PWA that you can install in your phone. This PWA will be able to create QR codes and read them as well. With this app, you will have more control of your guests for your next event!

In this app, we are going to suppose is a registration app for your event.

The final code:
https://github.com/devpato/angular-pwa-qrcode

Live App:
https://qr-app-79289.firebaseapp.com/

Let's create an angular app

1) Run and when asked to create routing click yes and when asked to select a CSS processor select SCSS.

ng new qr-app

2) Let's create our app into a PWA (Progressive Web App), so we can install the app in our phone. Inside of your project in your command line run:

ng add @angular/pwa

3) Create a registration component.

ng g c registration

4) Create a scanner component.

ng g c scanner

5) Create a guest-list component.

ng g c guest-list

6) Create a guest service.

ng g s guest

7) Create the navbar component

ng g c navbar

8) Install the following packages inside of your project:

//This is the package that scans qr codes
npm i @zxing/ngx-scanner

//This is the packages that generates qr codes
npm i ngx-qrcode2

//This is the package used to generate a random id for your users
npm i uuid

9) Go to your index.html and add the Semantic UI cdn, to give some styling to our app.

<link
      rel="stylesheet"
      href="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.4.1/semantic.min.css"
      integrity="sha256-9mbkOfVho3ZPXfM7W8sV2SndrGDuh7wuyLjtsWeTI1Q="
      crossorigin="anonymous"
    />

10) Navigate to your registration.component.ts file. Then copy paste the following code.

import { FormBuilder } from "@angular/forms";
import { Validators } from "@angular/forms";
import { v4 as uuid } from "uuid";
import { GuestService } from "../guest.service";
import { Router } from "@angular/router";
.
.
.
export class RegistrationComponent implements OnInit {
  registrationForm = this.fb.group({
    firstName: ["", Validators.required],
    lastName: ["", Validators.required]
  });

  constructor(
    private fb: FormBuilder,
    private guestService: GuestService,
    private router: Router
  ) {}

  ngOnInit() {}

  onSubmit(): void {
    const guest = { ...this.registrationForm.value, id: uuid() };
    guest.qr = JSON.stringify(guest);
    this.guestService.addGuest(guest);
    this.registrationForm.reset();
    this.router.navigate(["/guests"]);
  }
}

11) Navigate to your registration.component.scss file. Then copy paste the following code.

.registration {
  text-align: center;
  margin: 8px;
  &-form {
    form {
      display: flex;
      flex-direction: column;

      .field {
        margin: 8px;
      }
    }
  }
}

12) Navigate to your registration.component.html file. Then copy paste the following code. The following code will generate a new guest, which will be the info inside of our QR code.

<div class="registration">
  <h2>QR Code Registration App!</h2>
  <span>Please enter your information to register for the event.</span>
  <div class="registration-form">
    <form [formGroup]="registrationForm" (ngSubmit)="onSubmit()">
      <div class="ui left corner labeled input field">
        <input
          type="text"
          placeholder="Fist Name"
          formControlName="firstName"
        />
        <div class="ui left corner label">
          <i class="asterisk icon"></i>
        </div>
      </div>
      <div class="ui left corner labeled input field">
        <input type="text" placeholder="Last Name" formControlName="lastName" />
        <div class="ui left corner label">
          <i class="asterisk icon"></i>
        </div>
      </div>
      <button
        class="ui inverted orange button"
        type="submit"
        [disabled]="!registrationForm.valid"
      >
        Registration
      </button>
    </form>
  </div>
</div>

13) Navigate to your navbar.component.html file. Then copy paste the following code.

<div class="ui three item menu">
  <a class="item" [routerLink]="['']">Registration</a>
  <a class="item" [routerLink]="['/scanner']">QR Scanner</a>
  <a class="item" [routerLink]="['/guests']">Guest</a>
</div>

14) Navigate to your guest-list.component.ts file. Then copy paste the following code.

import { GuestService } from "../guest.service";
.
.
.
guestList$ = this.guestService.guests$;
  elementType: "url" | "canvas" | "img" = "url";
  constructor(private guestService: GuestService) {}
ngOnInit() {}

15) Navigate to your guest-list.component.html file. Then copy paste the following code.

<div class="guest-list">
  <table class="ui celled table" *ngIf="guestList$ | async as guestList">
    <tbody>
      <tr *ngFor="let g of guestList">
        <td data-label="firstName">{{ g.firstName }}</td>
        <td data-label="lastName">{{ g.lastName }}</td>
        <td data-label="qr">
          <ngx-qrcode
            [qrc-element-type]="elementType"
            [qrc-value]="g.qr"
            class="qrcode"
          ></ngx-qrcode>
        </td>
      </tr>
    </tbody>
  </table>
</div>

16) Navigate to your guest-list.component.scss file. Then copy paste the following code.

.qrcode {
  display: flex;
  justify-content: center;
}

17) Navigate to your scanner.component.ts file. Then copy paste the following code.

import { Guest } from "../guest.model";
import { GuestService } from "../guest.service";
import { map } from "rxjs/operators";
.
.
.
availableDevices: MediaDeviceInfo[];
  currentDevice: MediaDeviceInfo = null;
  hasDevices: boolean;
  hasPermission: boolean;
  qrResult: Guest;
  guestExist: boolean;

  constructor(private guestService: GuestService) {}

  ngOnInit(): void {}

  //Clears the QR code scanned
  clearResult(): void {
    this.qrResult = null;
  }

  //Scans the QR code
  onCodeResult(resultString: string): void {
    this.guestExist = null;
    if (this.checkQRJSON(resultString)) {
      this.qrResult = JSON.parse(resultString);
      this.checkInGuest(this.qrResult);
      this.clearMessage();
    } else {
      this.guestExist = false;
      this.clearMessage();
    }
  }

  //Permission for the app to use the device camera
  onHasPermission(has: boolean): void {
    this.hasPermission = has;
  }

  //Checks if the QR code belongs to a valid guest
  checkInGuest(guestQR: Guest): void {
    this.guestService.guests$
      .pipe(
        map(guests =>
          guests.find((guest: Guest) => guest.id === guestQR.id)
        )
      )
      .subscribe(guest => {
        if (guest !== null && guest !== undefined) {
          this.guestExist = true;
        } else {
          this.guestExist = false;
        }
        this.clearResult();
        this.clearMessage();
      });
  }

  clearMessage() {
    setTimeout(() => {
      this.guestExist = null;
    }, 3000);
  }

  //This function check if the QR code has a valid JSON as data
  checkQRJSON(qrString: string): boolean {
    if (
      /^[\],:{}\s]*$/.test(
        qrString
          .replace(/\\["\\\/bfnrtu]/g, "@")
          .replace(
            /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,
            "]"
          )
          .replace(/(?:^|:|,)(?:\s*\[)+/g, "")
      )
    ) {
      return true;
    } else {
      return false;
    }
  }

18) Navigate to your scanner.component.html file. Then copy paste the following code.

<div class="qr-scan-area">
  <!-- This is the npm package in-charge of scanning the QR -->
  <zxing-scanner
    #scanner
    [(device)]="currentDevice"
    (scanSuccess)="onCodeResult($event)"
    (permissionResponse)="onHasPermission($event)"
  ></zxing-scanner>
  <div class="qr-area">
    <div class="area"></div>
  </div>
</div>

<!-- Displays message on the screen if guest is valid or not -->
<div class="guest">
  <ng-container *ngIf="guestExist">
    <div class="ui success message">
      <i class="close icon"></i>
      <div class="header">
        Welcome!!
      </div>
      <p>Guest has been found on the guest lists</p>
    </div>
  </ng-container>
  <ng-container #notFound *ngIf="guestExist === false">
    <div class="ui negative message">
      <i class="close icon"></i>
      <div class="header">
        Warning!
      </div>
      <p>This person is not a guest!</p>
    </div>
  </ng-container>
</div>

19) Navigate to your scanner.component.scss file. Then copy paste the following code. In this css we are drawging a red square to make the scanner look cooler, but is not needed for the scanner to work.

::ng-deep {
  .qr-scan-area {
    position: relative;
    zxing-scanner {
      max-width: 100%;
    }

    .qr-area {
      position: absolute;
      display: flex;
      justify-content: center;
      align-items: center;
      height: calc(100% - 50px);
      top: 0;
      width: 100%;
      .area {
        height: 200px;
        width: 200px;
        border: 2px solid red;
      }
    }
  }
}

20) Inside of the app folder create a new interface with the following name: guest.model.ts

21) Inside of your guest.model.ts copy paste the following:

export interface Guest {
  id: string;
  firstName: string;
  lastName: string;
  qr?: string;
}

22) Now, navigate to the guest service you previously created. guest.service.ts. The following code is the code that will handle populated some dummy data to start with as well as adding every new guest created to the array of guest.

import { Guest } from "./guest.model";
import { BehaviorSubject } from 'rxjs';
.
.
.
private guestSource = new BehaviorSubject<Guest[]>(null);
  guests$ = this.guestSource.asObservable();
  private guests = [
    {
      id: "7558e6e5-3cfa-4c24-b5b7-653ecbd49925",
      firstName: "Pato",
      lastName: "Vargas"
    },
    {
      id: "4847498c-b57f-4ceb-8c0c-8831b9972158",
      firstName: "Diego",
      lastName: "Maradona"
    }
  ];

  constructor() {
    this.populateQR();
    this.guestSource.next(this.guests);
  }

  populateQR(): void {
    this.guests.forEach((g: Guest) => (g.qr = JSON.stringify({ ...g })));
  }

  addGuest(newGuest: Guest): void {
    this.guests.push(newGuest);
    this.guestSource.next(this.guests);
  }

23) Go to your app.module.ts and add the following modules to your code

import { NgxQRCodeModule } from "ngx-qrcode2";
import { ZXingScannerModule } from "@zxing/ngx-scanner";
import { ReactiveFormsModule } from "@angular/forms";
.
.
.
imports: [
    BrowserModule,,
    AppRoutingModule,
    ServiceWorkerModule.register("ngsw-worker.js", {
      enabled: environment.production
    }),
    ReactiveFormsModule,
    ZXingScannerModule,
    NgxQRCodeModule
]

24) Finally we need to create the routes for our app. Copy paste the following code.

import { RegistrationComponent } from "./registration/registration.component";
import { GuestListComponent } from "./guest-list/guest-list.component";
import { ScannerComponent } from "./scanner/scanner.component";

const routes: Routes = [
  {
    path: "",
    component: RegistrationComponent
  },
  {
    path: "guests",
    component: GuestListComponent
  },
  {
    path: "scanner",
    component: ScannerComponent
  }
];

25) Go to your app.component.html erase everything that is in there and copy paste the following:

<app-navbar></app-navbar>
<router-outlet></router-outlet>

26) Time to test our app. Run the app with ng serve --o, you should see the following:

Time to use our PWA in our phone.

1) First run

ng build --prod

2) Deploy your app to your favorite hosting provider. I like Firebase. It's very easy to deploy. (I'm not going to show you how to do so, so please google it).

3) Once your app has been deploy, go to your phone an navigate to the URL where your app is living.

4) Once the app opens it will ask you if you want to add your app to your home screen, since is a PWA. Like the picture below shows.

Posted on by:

devpato profile

Pato

@devpato

Google Developer Expert on Angular and Web Technologies | Auth0 Ambassador | Media Developer Expert for Cloudinary | Technical Coach at SpringBoard

Discussion

pic
Editor guide