I have a buddy who’s pretty bad at keeping track of his diet, and I’m pretty sure I know why. His wife showed me the 8.5″x5.5″ 7pt. font print-out of their weekly diet plan, complete with 4mm-wide checkboxes, and I had the immediate urge to help them out with a super-simple app that accomplished the same thing, but lived in a pretty interface on their phones. So, for the past few days I’ve spent an hour here, an hour there doing just that. In the end, they get a better way to track their diets, and I get my first Ionic 2 app. I’d say that’s a good deal.

This post will focus on the food-group progress ticker component that I built to facilitate incrementing the intake of each food group in the diet plan. It uses some Ionicons, matched with some Ionic directives, and some use of the Input and Output decorators in Angular 2.

Setting Up the Ionic App

I’ll gloss over some high-level details for those who haven’t yet checked out the Ionic 2 docs, so as to give context for the construction I’m working with.

First and foremost, if you haven’t already, you can install Ionic 2 by running the following in your command line:

$ sudo npm install -g ionic@beta

Once everything’s in, you can run this command to get your app off the ground:

$ ionic start dashDiet --ts --v2

That’ll set up a nice Ionic 2 app, complete with support for Angular 2’s TypeScript syntax.

At this point I’ll dart off into an overview of where things stand in my app as of the start of the ticker component. If you want to know more about what you’re looking at, you can check out my post detailing my initial tour through the Ionic 2 framework.

The Data Structure

The diet in question is the Dash Diet, which tracks targeted intake of specific food groups. I don’t know about you, but my favorite kinds of apps to work on are the ones that have all of the data models mapped out for you. And this one does, complete with mock data to get me started.

I have two interfaces to start, a FoodGroupInterface for each food group, and a DayInterface for the data that falls within each day:

// in app/models/food-group.interface.ts
export interface FoodGroupInterface {
    title: string,
    description: string,
    target: number,
    targetDescription: string,
    progress: number

// in app/models/day.interface.ts
export interface DayInterface {
    date: Date,
    intake: FoodGroupInterface[]

And here’s the mock data that I’m working with:

import {DayInterface} from '../models/day.interface';
import {FoodGroupInterface} from '../models/food-group.interface';

export const Data: DayInterface = {
    date: new Date(),
    intake: [
            title: 'Vegetables',
            description: '1/2 cup cooked veggies, 1 cup leafy greens and raw veggies, 1/2 cup vegetable juice',
            target: 5,
            targetDescription: 'something',
            progress: 4

That’s right, an array with one entry. At this point, nothing special, but it can grow to include all of the food groups he’s supposed to take in during his day. Since we’re building the ticker component that lives on the food group, one should do nicely.

Component Hierarchy

The next step is to lay out my components.

The ‘Today’ Page

I’ve got my top-level page, where my data is loaded. That will loop over all of the food groups that will live in the intake array, and display each food group with a description, target intake, and progress ticker.

<food-group *ngFor="#item of data.intake" [foodGroup]="item"></food-group>

I won’t go into detail on this, since it’s a pretty straightforward template looping over the intake array using an *ngFor. The only thing worth noting is that all of my data loads at this level, and populates downward.

The Food Group Component

Now we’re into the good stuff. Each food group component will have it’s own progress tracker, which is where we’ll click individual buttons to increment or decrement progress towards a goal of ingesting certain foods. Or whatever else a ticker may be applied to in your app.

The Template

The template is a basic card layout, using some simple Ionic directives to give it that native look and feel:

                <ticker [progress]="foodGroup.progress" [target]="foodGroup.target" item-right (progressChange)="updateFoodGroup($event)"></ticker>

The most important part of this template is the <ticker> component. Aside from the item-right Ionic directive, which displays the element in the right column of the layout, I have three important things going on there:

  • I set the progress data-bound attribute, which displays and tracks the intake progress in a particular food group. That’s what the ticker will manipulate the data in the progress field.
  • I also set the target, which is a static value that I’m going to show next to the ticker. That’s optional, but I’m including it for clarity in diet tracking.
  • Last we have a custom event handler. That’s going to handle the click event by updating the model baed on whatever event data was emitted. We’ll see that event handler in a second.

The Class

Similarly, the class definition isn’t all that complicated:

import {Component, Input} from 'angular2/core';
import {IONIC_DIRECTIVES} from 'ionic-framework/ionic';
import {FoodGroupInterface} from '../../../../models/food-group.interface';
import {TickerComponent} from '../ticker/ticker.component';

    selector: 'food-group',
    templateUrl: 'build/pages/current-day/components/food-group/food-group.template.html',
    directives: [TickerComponent, IONIC_DIRECTIVES],

export class FoodGroupComponent {
    @Input() foodGroup: FoodGroupInterface;
    public updateFoodGroup(e) {
        this.group.progress = this.group.progress + e;

Let’s take a look at what’s going on here:

  • I take in the Component and Input classes from Angular 2 Core, since those will help me build out the functionality I’m looking for.
  • I bring in IONIC_DIRECTIVES since I’m using layout-based directives to build my view.
  • I source the interface I’m refrencing as I build my data model.
  • I reference the TickerComponent that I’ll show you in a second, which, as you can see in the template, is its own component
  • Next I define the Component decorator, mostly straightforward.
  • Finally I define the FoodGroupComponent class, which declares a data-bound foodGroup attribute, and a method that we’ll use to handle events in the template. The progress field on this data object will increase by the value passed in the event by the Ticker, which will either be a positive or a negative number.

I’m handling data changes at the Food Group level instead of at the Ticker level since, in my opinion, the ticker should be pretty stupid in order to improve reusability. All it should communicate is how many times a directional indicator was clicked. It’ll be up to the component that manages that data model to decide what to do with that click event. And in this case, we’re adding or decreasing by the individual click. But that could change depending on the data model in question.

The Ticker Component

The ticker will be made up of two buttons set on either side of a data-bound display that shows progress and target. On the left side will be a button with a minus, and on the right side, a button with a plus. Looks like this:

Screen Shot 2016-01-13 at 7.14.02 AM

Plenty of room for stylisitic improvements, but for now let’s focus on the programming.

The Template

The template is made up of two buttons with Ionic classes and icons to make them look all native:

<button clear (click)="decrement()">
    <ion-icon name="remove-circle"></ion-icon>
<span class="ticker-progress">{{progress}}/{{target}}</span>
<button clear (click)="increment()">
    <ion-icon name="add-circle"></ion-icon>

I’m using the progress and target fields to display how the dietary intake is going. I mentioned those when we were looking at the <ticker> component in the Food Group template.

I also have click events handled on the two buttons. Let’s see how those are defined.

The Class

In this class definition, I need to do three things:

  1. Capture the data that’s bound to the component via the progress and target attribute bindings
  2. Handle the click events happening on each button
  3. Send that data modifier back up the component hierarchy to the Food Group

It doesn’t take much to pull all of that off…

import {Component} from 'angular2/core';
import {IONIC_DIRECTIVES} from 'ionic-framework/ionic';
import {Input, Output, EventEmitter} from 'angular2/core';

    selector: 'ticker',
    templateUrl: 'build/pages/current-day/components/ticker/ticker.template.html',
    directives: [IONIC_DIRECTIVES]

export class TickerComponent {
    @Input() progress;
    @Input() target;
    @Output('progressChange') progressChange = new EventEmitter();

    public increment() {
        return this.progressChange.emit(1);
    public decrement() {
        return this.progressChange.emit(-1);

The first two imports arent’ very exciting, so we’ll skip over those. The third import though pulls in the Output decorator and EventEmitter class. That’s how we’ll bind out custom event to the parent component:

@Output('progressChange') progressChange = new EventEmitter();

Once we have the event set up, we can run its emit method to send data to a parent component:

return this.progressChange.emit(1);

So in the template we handle click events on the buttons, and in handling them we emit a custom event indicating what value – positive or negative – to add to the progress field in the Food Group. And that’s it!

Further Development

For my purposes, this will start off as an offline app storing to a local SqlStorage on the device. For your purposes, that data change might mean sending the data off to a backend service to be saved in a remote database. Both are topics for another day.

There are also plenty of opportunities for stylistic improvement, such as fancy animations on click events, and color-based indicators to show progress more visually. All good opportunities for further discussion another day.

One response to “Let’s Build a Ticker in Ionic 2”

  1. EDAY GONZALEZ says:

    Hi, I’ve been following this post and I have a question.

    In that…

    And here’s the mock data that I’m working with:

    import {DayInterface} from ‘../models/day.interface’;
    import {FoodGroupInterface} from ‘../models/food-group.interface’;

    export const Data: DayInterface = {
    date: new Date(),
    intake: [
    title: ‘Vegetables’,
    description: ‘1/2 cup cooked veggies, 1 cup leafy greens and raw veggies, 1/2 cup vegetable juice’,
    target: 5,
    targetDescription: ‘something’,
    progress: 4

    where the previous code have to locate (be)? Within file?