Skip to content

Resource Management

Travis Tidwell edited this page Sep 5, 2018 · 12 revisions

One major component of Form.io is the ability to manage Resources within your Serverless application. This library provides a mechanism to allow you to easily introduce those Resources within your application so that you can provide all of the CRUD capabilities of these resources to your users of the application.

Building your resources

To get started, you will first need to create a separate module for each Resource you wish to bring into your application. As a quick example, lets suppose that we wish to add new Events to our application. Assuming that this resource has an API url of https://myproject.form.io/event, we can register this within our application using the following code. Note: This assumes you already have the Angular CLI tool installed and that your project was created with the CLI tool.

ng g module event

src/app/event/event.module.ts

import { NgModule, Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule } from '@angular/router';
import {
  FormioResource,
  FormioResourceRoutes,
  FormioResourceConfig,
  FormioResourceService
} from 'angular-formio/resource';

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

This will register all of the CRUDI routes within the EventModule class so that they can be provided within the application.

Custom Resource Components

Now let's suppose that you wish to provide your own custom component for the Event view page where you provide your own template, as well as introduce your own business logic. You can do this by simply extending the FormioResourceViewComponent class and then adding it to the route registration like so.

ng g component event/view

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

import { Component } from '@angular/core';
import { FormioResourceViewComponent } from 'angular-formio/resource';
@Component({
  templateUrl: './view.component.html',
})
export class EventViewComponent extends FormioResourceViewComponent {}

src/app/event/event.module.ts

import { NgModule, Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule } from '@angular/router';
import {
  FormioResource,
  FormioResourceRoutes,
  FormioResourceConfig,
  FormioResourceService
} from 'angular-formio/resource';

import { EventViewComponent } from './view/view.component';

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

Once you have done this, your View component will now be executed when the user visits the view page of the Event component.

Mounting the Event Resource

The last thing that needs to be done is that the Event resource needs to be "mounted" within the main application. This can be done using the loadChildren construct within the router. We can do this as follows.

src/app.module.ts

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { BrowserModule } from '@angular/platform-browser';
import { RouterModule, Routes } from '@angular/router';
import { FormioModule } from 'angular-formio';
import { FormioResources } from 'angular-formio/resource';
import { MainComponent } from './main';

@NgModule({
  imports: [
    BrowserModule,
    CommonModule,
    FormioModule,
    RouterModule.forRoot([
      {
        path: 'event',
        loadChildren: './event/event.module#EventModule'
      }
    ])
  ],
  providers: [
    FormioResources
  ],
  declarations: [
    MainComponent
  ],
  bootstrap: [
    MainComponent
  ]
})
export class AppModule {}

Nested (hierarchical) Resources

Within this library, you can also created Nested, or Hierarchical Resources. This is useful if you wish to have some resources be the child of other resources. An example of this would be if you were creating an Event management system, you may wish to have Activities available for that Event. You would, therefore, create an Event Resource within Form.io, and then Create an Activity resource that has the Event Resource Field that points to its parent. If you wish to create a project with this configuration, then you can go to https://portal.form.io, and use this project.json as your template when creating your project.

https://github.com/formio/angular-app-starterkit/blob/master/src/project.json

Once you have that project created, you can now establish the nesting of resources by first creating the Event resource as well as the Activity resource.

ng g module event/activity

src/app/event/activity/activity.resource.ts

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule, Routes } from '@angular/router';
import { FormioAppConfig } from 'angular-formio';
import {
  FormioResource,
  FormioResourceRoutes,
  FormioResourceConfig,
  FormioResourceService
} from 'angular-formio/resource';

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

src/app/event/event.module.ts

import { NgModule, Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule, Routes, ActivatedRoute } from '@angular/router';
import { FormioAppConfig } from 'angular-formio';
import {
  FormioResourceModule,
  FormioResourceRoutes,
  FormioResourceConfig,
  FormioResourceService,
  FormioResourceComponent
} from 'angular-formio/resource';

const eventResourceRoutes: Routes = FormioResourceRoutes();
eventResourceRoutes[2].children.push({
  path: 'activity',
  loadChildren: './activity/activity.module#ActivityModule'
});

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

Notice in the Activity Resource declaration, that we provide the parents parameter to the FormioResourceConfig. This is what establishes the hierarchy and tells the Activity resource to ensure that the Event resource is loaded and populated when filling out the forms and viewing the indexes.

For a full working example of how this works, take a look at the Angular App Starterkit

Working with AOT compiler

By default, the dynamic routes will not compile with the AOT compiler. For this reason, you will need to declare the routes statically like the following which is the EventModule with the Activity resource mounted at a nested path.

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { EventResourceComponent } from './resource/resource.component';
import { EventViewComponent } from './view/view.component';
import { RouterModule } from '@angular/router';
import { FormioModule } from 'angular-formio';
import {
    FormioResource,
    FormioResourceConfig,
    FormioResourceService,
    FormioResourceIndexComponent,
    FormioResourceCreateComponent,
    FormioResourceEditComponent,
    FormioResourceDeleteComponent
} from 'angular-formio/resource';

@NgModule({
  imports: [
    CommonModule,
    FormioModule,
    FormioResource,
    RouterModule.forChild([
        {
            path: '',
            component: FormioResourceIndexComponent
        },
        {
            path: 'new',
            component: FormioResourceCreateComponent
        },
        {
            path: ':id',
            component: EventResourceComponent,
            children: [
                {
                    path: '',
                    redirectTo: 'view',
                    pathMatch: 'full'
                },
                {
                    path: 'view',
                    component: EventViewComponent
                },
                {
                    path: 'edit',
                    component: FormioResourceEditComponent
                },
                {
                    path: 'delete',
                    component: FormioResourceDeleteComponent
                },
                {
                    path: 'activity',
                    loadChildren: './activity/activity.module#ActivityModule'
                }
            ]
        }
    ])
  ],
  declarations: [ResourceComponent, ViewComponent],
  providers: [
      FormioResourceService,
      {
          provide: FormioResourceConfig,
          useValue: {
              name: 'event',
              form: 'event'
          }
      }
  ]
})
export class EventModule { }

Full Working Example

For a full working application example of how this works, please take a look at the Angular Demo Application application.