Migrating Youtube-list Component in Angular 2 Using NgFor

DZone 's Guide to

Migrating Youtube-list Component in Angular 2 Using NgFor

Previously, I wrote about the migration process of a component based on Angular 1.x and ES2015. Since then, I've continued migrating Echoes Player to Angular 2. In this post, I'm sharing the migration process of the youtube-list component which uses the youtube-media component, as well as implements a smart component with Angular 2.

· Web Dev Zone ·
Free Resource

In a recent article, I wrote about the migration process of a component that is based on Angular 1.x and ES2015. Since then, I've continued migrating Echoes Player to Angular 2. In this post, I'm sharing the migration process of the youtube-list component which uses the youtube-media component, as well as implements a smart component with Angular 2.

The Youtube-list Component

The goal for this process was to reuse the recent youtube-media component and create a youtube-list component. Echoes Player's main feature is displaying a list of youtube videos like the following:

Screen Shot 2016-01-29 at 11.18.58 AM

The Angular 1.x ES2015 implementation of youtube-list is a core/component element. It is a relatively minimal component which reuse the youtube-media component. The template uses "ng-repeat" to render a list of videos:

      ng-repeat="video in vm.videos track by $index"

This is the directive definition:

import template from './youtube-list.tpl.html';

// Usage:
//<youtube-list videos on-select="func(video)" on-queue="func(video)"></youtube-list>
/* @ngInject */
export default function youtubeList() {
var directive = {
  restrict: 'E',
  replace: true,
  scope: {
    videos: '=',
    onSelect: '&',
    onQueue: '&',
    onAdd: '&'
  bindToController: true,
  controllerAs: 'vm',
  controller: class YoutubeList {
    constructor () {}

    playSelectedVideo (video){
    this.onSelect({ video });

    queueSelectedVideo (video) {
    this.onQueue({ video });

    add (video) {
    this.onAdd({ video });
  return directive;

The Angular 2 Youtube-list Component

The result of this component in Angular 2 is not so far from its Angular 1.x version. However, the migration process of this component involves few points to consider.

Importing Relevant Dependencies

With Angular 2, each dependancy must be defined. That includes:

  1. Angular 2's built in directives: NgFor (instead of ng-repeat)
  2. The youtube-media component
  3. Angular 2's annotations & docorators (@Component, @Input etc..)

Let's import all of these:

import { Component, EventEmitter, Input, Output } from 'angular2/core';
import { NgFor } from 'angular2/common';
import { YoutubeMedia } from '../youtube-media/youtube-media';

Note: "NgFor" is the new "ng-repeat" in Angular 2. More on that below.

Define The Component and Its Dependencies

This code defines how the youtube-list component will be used, its template, its input, and which directives it consumes.

  selector: 'youtube-list',
  template: require('./youtube-list.html'),
  inputs: [
  directives: [NgFor, YoutubeMedia ]

Notice how "NgFor" is injected to this component's directives array. If it's not defined as such, the Angular 2 template engine won't use it.

The Youtube-list Controller Class

The controller class in Angular 2 of this component is quite similar to its Angular 1.x version. The noticeable addition is the definition of the events that this component exposes.

export class YoutubeList {
  @Output() play = new EventEmitter();
  @Output() queue = new EventEmitter();
  @Output() add = new EventEmitter();

  constructor () {}

  playSelectedVideo (media) {

  queueSelectedVideo (media) {

  addVideo (media) {

Youtubelist Component Template

This component's template is quite simple. It repeats the youtube-media component following the "list" property.

  *ngFor="#media of list"

Lets overview the "NgFor" directive usage in this template.

First, notice that I'm using the syntactic sugar form of ngFor using the "*". It makes it easier to read (and yes, it's a valid html attribute). This "*" form is almost similar to the angular 1.x "ng-repeat". The value of this attribute is actually almost similar to the ES2015 "for of" loop, however, with little micro-syntax inside.

The "#" sign, is used to defined a local in-context variable that will be used throughout the iteration, which we can reference to in other places inside the template. In this template, the "media" variable is used to reference each time a different item is in the list array.

The exposed events: "play", "queue", and "add" pass the relevant "media" variable that was eventually clicked inside the youtube-media component.

Using the YoutubeList Component

Using this component should be simple. I designed it so I can use it like so:

<youtube-list [list]="videos" (play)="playSelectedVideo($event)"></youtube-list>

Notice how the "play" event passes the "$event" argument, which will eventually be the selected media. This is a very important point to realise. In contrary to the "ngFor", there is no reference in this context to a "video" property, but rather only to "videos" array. Referencing "media" here won't work (as we probably did in Angular 1.x).

In practice, I created a "youtube-videos" smart component—a component that is rendered without any attributes and is attached to a certain route (currently the index route). This component initiates an HTTP request call to Youtube's API and, upon response, saves the result in a "videos" property.

Final Thoughts

You can follow the full code commits of youtube-list commits in github.

Echoes Player with ng2 is an open source project that you can follow, fork, and overview at Github.

If you're still using Angular 1.x and looking to migrate in the future to Angular 2, I encourage you to start writing Angular 1.x with ES2015 and follow a style guide. You can overview the ES2015 branch of Echoes (at production http://echotu.be) to see it in action.

angular, angular2.0, components, es2015, typescript, web components

Published at DZone with permission of Oren Farhi . See the original article here.

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}