<!DOCTYPE html>
<html>

  <head>
    <link data-require="bootstrap-css@*" data-semver="3.3.1" rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha/css/bootstrap.min.css" />
    <link href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap-glyphicons.css" rel="stylesheet">
    <script src="http://cdn.rawgit.com/google/traceur-compiler/90da568c7aa8e53ea362db1fc211fbb4f65b5e94/bin/traceur-runtime.js"></script>
    <script src="http://cdnjs.cloudflare.com/ajax/libs/systemjs/0.18.4/system.js"></script>
    <script src="config.js"></script>
    <!-- Angular2 import -->
    <script src="http://code.angularjs.org/2.0.0-alpha.42/angular2.dev.js"></script>
    <script>
      //bootstrap the Angular2 application
      System.import('app').catch(console.log.bind(console));
    </script>
  </head>

  <body>
    <my-app></my-app>
  </body>

</html>
import {Component, View, bootstrap} from 'angular2/angular2';

import {NgbRating} from './rating';

@Component({
  selector: 'my-app'
})
@View({
  templateUrl: 'src/main.html',
  directives: [NgbRating]
})
export class MyApp {
  private rate: number;
  private rate2: number;
  private customRate: number;
  private customRate2: number;
  private isReadonly: boolean = true;
  
  constructor() {
    this.rate = 7;
    this.rate2 = 3;
    this.customRate = this.rate2 * 10;
    this.customRate2 = 0.4;
  }
  
  onRate(value) {
    this.customRate = value * 10;
  }
  
  onRate2(value) {
    this.customRate2 = value / 5;
  }
}

bootstrap(MyApp);
System.config({
  defaultJSExtensions: true,
  transpiler: 'typescript',
  typescriptOptions: {
    emitDecoratorMetadata: true
  },
  map: {
    typescript: 'https://cdn.rawgit.com/robwormald/9883afae87bffa2f4e00/raw/8bca570a696c47a4f8dd03a52c98734676e94cea/typescript.js',
    'rx.all': 'https://cdnjs.cloudflare.com/ajax/libs/rxjs/3.1.1/rx.all.js',
  },
  paths: {
    app: 'src'
  },
  packages: {
    app: {
      main: 'main.ts',
      defaultExtension: 'ts',
    }
  }
});
import {Component, Input, Output, NgFor, EventEmitter, OnInit} from 'angular2/angular2';

@Component({
  selector: 'ngb-rating',
  template: `
    <span tabindex="0" (mouseleave)="reset()" aria-valuemin="0" [attr.aria-valuemax]="max" [attr.aria-valuenow]="rate">
      <template ng-for #r [ng-for-of]="range" #index="index">
        <span class="sr-only">({{ index < rate ? '*' : ' ' }})</span>
        <i class="glyphicon {{index < rate ? 'glyphicon-star' : 'glyphicon-star-empty'}}" (mouseenter)="enter(index + 1)" (click)="update(index + 1)" [title]="r.title" [attr.aria-valuetext]="r.title"></i>
      </template>
    </span>
  `,
  directives: [NgFor]
})
export class NgbRating implements OnInit {
  @Input() private max: number = 10;
  @Input() private rate: number;
  @Input() private readonly: boolean;
  @Output() private rateChange: EventEmitter = new EventEmitter();
  @Output() private hover: EventEmitter = new EventEmitter();
  @Output() private leave: EventEmitter = new EventEmitter();
  private oldRate: number;
  private range: Array<any>;

  onInit() {
    this.oldRate = this.rate;
    this.range = this.buildTemplateObjects();
  }

  buildTemplateObjects(): Array<any> {
    let range = [];
    for (let i = 1; i <= this.max; i++) {
      range.push({title: i});
    }
    return range;
  }

  enter(value: number): void {
    if (!this.readonly) {
      this.rate = value;
    }
    this.hover.next(value);
  }

  reset(): void {
    this.leave.next(this.rate);
    this.rate = this.oldRate;
  }

  update(value: number): void {
    if (!this.readonly) {
      this.oldRate = value;
      this.rate = value;
      this.rateChange.next(value);
    }
  }
}
<ngb-rating [(rate)]="rate" (hover)="overStar = $event" (leave)="overStar = null" aria-labelledby="rating1"></ngb-rating>

<pre style="margin:15px 0;" class="card card-block card-header">Rate: <b>{{rate}}</b> - Hovering over: <b>{{overStar || "none"}}</b></pre>

<ngb-rating [rate]="rate2" [readonly]="isReadonly" (rate-change)="onRate($event)" aria-labelledby="rating2"></ngb-rating>

<pre style="margin:15px 0;" class="card card-block card-header">Custom rate: <b>{{customRate}}</b> - Readonly is: <i>{{isReadonly}}</i></pre>

<ngb-rating [rate]="2" max="5" (rate-change)="onRate2($event)" aria-labelledby="rating3"></ngb-rating>

<pre style="margin:15px 0;" class="card card-block card-header">Custom rate: <b>{{customRate2}}</b></pre>