Angular 2 Component Data Binding with Sample Whiskey Application

WRITTEN BY GARETH DUNNE @JSDIARIES

In our previous Angular 2 posts, we concentrated on the setup and structure of our application. You can find that here.

If you are already familiar with component data binding you can always check out latest Angular 2 practices in ngBook.

Now, we are moving onto something a little more visually apparent using some sample Whiskey data.

Our site looks something like this:

whiskey-list
whiskey-list

Here is our mock whiskey catalog used as the data for displaying the 3 different whiskeys.

whiskey-catalogue.ts

import { Whiskey } from './whiskey';


export const WHISKEY_CAT = [
    new Whiskey("Jameson", 22 , 'Florida', 'Jacksonville', 'An Oak that grew on the bank of a river was uprooted by a severe gale of wind, and thrown across the stream.', 'images/clontarf-whiskey.jpg'),
     new Whiskey(" Wood Emerald", 26 , 'Glasgow', 'Jacksonville', 'An Oak that grew on the bank of a river was uprooted by a severe gale of wind, and thrown across the stream.', 'images/kilbeggan_whiskey.jpg'),
      new Whiskey("Paddys", 42 , 'Ireland', 'Galway', 'his blend has always been a mix of both pot still whiskeys, grain and also some single malt.Paddy is best described as unpretentious and friendly,', 'images/clontarf-whiskey.jpg'),
] 

Whiskey.ts

 export class Whiskey {
    whiskeyName: string = 'Jameson';
    price: number = 22;
    origin: string = "Florida";
    distillery : string = "Jacksonville";
    desc : string = "An Oak that grew on the bank of a river was uprooted by a severe gale of wind, and thrown across the stream.";
    imgsrc : string = "images/clontarf-whiskey.jpg";


constructor(whiskeyName: string, price: number, origin : string, distillery : string, description : string, imgsrc : string)
{
    this.whiskeyName = whiskeyName;
    this.price = price;
    this.origin = origin;
    this.distillery = distillery;
    this.desc = description;
    this.imgsrc = imgsrc;
}

} 

We want to display these whiskeys from our mock data in our whiskey-list.component.

whiskey-list-component.ts

import { Component, OnInit } from '@angular/core';
import { WHISKEY_CAT } from '../whiskey-catalogue';
import { Whiskey } from '../../shared/whiskey/Whiskey';
import { RestAPIService } from '../../shared/restapi.service';
@Component({
  selector: 'app-whiskey-list',
  templateUrl: './whiskey-list.component.html',
  styleUrls: ['./whiskey-list.component.css']
})
export class WhiskeyListComponent implements OnInit {
  whiskeyCat: Whiskey[];
  selectedWhiskey : Whiskey;

  constructor(private apiService: RestAPIService) { }

  ngOnInit() {
    this.whiskeyCat = this.apiService.getWhiskeyCat();
  }

  setSelectedWhiskey(selectedWhiskey : Whiskey)
  {
    this.selectedWhiskey = selectedWhiskey;
  }
}

 

This component contains a class that initializes our imported Whiskey and WHISKEY_CAT classes.

From here, we want to be able to click on one of those whiskeys displayed to focus on it and display it in bigger dimension right above it.

We then want the clicked whiskey to appear inside a different div in a completely different component (whiskey.details.component).

This would be considered common practice in a typical website displaying a product catalog. They would have a style transition that highlighted one products chosen in a list by the user.

When understood, this should give you a good feel of how data flows down through components in an application. It will also show you how to utilize directives, while also showing you how the process behind how an event is handled in Angular 2.

Exposing selected data.

Our variable selectedWhiskey is assigned to a TypeScript export of a our Whiskey object. Just from being declared inside the WhiskeyListComponent class, selectedWhiskey is already exposed and accessible from our whiskey.list.component html file. We can bind our selected whiskey properties to our UI. In this case image src, whiskey name and description.

But how will this component get access to the information from the clicked on whiskey? We need our application to take the properties of the item clicked on and to then pass it to our whiskey.details.component.

The @Input() decorator was added to our whiskey-details.component . @Input allows us to define an input for a given component. So our selected whiskey value can be put in as an data attribute and the value of it flows down to our component.

  

This is an attribute binding that passes down the value of the selected whiskey

We need to create a function to set our selected whiskey.


  setSelectedWhiskey(selectedWhiskey : Whiskey)
  {
  this.selectedWhiskey = selectedWhiskey;
  }

whiskey-list-details.component

 

{{selectedWhiskey.whiskeyName}}

{{selectedWhiskey.desc}}
We also use the NgIf directive to ensure this UI whiskey properties are generated only when sharedWhiskey has an actual value and is not undefined.

whiskey-list.component

 

{{whiskey.whiskeyName}}

${{whiskey.price}}

{{whiskey.description}}


But what else is going on here? Well the object passed in our setSelectedWhiskey click method is referring to the singular whiskey at the current index using our *ngFor looping directive.

So when our *ngFor directive iterates through whiskeys in our whiskeyCat, whiskey is always referring to the current whiskey. When clicked the current whiskey is passed down to our whiskey-list-details.component.

We should now be able to see the selected whiskey in a different div from a our whiskey-list-details.component.

This is a very handy way of sharing a specific piece of data to another component. This is just one practical use of data sharing between components.

There are many other uses that I won't cover here but make sure you check our resources page for any relevant reading material on Angular 2.

http://jsdiaries.com/resources/

So to reflect back, the @Input decorator tells Angular to treat selectedWhiskey as an input binding.

  export class WhiskeyDetailsComponent {
  @Input()
  selectedWhiskey: Whiskey;
} 

 

This means that it has access to event data. Once this is bound to our nested component, our nested component can now receive event data for example in this case its the selected whiskey clicked.

I won't go too far into how decorators work in general. You can get pretty far not understanding what they actually are doing past the layer of abstraction that Angular provides us.

In the case of selected Whiskey we have specified it as an input binding.

There are many different types of decorators and you should really look at Todd Motto's post to further unmask some of their mysteries.

https://toddmotto.com/angular-decorators

Overall, this is a simple example of how you would use Angular 2’s data flow decorators to control the flow of data to a nested component.

In essence, they are just a function that provides itself with instructions on what type of information it should expose it's targeted variable.

Conclusion

This is a very basic version of this Angular 2 Whiskey application there isn’t a whole lot functionality here apart from the displaying the selected whiskey.

However, I plan to incrementally add bits functionality as I learn more about Angular 2 and its various techniques. I'm finding it be a very solid framework to be working with and something that I'm trying to specializing in.

The combination of TypeScript decorators and Angular directives really opens up the possibilities of your UI interacting with your data in different ways for creating feature rich applications.

Early GIT version

Here is very an early draft of this sample application for reference.

Proudly published with Gatsby