How to Build a Mobile Product Catalog App Using Angular JS, Ionic and Cosmic
Cosmic
May 18, 2017

TL;DR
View the codebase and follow installation instructions on GitHub.
In this tutorial Iâm going to show you how to create a simple catalog mobile app with Cosmic and Ionic Framework.
Prerequisites
Youâll need the node.js, npm and ionic cli pre-installed. Make sure you already have them before start. Please refer to ionic docs how to do this. You need Ionic framework >= 2.0 to run this example, so make sure you have the right Ionic version:
ionic -v
Getting Started
First of all weâll need to create the ionic project. Weâll use standard tabs template and will modify one tab to keep our Catalog component. So once youâll have all prerequisites installed, youâll need to setup the new Ionic project:
ionic start cosmic-demo tabs --v2
After youâll setup this project youâll be able to run
ionic serve
And play with your app in browser
Setting up Cosmic library
First of all, install Cosmic Angular/JavaScript library
npm install cosmicjs --save
Now you should be able to import Cosmic object and perform Cosmic API calls like following:
import Cosmic from 'cosmicjs'; const bucket = { slug: 'your-bucket-slug' }; Cosmic.getObjects({ bucket }, (err, res) => { console.log(res.objects); });
Setting up things with Cosmic
Create the bucket and remember the bucket name (âcosmic-ionicâ in our case):
Than create a new object type named âCategoryâ and please remember the object type slug (âcategoriesâ).
We donât need any additional settings right now, so just set the name and save object type. After save youâll be redirected to âNew Categoryâ page. Create some categories using this page and save them.
Now create the Product object type using the same method as for categories. But weâll have one difference - please enter the âMetafields Templateâ tab and add âImage/Fileâ type metafield with key 'image'. This metafield will store the product image.
The second metafield youâll need to add is âSingle Object Relationshipâ. Please create such metafield and choose Category as âObject type to choose fromâ.
Such Product structure allows us to create one-to-many relationship between products and categories.
Once Product object type will be created, please add some demo products and assign them to different categories. Make sure youâll have more than 5 products in single category - this allow us to test infinite scroll.
Ionic part of the app
Create src/pages/categories_list/categories_list.ts file with the following content:
import { Component } from '@angular/core'; import { NavController } from 'ionic-angular'; import Cosmic from 'cosmicjs'; import { ProductsList } from '../products_list/products_list'; @Component({ selector: 'page-categories', templateUrl: 'categories_list.html' }) export class CategoriesList { public categories; constructor( public navCtrl: NavController ) { this.categories = []; Cosmic.getObjectType({ bucket: { slug: 'cosmic-ionc' } }, { type_slug: 'categories' }, (err, res) => { this.categories = res.objects.all; }); } navToCategory(category) { this.navCtrl.push(ProductsList, { title: category.title, id: category._id }); } }
Than create a template for CategoriesList component:
<ion-header> <ion-navbar> <ion-title> Categories </ion-title> </ion-navbar> </ion-header> <ion-content padding> <ion-list> <button ion-item *ngFor="let category of categories" (click)="showProducts()"> {{ category.title }} </button> </ion-list> </ion-content>
Add CategoriesList component to app.module.ts as itâs done with other components like HomePage and set it as first tab for TabsPage component.
What happens here?
Our Categories list component uses Cosmic API on its constructor to receive a list of categories we have. It uses two things to achieve the required functionality:
- Filters objects by Cosmic bucket
- Filters objects by object type
CategoriesList components references ProductsList component - it navigates to products list page once user click on the category item. So we need the ProductsList - component which will show us products list for each particular category. Letâs introduce it!
import { Component } from '@angular/core'; import { NavController, NavParams } from 'ionic-angular'; import {Http} from '@angular/http'; import { DomSanitizer } from '@angular/platform-browser' @Component({ selector: 'page-products-list', templateUrl: 'products_list.html' }) export class ProductsList { public products; public category_title; constructor( public navCtrl: NavController, public params: NavParams, public http: Http, private sanitizer: DomSanitizer ) { this.products = []; this.category_title = this.params.get('title'); this.http.get(`https://api.cosmicjs.com/v1/cosmic-ionc/object-type/products/search?metafield_key=category&metafield_value=${this.params.get('id')}`).subscribe((resp) => { let data = resp.json(); if (data.objects) { this.products = data.objects; } else { this.products = []; } }); } getImageUrl(product) { let url = product.metafields.find((v) => { return (v.key == 'image') }).value; return `https://cosmicjs.imgix.net/${url}`; } sanContent(product): any { return this.sanitizer.bypassSecurityTrustHtml(product.content); } }
And here we have the ProductsList template:
<ion-header> <ion-navbar> <ion-title> {{ category_title }} </ion-title> </ion-navbar> </ion-header> <ion-content padding> <ion-card ion-item *ngFor="let product of products"> <img [src]="getImageUrl(product)" alt=""> <ion-card-content> <ion-card-title>{{ product.title }}</ion-card-title> <div class="white-space-normal" [innerHTML]="sanContent(product)"></div> </ion-card-content> </ion-card> </ion-content>
Whatâs happening here?
Cosmic JavaScript library doesnât provide any method to filter objects by their properties, but REST API does. Thatâs why weâre doing a HTTP request to Cosmic API using Angular Http module.
In this case request URL should look like the following:
https://api.cosmicjs.com/v1/BUCKET_NAME/object-type/OBJECT_TYPE_SLUG/search?metafield_key=CATEGORY_OBJECT_TYPE_SLUG&metafield_value=CATEGORY_OBJECT_ID
The second interesting thing we have to look at is getImageUrl function. Image is a part of product metadata, thatâs why itâll be an item of metafields array for each API response object. Our goal is to extract the required metafieldsarray item (with key field equals to âimageâ - the key weâve entering during metafield creation). This array item will also have value key - itâs the image file name, weâll need to prepend it with https://cosmicjs.imgix.net/ to get full image URL.
Weâre using Angular 4 here, thatâs why we have to use DomSanitizer to display HTML markup received from Cosmic API.
Conclusion
Cosmic allows us to quickly start mobile application development without thinking too much about backend and API. Generally, everything can be done using your Ionic/Angular developers and would save you a lof of time and money. Any backend/API entities can be quickly added/removed or modified to meet your project requirements.