<!DOCTYPE html>
<html>
  <head>
    <title>Angular Material Plunker</title>
    
    <!-- Load common libraries -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/typescript/2.1.6/typescript.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/core-js/2.4.1/core.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/zone.js/0.7.2/zone.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.47/system.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/hammer.js/2.0.8/hammer.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/web-animations/2.2.2/web-animations.min.js"></script>


    <!-- Configure SystemJS -->
    <script src="systemjs.config.js"></script>

    <script>
      System
        .import('main.ts')
        .catch(console.error.bind(console));
    </script>
    
    <!-- Load the Angular Material stylesheet -->
    <link href="https://rawgit.com/angular/material2-builds/master/prebuilt-themes/indigo-pink.css" rel="stylesheet">
    <style>body { font-family: Roboto, Arial, sans-serif; margin: 0 }</style>


  </head>

  <body class="mat-app-background">
    <material-app>Loading the Angular Material App...</material-app>
  </body>

</html>

<!--
  Copyright 2017 Google LLC. All Rights Reserved.
  Use of this source code is governed by an MIT-style license that
  can be found in the LICENSE file at http://angular.io/license
-->
import {Component} from '@angular/core';
import {bootstrap} from '@angular/platform-browser-dynamic';
import {VERSION} from '@angular/material';

@Component({
  selector: 'material-app',
  templateUrl: 'app.component.html'
})
export class AppComponent {
  
    private version = VERSION;

    items = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
    selected = [];

    toggle(item): void {
        // if (this.isDisabled(item)) {
        //     return;
        // }

        const idx = this.selected.indexOf(item);
        if (idx > -1) {
            this.selected.splice(idx, 1);
        } else {
            this.selected.push(item);
        }

        console.log("toggle (after)", this.selected);
    }

    isIndeterminate(): boolean {
        return (this.selected.length > 0 && this.selected.length < this.items.length);
    }

    exists(item): boolean {
        return this.selected.indexOf(item) > -1;
    }

    isChecked(): boolean {
        return this.selected.length === this.items.length;
    }

    isDisabled(item): boolean {
        return item === 4;
    }

    toggleAll(): void {
        if (this.selected.length === this.items.length) {
            this.selected = [];
        } else if (this.selected.length === 0 || this.selected.length > 0) {
            this.selected = this.items.slice(0);
        }
    }

}

/*
  Copyright 2017 Google LLC. All Rights Reserved.
  Use of this source code is governed by an MIT-style license that
  can be found in the LICENSE file at http://angular.io/license
 */
<mat-toolbar color="primary">
  Nested checkboxes
</mat-toolbar>

<div style="padding: 7px">
  
  <my-checkbox [checked]="isChecked()" [indeterminate]="isIndeterminate()" [label]="isChecked() ? 'Un-select All' : 'Select All'" (onChange)="toggleAll($event)"></my-checkbox>
  <div *ngFor="let item of items">
      <my-checkbox (click)="toggle(item)" [checked]="exists(item)" [disabled]="isDisabled(item)" label="{{item}}"></my-checkbox>
  </div>

  <hr>
  <p>Version: {{version.full}}</p>
  
</div>

<!--
  Copyright 2017 Google LLC. All Rights Reserved.
  Use of this source code is governed by an MIT-style license that
  can be found in the LICENSE file at http://angular.io/license
-->
/** Add Transpiler for Typescript */
System.config({
  transpiler: 'typescript',
  typescriptOptions: {
    emitDecoratorMetadata: true
  },
  packages: {
    '.': {
      defaultExtension: 'ts'
    },
    'vendor': {
      defaultExtension: 'js'
    }
  }
});

System.config({
  map: {
    'main': 'main.js',
    
    // Angular specific mappings.
    '@angular/core': 'https://unpkg.com/@angular/core/bundles/core.umd.js',
    '@angular/common': 'https://unpkg.com/@angular/common/bundles/common.umd.js',
    '@angular/common/http': 'https://unpkg.com/@angular/common/bundles/common-http.umd.js',
    '@angular/compiler': 'https://unpkg.com/@angular/compiler/bundles/compiler.umd.js',
    '@angular/animations': "https://unpkg.com/@angular/animations/bundles/animations.umd.js",
    '@angular/animations/browser': 'https://unpkg.com/@angular/animations/bundles/animations-browser.umd.js',
    '@angular/http': 'https://unpkg.com/@angular/http/bundles/http.umd.js',
    '@angular/forms': 'https://unpkg.com/@angular/forms/bundles/forms.umd.js',
    '@angular/router': 'https://unpkg.com/@angular/router/bundles/router.umd.js',
    '@angular/platform-browser': 'https://unpkg.com/@angular/platform-browser/bundles/platform-browser.umd.js',
    '@angular/platform-browser/animations': 'https://unpkg.com/@angular/platform-browser/bundles/platform-browser-animations.umd.js',
    '@angular/platform-browser-dynamic': 'https://unpkg.com/@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js',
    
    '@angular/material': 'https://rawgit.com/angular/material2-builds/master/bundles/material.umd.js',
    '@angular/cdk': 'https://rawgit.com/angular/cdk-builds/master/bundles/cdk.umd.js',

    // CDK Secondary entry points
    '@angular/cdk/a11y': 'https://rawgit.com/angular/cdk-builds/master/bundles/cdk-a11y.umd.js',
    '@angular/cdk/accordion': 'https://rawgit.com/angular/cdk-builds/master/bundles/cdk-accordion.umd.js',
    '@angular/cdk/bidi': 'https://rawgit.com/angular/cdk-builds/master/bundles/cdk-bidi.umd.js',
    '@angular/cdk/coercion': 'https://rawgit.com/angular/cdk-builds/master/bundles/cdk-coercion.umd.js',
    '@angular/cdk/keycodes': 'https://rawgit.com/angular/cdk-builds/master/bundles/cdk-keycodes.umd.js',
    '@angular/cdk/observers': 'https://rawgit.com/angular/cdk-builds/master/bundles/cdk-observers.umd.js',
    '@angular/cdk/platform': 'https://rawgit.com/angular/cdk-builds/master/bundles/cdk-platform.umd.js',
    '@angular/cdk/portal': 'https://rawgit.com/angular/cdk-builds/master/bundles/cdk-portal.umd.js',
    '@angular/cdk/rxjs': 'https://rawgit.com/angular/cdk-builds/master/bundles/cdk-rxjs.umd.js',
    '@angular/cdk/table': 'https://rawgit.com/angular/cdk-builds/master/bundles/cdk-table.umd.js',
    '@angular/cdk/testing': 'https://rawgit.com/angular/cdk-builds/master/bundles/cdk-testing.umd.js',
    '@angular/cdk/overlay': 'https://rawgit.com/angular/cdk-builds/master/bundles/cdk-overlay.umd.js',
    '@angular/cdk/scrolling': 'https://rawgit.com/angular/cdk-builds/master/bundles/cdk-scrolling.umd.js',
    '@angular/cdk/collections': 'https://rawgit.com/angular/cdk-builds/master/bundles/cdk-collections.umd.js',
    '@angular/cdk/stepper': 'https://rawgit.com/angular/cdk-builds/master/bundles/cdk-stepper.umd.js',
    '@angular/cdk/layout': 'https://rawgit.com/angular/cdk-builds/master/bundles/cdk-layout.umd.js',

    // Third party libraries
    'tslib': 'https://unpkg.com/tslib@1.7.1',
    'rxjs': 'https://unpkg.com/rxjs@5.5.2',
  },
  packages: {
    // Thirdparty barrels.
    'rxjs': { main: 'index' },
    'rxjs/operators': {main: 'index'},
  }
});

/*
  Copyright 2017 Google LLC. All Rights Reserved.
  Use of this source code is governed by an MIT-style license that
  can be found in the LICENSE file at http://angular.io/license
 */
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
import {BrowserModule} from '@angular/platform-browser';
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
import {NgModule} from '@angular/core';
import {CommonModule} from '@angular/common';
import {HttpClientModule} from '@angular/common/http';
import {AppComponent} from './app.component';
import {CdkTableModule} from '@angular/cdk/table'
import {OverlayModule} from '@angular/cdk/overlay';
import {MatToolbarModule} from '@angular/material';
import {MyCheckboxModule} from './my-checkbox.module';

/**
 * NgModule that includes all Material modules that are required to serve 
 * the Plunker.
 */
@NgModule({
  exports: [
    MatToolbarModule,
    MyCheckboxModule
  ]
})
export class PlunkerMaterialModule {}

@NgModule({

  imports: [
    BrowserModule,
    CommonModule,
    HttpClientModule,
    PlunkerMaterialModule,
    BrowserAnimationsModule
  ],

  declarations: [AppComponent],
  bootstrap: [AppComponent],
  providers: []
})
export class PlunkerAppModule {}

platformBrowserDynamic().bootstrapModule(PlunkerAppModule);

/*
  Copyright 2017 Google LLC. All Rights Reserved.
  Use of this source code is governed by an MIT-style license that
  can be found in the LICENSE file at http://angular.io/license
 */
<mat-checkbox disableRipple
              class="my-checkbox"
              [class.checked]="innerValue || checked"
              [class.disabled]="disabled"
              [class.indeterminate]="indeterminate"
              [ngModel]="innerValue"
              (ngModelChange)="modelChange($event)"
              [disabled]="disabled"
              [checked]="checked"
              [indeterminate]="indeterminate"
              (change)="doChange($event)">
    {{ label }}
</mat-checkbox>
import {CommonModule} from "@angular/common";
import {NgModule} from "@angular/core";
import {MatCheckboxModule} from "@angular/material";
import {FormsModule} from "@angular/forms";
import {MyCheckboxComponent} from "./my-checkbox.component";

@NgModule({
    exports: [
        MyCheckboxComponent,
    ],
    imports: [
        MatCheckboxModule,
        FormsModule,
        CommonModule,
    ],
    declarations: [
        MyCheckboxComponent,
    ]
})
export class MyCheckboxModule {
}
import {Component, EventEmitter, Input, Output} from "@angular/core";

@Component({
    selector: "my-checkbox",
    templateUrl: "./my-checkbox.component.html"
})
export class MyCheckboxComponent {

    innerValue: boolean;

    @Input() value: any;
    @Input() label: string;
    @Input() disabled: boolean;
    @Input() checked: boolean;
    @Input() indeterminate: boolean;
    @Input() trueValue: any = true;
    @Input() falseValue: any = false;
    @Output() valueChange = new EventEmitter();
    @Output() onChange = new EventEmitter();

    ngOnInit() {
        this.setInnerValue();
    }

    ngOnChanges() {
        this.setInnerValue();
    }

    doChange($event: MatCheckboxChange) {
        this.onChange.emit($event);
    }

    modelChange($event: MatCheckboxChange) {
        this.innerValue = !!$event;
        this.valueChange.emit($event ? this.trueValue : this.falseValue);
    }

    private setInnerValue() {
        this.innerValue = (this.value === this.trueValue);
    }

  
}