Back to blog
Blog

How to create a management system with Cosmic and Angular

Bulat Kutliev's avatar

Bulat Kutliev

February 14, 2018

cover image

TL;DR

Download the GitHub repo.
Check out the demo.

Intro

Imagine we need an app to run a parking lot with not too many requirements – parking slots should be cleaned and maintained.  Spots will be rented or owned and customers will need to pay for the service.  All of this data, along with customer information, will need to be stored for easy access. In this article I'll show you how to create this basic data management app using Cosmic.

Preparing backend

First, register in Cosmic and create your own bucket. 

After that we need to create a couple of Object Types: one for describing a parking spot, and another one for an event, happened to the spot. It might be one of three different types: payment, maintenance or cleaning.

To do it, within your bucket click "Add Object Type"

Every Object has built-in properties like title, slug, and content. Usually, it’s quite enough, but let’s make our Object Types more specific. Metafields to the rescue!

Add a list to keep a floor number and fill it with values ‘Ground’, ‘First’ and ‘Second’.

After that create another Object Type, spot event. Add Metafield type (‘Payment’, ‘Maintenance’ and ‘Cleaning’) and event date (as date typed Metafield). Don’t forget to add one more field with type ‘Object’ to point a parent spot.

Now we need to add a tiny scent of security: set up write_key and read_key to restrict anonymous access to our data. 

They are controlled by Settings -> Basic Settings page

Ok, our backend is complete. Our app will use powerful Cosmic API to operate, and all we need is to write a single page application. Angular 2 is a good solution for this.

Let the code rock!

Before we start.

First, we need to install NodeJS and its package manager NPM (surprisingly, it stays for NodeJS Package Manager). Here is quite a useful link: https://nodejs.org/en/download/package-manager/

Install Angular CLI (command-line interface). Take it from here: https://angular.io/guide/quickstart

Also, check out the code here: https://github.com/cosmicjs/parkingcare2/

and view demo app here: https://parkingcare.cosmicapp.co/

Getting started

Now open a console/command line/whatever you have to run commands and create a folder, get into it and type 

ng new ParkingCare. Ok, we have a sample project installed.

All the people were excited by Bootstrap years ago, so now it’s everywhere and looks boring. Take fresh and crisp Bulma framework. You can read about it here: https://bulma.io/

Another great UI thing is Font Awesome. Check it out here, if you haven’t done yet: https://fontawesome.com/



Go to parkingcare/src/index.html and add references for Bulma and Font Awesome

Let’s see how it looks now: run ng serve --open

Within app, folder create another three: models, services, and components

Data models

Create data models for our app: get into /models and type ng generate class entity, ng generate class spot, ng generate class spotevent. As TypeScript support inheritance everything common into an entity class and keep specific data in derived classes: Spot and SpotEvent 

Create another class called Settings and post this data into it. This data will serve as application configuration file

Service

Now we need to create a service – that exact thing which will pump API-calls for us. Move to the /services folder and type ng g service data ("g" means "generate"). We fill it a bit later.

Components

Now move to the /components and create a few components:

Dashboard (ng g component dashboard) – for the main page

Spotcard (ng g c dashboard) – for particular spot page

Spotcardedit (ng g c spotcardedit) – spot edit form

Eventcardedit (ng g c eventcardedit) – spotevent edit form

Routing

Now we need to add a router to explain to the system which component should be used for exact URL. Nice explanation located here https://angular.io/tutorial/toh-pt5

There are few request types we need to serve:

  • By default, we need to show a Dashboard
  • Create a new spot /createspot/
  • Display selected spot /spots/:spot_slug (like, /spots/101)
  • Edit selected spot /spot/:spot_slug/edit
  • Add new spot event /spot/:spot_slug/addevent
  • We don’t need a separate event list, spot display page covers it
  • All other requests to be redirected to the root

In the app/app-routing.module we need to assign components to the paths.

Ok, we created a routing, let’s see how it looks. Run ng serve --open again. See no changes. It is because we need to add a router-outlet tag to the app.component.html. 

Adjust it and run ng serve --open. Now it works.

UI

It’s time to make some UI. Our entry point, the dashboard, will show user two blocks:

  • Spot list overview
  • Last events happened

Go to the app/componens/dashboard/dashboard.component.html, create there a two-columns layout (let’s give two-thirds to the overview) and put component tags: app-spotlist and app-eventlist. But component tags won’t work without a data. Let’s pass some Objects there, “spots” for spot list and “spotEvents” for last events.

Data retrieving

These Objects are described in dashboard.component.ts. We need to go deeper there.

Go to the /services/data.service.ts and create a few functions there:

Some of them will be used for getting data, some of them for changing data.

Starting with a simple one: getting spot list. We will use RxJS (http://reactivex.io/rxjs/)

First, compose a proper URL to call Cosmic API.

After that call API by GET method and return thing, called Observable

Make similar to the event list.

And make final function getSpots()

return Observable.forkJoin(this.getSpotData(), this.getSpotEvents());

It will return all data when both lists ready.

Enough here, let’s go back to the dashboard.component.ts

Within ngOnInit we subscribe to the service function, and when receive a data we do some data transformation: repack received data into our Objects “spots” and “spotEvents”, which were described previously.

As our Objects inflated, they should be rendered on the page. We need to add couple more components: spotlist and eventlist (ng g component spotlist, ng g component eventlist)

In the component’s .ts file set @Input as an Object list (to be able to pass it to the component),

In .html file describe the list using *ngFor="let spot of spots" to iterate Objects within the passed list.

For the event list, it is quite similar.

Navigation

Our actions like adding or moving to the display page present as a link, but with routerLink param instead of href.

Also, there are some button click handlers. They are set up in (click)=”func(param)” way.

Data create

To create an Object we need to send a properly-formed json to the Cosmic API with a write key, passed in the payload. Let’s go to the services/data.service.ts and create a function for serving new spot creation.

By default, it is required to pass a title and type_slug. As we have a more complex Object, we also need to pass a metadata and write_key in out payload Object.

Don’t forget to add a header Content-Type: application/json. API won’t be able to recognize a payload without it. Send it with a POST to the /add-object and get a new Object back. It is pretty obvious.

Data change

To change your Object you need to POST another json to the Cosmic API “edit-object” controller. In that json you need to pass a write_key, updated Object slug, title, content and all Metafields (event if they not changed). And, of course, don’t forget Content-Type header.

Data removing.

As all out inner Objects are children of common Entity type we can use a common function because the only thing Cosmic needed to remove an Object – it is its slug. You have to call DELETE request to the API’s “objects” controller. In our case, we also need to pass a write_key, so here is a trick: we add a json {“write_key”: “”} as “body” option to the request. And it works just well.

Before removing a spot we need to ensure that bound events do not exist. So we call a function which checks that no events are bound to the spot. We can show the warning if the spot cannot be deleted. *ngIf is used for it

In components/spotcard/spotcard.component.html

And in components/spotcard/spotcard.component.ts

Ready to launch.

Well, now we need to deploy this somehow. Cosmic provides a nice and quite easy way to launch your app, PaaS based on Dokku. You just go to the Settings -> Deploy Web App in the left menu, fill the repo URL and click the blue button which says “Deploy to Web”.

Well, as we have an angular application, some extra preparations are required.

To make entire picture clear, we need to understand following statements:

  • Our code needs to be built (translated from Angular/TypeScript to Html/JavaScript)
  • We need to install angular infrastructure to let #1 possible
  • After building an app we need to start small web-server to serve inbound requests

Ok, let’s adjust the package.json a bit.

  • Move @angular/cli, @angular/compiler-cli, typescript and @types/node from devDependencies branch to the dependencies.
  • Add engines block
  • Add express dependency
  • Edit the “scripts” block in following way:
  • Change "start" line from “ng serve” to the “npm install && node server.js”. It will install everything required by dependency list and after that will start our web tiny server.
  • Add “postinstall” line with setting an entire path to the angular core “ng” and build. This line provides a building right after installation complete.
  • Create a server.js file in the folder root. It is quite primitive: require Express framework, set a static folder as /dist (it is a standard folder for angular’s build output), let it listen a port from environment variables or standard for Heroku 5000. That is it.

Here is the code of server.js


and part of the package.json

After these preparations commit everything to the repository, go to the deployment page (once again, Settings -> Deploy Web App) and click “Deploy to Web”. In a while, you receive an email from Cosmic as a successful deployment confirmation. If no, you can check that page again for the error log, if any.

Conclusion.

Now, when you see how simple and cozy it is, I hope you are excited enough to bring your ideas to life with Angular and Cosmic.