Ionic 2 Beers
Ionic Beers is a tutorial of the Beer Tutorials series. In this tutorial we will create a simple app that queries a beer catalog and displays a list of beers.
Getting Started
Install NodeJS and then using the node package manager (npm), install ionic and cordova.
npm install -g ionic cordova
After installing ionic, create a new project called ionic2-beers
.
ionic start ionic2-beers blank --v2
Navigate to the project directory and add the mobile development platform.
ionic platform add android
Run the application on the Android emulator.
ionic emulate android
Run the application on desktop browser
ionic serve --lab
Note: To run the application in the Android emulator, you need to have the Android SDK installed and configured on your computer. The easiest way to do it is to install Android Studio for your platform.
If you have issues while initializing the app, read carefully these instructions
Project Structure
.
└── ionic2-beers
├── hooks
│ ├── after_prepare
│ │ └── ...
│ └── README.md
├── node_modules
│ ├── ...
│ └── ...
├── platforms
│ ├── android
│ │ └── ...
│ ├── ios
│ │ └── ...
│ └── platform.json
├── plugins
│ ├── ...
│ ├── fetch.json
│ └── ios.json
├── resources
│ ├── android
│ │ └── ...
│ ├── ios
│ │ └── ...
│ ├── icon.png
│ └── splash.png
├── src
│ ├── app
│ | ├── app.component.ts
│ | ├── app.html
│ | ├── app.module.ts
│ | ├── app.scss
│ | └── main.ts
│ ├── assets
│ | └── icon
│ | └── favicon.ico
│ ├── pages
│ | └── home
│ | ├── home.html
│ | ├── home.scss
│ | └── home.ts
│ ├── theme
│ | └── variables.scss
│ ├── declaration.d.ts
│ ├── index.html
│ ├── manifest.json
│ └── service-worker.js
├── typings
│ └── cordova-typings.d.ts
├── www
│ ├── index.html
| ├── manifest.json
| └── service-worker.js
├── package.json
├── config.xml
├── ionic.config.json
├── tsconfig.json
└── tslint.json
Inside the project folder there are 8 sub-folders: hooks
, node_modules
, platforms
, plugins
, resources
, src
, typings
and www
. The application source code resides in the app
folder. Application code is written using Angular2 and Typescript.
Inside the src
folder is a file called index.html
which has the default application code. Finally app/main.ts
contains the code to start the application with the defined modules.
Designing the app
Beers list
We need to create a new page to list the beers in the application. For that, we’re going to use Ionic CLI to generate pages with command
ionic generate page beers
Open pages/beers/beers.html
and add the code which define the beers list to display.
<ion-content padding>
<ul>
<li>
<span>Affligem Blond</span>
<p>
Affligem Blonde, the classic clear blonde abbey ale,
with a gentle roundness and 6.8% alcohol. Low on bitterness,
it is eminently drinkable.
</p>
</li>
<li>
<span>Affligem Tripel</span>
<p>
The king of the abbey beers. It is amber-gold and pours with a
deep head and original aroma,
delivering a complex, full bodied flavour. Pure enjoyment! Secondary
fermentation in the bottle.
</p>
</li>
</ul>
<p>Total number of beers: 2</p>
</ion-content>
Now, we need to add this new page to the application. Open app/app.component.ts
and add after the import of the HomePage
import { BeersPage } from '../pages/beers/beers';
Open app/app.module.ts
and add after the import of the HomePage
import { BeersPage } from '../pages/beers/beers';
Add the BeersPage in declarations
and entryComponents
Save changes.
Menu
First, we’re going to add the menu to the app. For that, open app/app.html
and replace code with this code
<ion-menu [content]="content">
<ion-header>
<ion-toolbar>
<ion-title>Menu</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-list>
<button menuClose ion-item *ngFor="let p of pages" (click)="openPage(p)">
</button>
</ion-list>
</ion-content>
</ion-menu>
<!-- Disable swipe-to-go-back because it's poor UX to combine STGB with side menus -->
<ion-nav [root]="rootPage" #content swipeBackEnabled="false"></ion-nav>
Now, we need to add the reference to the menu in the application pages. Open pages/beers/beers.html
and add this code at the beginning of the page
<ion-header>
<ion-navbar>
<button ion-button menuToggle>
<ion-icon name="menu"></ion-icon>
</button>
<ion-title>Ionic 2 Beers Gallery</ion-title>
</ion-navbar>
</ion-header>
Do the same for pages/home/home.html
.
Open app/app.component.ts
and add this code in the constructor
this.pages = [
{ title: 'Home', component: HomePage },
{ title: 'Beers list', component: BeersPage }
];
And add
openPage(page) {
// Reset the content nav to have just this page
// we wouldn't want the back button to show in this scenario
this.nav.setRoot(page.component);
}
Save changes and run the app. It should look this way.
Fetching data from Beer catalog
In the first step, we load beers catalog in a static page. Now, we load this catalog from the controller.
First, open pages/beers/beers.ts
and add the code in the constructor
this.beers = [
{
alcohol: 8.5,
name: 'Affligem Tripel',
description: 'The king of the abbey beers. It is amber-gold and pours with a deep head and original aroma, delivering a complex, full bodied flavour. Pure enjoyment! Secondary fermentation in the bottle.'
},
{
alcohol: 9.2,
name: 'Rochefort 8',
description: 'A dry but rich flavoured beer with complex fruity and spicy flavours.'
},
{
alcohol: 7,
name: 'Chimay Rouge',
description: 'This Trappist beer possesses a beautiful coppery colour that makes it particularly attractive. Topped with a creamy head, it gives off a slight fruity apricot smell from the fermentation. The aroma felt in the mouth is a balance confirming the fruit nuances revealed to the sense of smell. This traditional Belgian beer is best savoured at cellar temperature.'
}
];
Then open pages/beers/beers.html
and modify the display list construction like this
<ul>
<li *ngFor="let beer of beers">
<span></span>
<p>
</p>
</li>
</ul>
<p>Total number of beers: </p>
Translate labels
Now the application needs to be translated for users all around the world. For this, add ng2-translate
library with this command and update bower configuration
npm install ng2-translate --save
Open app/app.component.ts
file and add
import { TranslateService } from 'ng2-translate/ng2-translate';
and add parameter to the constructor
constructor(translate: TranslateService, public platform: Platform) {
and set default language in the constructor
// set default language
translate.setDefaultLang('en');
translate.use(translate.getBrowserLang());
Create new files that contain translated labels in a new directory i18n
in assets
directory, for example en.json
{
"menu" : "Menu",
"home" : "Home",
"beersList" : "List of beers",
"beerGallery" : "Ionic Beer Gallery",
"beersNumbers" : "Total number of beers",
"content" : "Welcome!",
"ionicBeers" : "Ionic Beers"
}
Update pages/home/home.html
file to translate labels
content
Change all labels in *.html
files to translate labels
Order and search in list
Sometimes the list need to be ordered. Angular do this with easy directives.
We need to create a new provider with Ionic CLI
ionic g provider Data
Open app/app.module.ts
and add
import { Data } from '../providers/data';
In @NgModule
add the definition of the provider
providers: [{provide: ErrorHandler, useClass: IonicErrorHandler}, Data]
Open providers/data.ts
file and add in the Data class
beers: Array<{alcohol: number, name: string, description: string}>;
constructor(public http: Http) {
this.beers = [
{
alcohol: 8.5,
name: 'Affligem Tripel',
description: 'The king of the abbey beers. It is amber-gold and pours with a deep head and original aroma, delivering a complex, full bodied flavour. Pure enjoyment! Secondary fermentation in the bottle.'
},
{
alcohol: 9.2,
name: 'Rochefort 8',
description: 'A dry but rich flavoured beer with complex fruity and spicy flavours.'
},
{
alcohol: 7,
name: 'Chimay Rouge',
description: 'This Trappist beer possesses a beautiful coppery colour that makes it particularly attractive. Topped with a creamy head, it gives off a slight fruity apricot smell from the fermentation. The aroma felt in the mouth is a balance confirming the fruit nuances revealed to the sense of smell. This traditional Belgian beer is best savoured at cellar temperature.'
}
];
}
filterBeers(searchTerm) {
return this.beers.filter((beer) => {
return beer.name.toLowerCase().indexOf(searchTerm.toLowerCase()) > -1;
});
}
In beers/beers.ts
file import the provider Data
import { Data } from '../../providers/data';
and replace the beers definition
searchTerm: string = '';
beers: any;
listSize: number;
Remove the initialization of the beers list in the constructor and define the filtered function
setFilteredBeers() {
this.beers = this.dataService.filterBeers(this.searchTerm);
}
Open beers/beers.html
and add lines to filter beers
<div>
<ion-searchbar [(ngModel)]="searchTerm" (ionInput)="setFilteredBeers()"></ion-searchbar>
</div>
Replace the code for the list size
<p>beersNumbers : </p>
Loading beers from JSON files
Open providers/data.ts
and replace the code in the constructor
this.getJsonData().subscribe(data => {
this.beers = data;
});
and create a new function
getJsonData() {
return this.http.get('../assets/beers/beers.json').map(res => res.json());
}
Open pages/beers/beers.ts
and create a new function
getData() {
this.dataService.getJsonData().subscribe(result => {
this.beers = result;
this.listSize = this.beers.length;
});
}
and add the call of the function in ionViewDidLoad
function.
Getting the beers pics
We can also extract the image URL from the received JSON and then we add the image to the pages/beers/beers.html
:
<a href="#/assets/beers/">
<ion-img src="" class="thumb-img"></ion-img>
</a>
<div class="thumb">
<a href="#/beers/"></a>
<p></p>
</div>
Let’s display the beer description
On the beers list listBeers.html
, add action on beer name and on picture
<img ng-src="" class="thumb-img" ng-click="openModal(beer.id)">
<a href="" ng-click="openModal(beer.id)"></a>
Now create new file beer-detail.html
to display beer description
<ion-modal-view>
<ion-header-bar align-title="left" class="bar-calm">
<h1 class ="title"></h1>
<button class="button icon ion-close" ng-click="closeModal()"></button>
</ion-header-bar>
<ion-content>
<img ng-src="" class="beer">
<p class="description"></p>
<ul class="beer-thumbs">
<li>
<img ng-src="" ng-click="setImage(beer.img)">
</li>
<li>
<img ng-src="" ng-click="setImage(beer.label)">
</li>
</ul>
<ul class="specs">
<li>
<dl>
<dt>alcoholContent</dt>
<dd></dd>
</dl>
</li>
<li>
<dl>
<dt>brewery</dt>
<dd></dd>
</dl>
</li>
<li>
<dl>
<dt>availability</dt>
<dd></dd>
</dl>
</li>
<li>
<dl>
<dt>style</dt>
<dd></dd>
</dl>
</li>
<li>
<dl>
<dt>serving</dt>
<dd></dd>
</dl>
</li>
</ul>
</ion-content>
</ion-modal-view>
Define modal to display beer detail in controllers.js
$ionicModal.fromTemplateUrl('templates/beer-detail.html', {
scope: $scope,
animation: 'slide-in-up'
}).then(function(modal) {
$scope.beerModal = modal;
});
Load beer definition from JSON file in controllers.js
$scope.openModal = function(beerId) {
$http.get('beers/' + beerId + '.json').success(function(data) {
$scope.beer = data;
$scope.mainImg = $scope.beer.img;
$scope.setImage = function(img) {
$scope.mainImg = img;
}
});
myBeerId = beerId;
$scope.beerModal.show();
};
Hide modal when click on close button in controllers.js
$scope.closeModal = function() {
$scope.beerModal.hide();
};
$scope.$on('$destroy', function() {
$scope.beerModal.remove();
});