Application Development

You’re ready to get started! The fastest way to immerse ourselves in <form.io> is to create a simple application that demonstrates the platforms capabilities.

Create your Project

You created an account and are here! Let’s create an Event Registration system in 30 minutes using Angular! Let’s create a new project by clicking Angular

Provide your project information like so, and then click Create Project

Create Resources

An Event Registration application will need to store some “structured” objects called Events. These are called Resources in Form.io, so lets create a new Event by clicking on the following.

We will then build our Event object using a form builder (pretty cool). We could also provide some field validations and such, but for now we will keep the form simple.

When you are done, click on Create Resource

Assigning Permissions

You now need to allow Authenticated users to read all events. We will also want them to be able to create their own, update their own, and delete their own events. To do this, click on Access section, and configure the settings as follows.

The settings should automatically save when you add this role to these permissions.

Event Registration Form

Now that we have an Event resource, we need a way for people to register to attend the Event. This is a great use case for a Form which provides “unstructured” data that references Resources.

Let’s create a new form by clicking on the Forms section and pressing New Form, and then selecting API Web Form.

Here we will build an Registration form. The first field we will add to this form is a Resource field like so…

Once we add this, field, we will then configure it as follows to point to the Event resource.

Now that we have an Event resource field, we can add other fields to the registration form like so…

We will now press the Create Form button to save our form.

Access Permissions

We also need to ensure that Authenticated users can submit the Registration Form, so we will go to the Access section and configure the following.

The permissions should automatically save when you set them.

We are now done setting up our Form.io Resources + Forms for our application, now lets build an app!

Create an Application

To get started quickly in Angular, we recommend using the Angular CLI tool to create our application. We can do this by typing the following within your terminal.

npm install -g @angular/cli
ng new eventmanager --style=scss

For the options, we will select the following

  • Would you like to add Angular routing? Yes
  • Which stylesheet format would you like to use? SCSS

This will now create a new application within the folder eventmananger, we can navigate into that folder by typing the following in the terminal.

cd eventmanager

We will now bring in all of our dependencies into the application by typing the following within the application folder.

npm install --save bootstrap bootswatch font-awesome angular-formio

We can now setup the styles for our application by editing the following file.

src/styles.scss

@import "~bootswatch/dist/cosmo/_variables.scss";
@import "~bootstrap/scss/bootstrap.scss";
@import "~bootswatch/dist/cosmo/_bootswatch.scss";
$fa-font-path: '../node_modules/font-awesome/fonts';
@import '~font-awesome/scss/font-awesome';

We now need to ensure that the global keyword is set to the browser window. We can do this within the following file by adding the following line.

src/polyfills.ts

...
...

/***************************************************************************************************
 * APPLICATION IMPORTS
 */
(window as any).global = window;

We will now start our application by typing the following in the terminal.

ng serve

You should see the following when you go to http://localhost:4200 in your browser.

We can now create a home page, by typing the following in the terminal.

ng g component home

And then provide the following code in the following file.

src/app/home/home.component.html

<div class="jumbotron">
  <h3>Event Registration Application</h3>
  <p>This is an example home page for the Event Registration Application</p>
</div>

And then add the following to the routes.

src/app/app-routing.module.ts

...
import { HomeComponent } from './home/home.component';

const routes: Routes = [
  {
    path: 'auth',
    loadChildren: './auth/auth.module#AuthModule'
  }
];

...

Application Configuration

Now that we have an application running, we will need create a configuration file so that we can tell the application which Form.io project we are pointed to.

To do this, we will create a new config.ts file as follows.

src/app/config.ts

export const AppConfig = {
  appUrl: 'https://yourproject.form.io',
  apiUrl: 'https://api.form.io'
};

You will need to make sure that you replace “yourproject” with the name of your Project URL which you can find at the following location within your Project page.

User Authentication

Now that we have the configuration file in place, we can setup User Authentication.

Angular Auth Documentation

We accomplish this by first creating an Angular module that will contain the authentication routes.

ng g module auth

This will create a new folder within our application within the src/app folder, which we can then use to include all the necessary modules to bring in Authentication.

src/app/auth/auth.module.ts

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule } from '@angular/router';
import { FormioAuth, FormioAuthRoutes } from 'angular-formio/auth';

@NgModule({
  declarations: [],
  imports: [
    CommonModule,
    FormioAuth,
    RouterModule.forChild(FormioAuthRoutes())
  ]
})
export class AuthModule { }

We must now register the Authentication module by lazy loading the module within the “auth” route. We can accomplish this within the following file.

src/app/app-routing.module.ts

const routes: Routes = [
  {
    path: '',
    component: HomeComponent
  },
  {
    path: 'auth',
    loadChildren: './auth/auth.module#AuthModule'
  }
];

Next, we just need to register the service providers with configurations within the app.module.ts file.

src/app/app.module.ts

...
...
import { AppConfig } from './config';
import { FormioAppConfig } from 'angular-formio';
import { FormioResources } from 'angular-formio/resource';
import { FormioAuthService, FormioAuthConfig } from 'angular-formio/auth';

@NgModule({
  ...
  ...
  providers: [
    FormioResources,
    FormioAuthService,
    {provide: FormioAppConfig, useValue: AppConfig},
    {provide: FormioAuthConfig, useValue: {
      login: {
        form: 'user/login'
      },
      register: {
        form: 'user/register'
      }
    }}
  ]
})
export class AppModule { }

We should now add a header to our application so that we can login, and see our login state.

We can now add a header to our application by editing the following file.

src/app/app.component.html

<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
  <div class="container">
    <a class="navbar-brand" href="#"><img style="height: 2em;" src="https://portal.form.io/images/formio-logo.png" /></a>
    <ul class="nav navbar-nav mr-auto">
      <li class="nav-item" routerLinkActive="active">
        <a class="nav-link" routerLink="/"><i class="fa fa-home"></i></a>
      </li>
      <li class="nav-item" routerLinkActive="event" *ngIf="auth.authenticated">
        <a class="nav-link" routerLink="event"><i class="fa fa-calendar"></i> Events</a>
      </li>
    </ul>
    <ul class="nav navbar-nav ml-auto">
      <li class="nav-item" routerLinkActive="active" *ngIf="!auth.authenticated">
        <a class="nav-link" routerLink="auth">Login | Register</a>
      </li>
      <li class="nav-item" *ngIf="auth.authenticated">
        <a class="nav-link" routerLink="/" (click)="auth.logout()"><span class="glyphicon glyphicon-off"></span> Logout</a>
      </li>
    </ul>
  </div>
</nav>
<div class="container pt-3">
  <router-outlet></router-outlet>
</div>

src/app/app.component.ts

...
...
import { Router } from '@angular/router';
import { FormioResources } from 'angular-formio/resource';
import { FormioAuthService } from 'angular-formio/auth';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent {
  ...
  ...
  constructor(
    public auth: FormioAuthService,
    private router: Router,
    public resources: FormioResources
  ) {
    this.auth.onLogin.subscribe(() => {
      this.router.navigate(['/']);
    });

    this.auth.onLogout.subscribe(() => {
      this.router.navigate(['/auth/login']);
    });

    this.auth.onRegister.subscribe(() => {
      this.router.navigate(['/']);
    });
  }
}

We should now see the following within our application with a working authentication and registration system.

Application Resources

Now that you have a running application with authentication, we can now add the Event resource using the FormioResource module.

Angular Resource Documentation

ng g module event

We will then add the following to the following module file.

src/app/event/event.module.ts

...
import { RouterModule } from '@angular/router';
import {
  FormioResource,
  FormioResourceRoutes,
  FormioResourceConfig,
  FormioResourceService
} from 'angular-formio/resource';

@NgModule({
  declarations: [],
  imports: [
    CommonModule,
    FormioResource,
    RouterModule.forChild(FormioResourceRoutes())
  ],
  providers: [
    FormioResourceService,
    {provide: FormioResourceConfig, useValue: {
      name: 'event',
      form: 'event'
    }}
  ]
})
export class EventModule { }

The next thing we will need to do is to register this event within the router.

src/app/app-routing.module.ts

const routes: Routes = [
  ...
  ...
  {
    path: 'event',
    loadChildren: './event/event.module#EventModule'
  }
];

You now have a complete Event management system!

Let’s add our Registration form!

Event Registration

We will now add the Event Registration form to the event. Since forms and resources are conceptually the same thing in Form.io, we can use a nested resource to attach forms to any resource within our application. We can start by adding a submodule within Angular.

ng g module event/register

We can now add the following to the created file.

src/app/event/register/register.module.ts

...
import { RouterModule } from '@angular/router';
import {
  FormioResource,
  FormioResourceRoutes,
  FormioResourceConfig,
  FormioResourceService
} from 'angular-formio/resource';

@NgModule({
  declarations: [],
  imports: [
    CommonModule,
    FormioResource,
    RouterModule.forChild(FormioResourceRoutes())
  ],
  providers: [
    FormioResourceService,
    {provide: FormioResourceConfig, useValue: {
      name: 'registration',
      form: 'registration',
      parents: [
        'event',
        {
          field: 'user',
          resource: 'currentUser',
          filter: false
        }
      ]
    }}
  ]
})
export class RegisterModule { }

Notice that we added the parents construct to our providers. This tells the Form.io Angular Resource system that this is nested within the Event resource as well as should contain the currently logged in User assigned to the new records as well.

Next, we need to mount this nested resource within the Event resource. To do this, we add it to the children of the Event resource routes as follows.

src/app/event/event.module.ts

...
import { RouterModule, Routes } from '@angular/router';
import { RegisterModule } from './register/register.module';
...

const eventRoutes: Routes = FormioResourceRoutes();
eventRoutes[2].children.push({
  path: 'registrations',
  loadChildren: () => RegisterModule
});

@NgModule({
  declarations: [],
  imports: [
    ...
    RouterModule.forChild(eventRoutes)
  ],
  ...
})
export class EventModule { }

For nested resources, we do need to use the Dynamic loading method for bringing in the submodule.

loadChildren: () => RegisterModule

For some reason, this does not work if you use the lazy loading method such as loadChildren: './register/register.module#RegisterModule''

We can now navigate to the following url to see the Forms for a specific event, as well as all the registrations within that Event.

http://localhost:4200/event/[EVENTID]/registrations

Next, we will need to change the Event resource view so that we can add the tab to the interface.

ng g component event/resource

We can now add the following the the event resource html.

src/app/event/resource/resource.component.html

<ul class="nav nav-tabs" style="margin-bottom: 10px;">
  <li class="nav-item"><a class="nav-link" routerLink="../"><i class="fa fa-chevron-left"></i></a></li>
  <li class="nav-item"><a class="nav-link" routerLink="view" routerLinkActive="active">View</a></li>
  <li class="nav-item"><a class="nav-link" routerLink="registrations" routerLinkActive="active">Registrations</a></li>
  <li class="nav-item"><a class="nav-link" routerLink="edit" routerLinkActive="active">Edit</a></li>
  <li class="nav-item"><a class="nav-link" routerLink="delete" routerLinkActive="active"><span class="fa fa-trash"></span></a></li>
</ul>
<router-outlet></router-outlet>

Next, we will need to extend the FormioResourceComponent

src/app/event/resource/resource.component.ts

import { Component } from '@angular/core';
import { FormioResourceComponent } from 'angular-formio/resource';

@Component({
  selector: 'app-resource',
  templateUrl: './resource.component.html',
  styleUrls: ['./resource.component.scss']
})
export class ResourceComponent extends FormioResourceComponent {}

And finally, we can register this within the routes using the following.

src/app/event/event.module.ts

const eventRoutes: Routes = FormioResourceRoutes({
  resource: ResourceComponent
});

This should create the following interface, where we can now view all of the registrations within an Event.

Let’s now change the Event view page to add a Register for this Event button!

Event View

To change the view of the Event, we can use the same method we did for the Resource component, but this time we will create one for the event view.

ng g component event/view

We can now modify the following template with the following.

src/app/event/view/view.component.html

<div class="row">
  <div class="col col-sm-6">
    <div class="card">
      <div class="card-header bg-primary text-white">
        <h3 class="card-title">Event Information</h3>
      </div>
      <ul class="list-group list-group-flush">
        <li class="list-group-item"><strong>Title:</strong> {{ service.resource.data.title }}</li>
        <li class="list-group-item"><strong>Description:</strong> {{ service.resource.data.description }}</li>
        <li class="list-group-item"><strong>Date:</strong> {{ service.resource.data.date }}</li>
      </ul>
    </div>
  </div>
  <div class="col col-sm-6">
    <div class="card">
      <div class="card-header bg-success text-white">
        <h3 class="card-title">Event Registration</h3>
      </div>
      <div class="card-body">
        <a routerLink="../registrations/new" class="btn btn-primary">Register for this Event</a>
      </div>
    </div>
  </div>
</div>

Next, we need to extend the FormioResourceView as follows.

src/app/event/view/view.component.ts

import { Component } from '@angular/core';
import { FormioResourceViewComponent } from 'angular-formio/resource';

@Component({
  selector: 'app-view',
  templateUrl: './view.component.html',
  styleUrls: ['./view.component.scss']
})
export class ViewComponent extends FormioResourceViewComponent {}

And finally, we will register this with the FormioResourceRoutes as follows.

src/app/event/event.module.ts

const eventRoutes: Routes = FormioResourceRoutes({
  resource: ResourceComponent,
  view: ViewComponent
});

This produces the following result…

We now have a full working Event Management system, which even allows for other users to create an account and Register for this event. We hope that this walkthrough guide provides you a solid footing on building your next Serverless application on Form.io!

If you would like to download the code behind this application, then go to Event Manager Github Page.

Walthrough Video

Here is an online video where we create an application from scratch.