import { Component } from '@angular/core';
import { HomePage } from '../pages/home/home';

@Component({
    template: `<ion-nav [root]="rootPage"></ion-nav>`
})
export class AppComponent {
    rootPage = HomePage;
}
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { IonicApp, IonicModule } from 'ionic-angular';
import { SelectSearchableModule } from 'ionic-select-searchable';
import { AppComponent } from './app.component';
import { HomePage } from '../pages/home/home';
import { ModalPage } from '../pages/modal/modal';
import { PortService } from '../services/index';

let components = [AppComponent, HomePage, ModalPage];

@NgModule({
  imports: [
    BrowserModule,
    IonicModule.forRoot(AppComponent),
    SelectSearchableModule
  ],
  bootstrap: [IonicApp],
  declarations: components,
  entryComponents: components,
  providers: [PortService]
})
export class AppModule { }
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app.module';

const platform = platformBrowserDynamic();
platform.bootstrapModule(AppModule);
<!DOCTYPE html>
<html>
<head>
  <title>Ionic SelectSearchable Demo</title>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <script src="https://unpkg.com/core-js@2.4.1/client/shim.min.js"></script>
  <script src="https://unpkg.com/zone.js@0.6.26?main=browser"></script>
  <script src="https://unpkg.com/systemjs@0.19.40/dist/system.src.js"></script>
  <script src="systemjs.config.js"></script>
  <link href="https://unpkg.com/ionic-angular@3.1.1/css/ionic.css" rel="stylesheet">
  <link href="https://unpkg.com/ionic-select-searchable@latest/select-searchable.style.min.css" rel="stylesheet">
</head>
<body>
  <ion-app></ion-app>
  <script>
    System.import('app').catch(function(error) {
      console.error(error);
    });
  </script>
</body>
</html>
# Ionic SelectSearchable Demo
A demo app for [Ionic SelectSearchable](https://github.com/eakoriakin/ionic-select-searchable) component.
(function(global) {
  System.config({
    transpiler: 'ts',
    typescriptOptions: {
      tsconfig: true
    },
    meta: {
      typescript: {
        "exports": "ts"
      }
    },
    // Paths serve as alias.
    paths: {
      'npm:': 'https://unpkg.com/'
    },
    // Map tells the System loader where to look for things.
    map: {
      '@angular/core': 'npm:@angular/core@4.0.2/bundles/core.umd.js',
      '@angular/common': 'npm:@angular/common@4.0.2/bundles/common.umd.js',
      '@angular/compiler': 'npm:@angular/compiler@4.0.2/bundles/compiler.umd.js',
      '@angular/platform-browser': 'npm:@angular/platform-browser@4.0.2/bundles/platform-browser.umd.js',
      '@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic@4.0.2/bundles/platform-browser-dynamic.umd.js',
      '@angular/http': 'npm:@angular/http@4.0.2/bundles/http.umd.js',
      '@angular/forms': 'npm:@angular/forms@4.0.2/bundles/forms.umd.js',
      'ionic-angular': 'npm:ionic-angular@3.1.1',
      'rxjs': 'npm:rxjs@5.5.2',
      'rxjs/operators': 'npm:rxjs@5.5.2/operators/index.js',
      'ts': 'npm:plugin-typescript@5.2.7/lib/plugin.js',
      'typescript': 'npm:typescript@2.2.1/lib/typescript.js',
      'ionic-select-searchable': 'npm:ionic-select-searchable@2.1.1/index.js'
    },
    // Packages tells the System loader how to load when
    // no file name and/or no extension.
    packages: {
      rxjs: {
        defaultExtension: 'js'
      },
      'ionic-angular': {
        main: './umd/index.js',
        defaultExtension: 'js'
      },
      app: {
        main: './main.ts',
        defaultExtension: 'ts'
      },
      pages: {
        defaultExtension: 'ts'
      },
      components: {
        defaultExtension: 'ts'
      },
      services: {
        defaultExtension: 'ts'
      },
      types: {
        defaultExtension: 'ts'
      }
    }
  });
})(this);
{
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    "moduleResolution": "node",
    "sourceMap": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "removeComments": false,
    "noImplicitAny": true,
    "suppressImplicitAnyIndexErrors": true
  }
}
export class Port {
  public id: number;
  public name: string;
  public country: string;
}
export * from './port';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { delay } from 'rxjs/operators';
import { Port } from '../types/index';

@Injectable()
export class PortService {
  private ports: Port[] = [
    { id: 0, name: 'Tokai', country: 'Japan' },
    { id: 2, name: 'Vladivostok', country: 'Russia' },
    { id: 3, name: 'Navlakhi', country: 'India' },
    { id: 4, name: 'Cayman Brac', country: 'Cayman Islands' },
    { id: 5, name: 'Areia Branca', country: 'Brazil' },
    { id: 6, name: 'Port Ibrahim', country: 'Egypt' },
    { id: 7, name: 'Brahestad', country: 'Finland' },
    { id: 8, name: 'Brake', country: 'Germany' },
    { id: 9, name: 'Hantsport NS', country: 'Canada' },
    { id: 10, name: 'Santa Maria Bay', country: 'Cape Verde' },
    { id: 11, name: 'Antofagasta', country: 'Chile' },
    { id: 12, name: 'San Antonio', country: 'Chile' },
    { id: 13, name: 'Santa Barbara', country: 'Chile' },
    { id: 14, name: 'Cabo San Antonio', country: 'Argentina' },
    { id: 15, name: 'Diamante', country: 'Argentina' },
    { id: 16, name: 'San Antonio Este Arg', country: 'Argentina' },
    { id: 17, name: 'Santa Anna Bay', country: 'Curacao' },
    { id: 18, name: 'Hambantota', country: 'Sri Lanka' },
    { id: 19, name: 'Antananarivo', country: 'Madagascar' },
    { id: 20, name: 'Navegantes', country: 'Brazil' },
    { id: 21, name: 'Bantry Bay', country: 'Ireland' },
    { id: 22, name: 'Porto Levante', country: 'Italy' },
    { id: 23, name: 'Port of Antikyra', country: 'Greece' },
    { id: 24, name: 'Berantai FPSO', country: 'Malaysia' },
    { id: 25, name: "Alicante", country: 'Spain' },
    { id: 26, name: "Almirante", country: 'Panama' },
    { id: 27, name: "Canton", country: 'China' },
    { id: 28, name: "Dante", country: 'Somalia' },
    { id: 29, name: "Davant LA", country: 'United States' },
    { id: 30, name: "Fremantle", country: 'Australia' },
    { id: 31, name: "General Santos", country: 'Philippines' },
    { id: 32, name: "Granton", country: 'United Kingdom' },
    { id: 33, name: "Guanta", country: 'Venezuela' },
    { id: 34, name: "Hambantota", country: 'Sri Lanka' },
    { id: 35, name: "Kalimantan", country: 'Indonesia' },
    { id: 36, name: "Kantang", country: 'Thailand' },
    { id: 37, name: "Kantvik", country: 'Finland' },
    { id: 38, name: "Kuantan", country: 'Malaysia' },
    { id: 39, name: "Lantian", country: 'China' },
    { id: 40, name: "Manta", country: 'Ecuador' },
    { id: 41, name: "Mantes", country: 'France' },
    { id: 42, name: "Nantong", country: 'China' },
    { id: 43, name: "Antonina", country: 'Brazil' },
    { id: 44, name: "Santa Cruz", country: 'Argentina' },
    { id: 45, name: "Santa Eugenia De Riveira", country: 'Spain' }
  ];

  getPorts(page: number = 1, size: number = 15): Port[] {
    return this.ports.slice((page - 1) * size, ((page - 1) * size) + size);
  }

  getPortsAsync(page: number = 1, size: number = 15): Observable<Port[]> {
    return new Observable<Port[]>(observer => {
      observer.next(this.getPorts(page, size));
      observer.complete()
    }).pipe(delay(2000));
  }
}
export * from './port.service';
import { Component } from '@angular/core';
import { FormBuilder, FormGroup, FormControl, Validators } from '@angular/forms';
import { InfiniteScroll, ModalController } from 'ionic-angular';
import { SelectSearchableComponent } from 'ionic-select-searchable';
import { Port } from '../../types/index';
import { PortService } from '../../services/index';
import { ModalPage } from '../modal/modal';

@Component({
  selector: 'page-home',
  templateUrl: './pages/home/home.html'
})
export class HomePage {
  ports: Port[];
  ports10: Port[];
  portNames: string[];
  port1: Port;
  port2: Port;
  port3: Port;
  port4: Port;
  port5: Port;
  port6: Port;
  port7: Port;
  port9: string = 'Vladivostok';
  port10: Port;
  form: FormGroup;
  port8Control: FormControl;
  ports10Page = 2;

  constructor(
    private formBuilder: FormBuilder,
    private modalController: ModalController,
    private portService: PortService
  ) {
    this.ports = this.portService.getPorts();
    this.portNames = this.portService.getPorts().map(port => port.name);
    this.port2 = this.ports[1];
    this.port7 = this.ports[5];
    this.port8Control = this.formBuilder.control(this.ports[6], Validators.required);
    this.form = this.formBuilder.group({
      port8: this.port8Control
    });
    this.ports10 = this.portService.getPorts();
  }

  getMorePorts(event: { component: SelectSearchableComponent, infiniteScroll: InfiniteScroll }) {
    // Trere're no more ports - disable infinite scroll.
    if (this.ports10Page > 3) {
      event.infiniteScroll.enable(false);
      return;
    }

    this.portService.getPortsAsync(this.ports10Page).subscribe(ports => {
      event.component.items = event.component.items.concat(ports);
      event.infiniteScroll.complete();
      this.ports10Page++;
    });
  }

  searchPorts(event: { component: SelectSearchableComponent, text: string }) {
    let text = (event.text || '').trim().toLowerCase();

    if (!text) {
      event.component.items = [];
      return;
    } else if (event.text.length < 3) {
      return;
    }

    event.component.isSearching = true;

    this.portService.getPortsAsync().subscribe(ports => {
      event.component.items = ports.filter(port => {
        return port.name.toLowerCase().indexOf(text) !== -1 ||
          port.country.toLowerCase().indexOf(text) !== -1;
      });

      event.component.isSearching = false;
    });
  }

  portChange(event: { component: SelectSearchableComponent, value: any }) {
    console.log('port:', event.value);
  }

  reset() {
    this.port8Control.reset();
  }

  openModal() {
    let modal = this.modalController.create(ModalPage);
    modal.present();
  }
}
<ion-header>
  <ion-navbar>
    <ion-title>Ionic SelectSearchable</ion-title>
  </ion-navbar>
</ion-header>
<ion-content>
  <ion-item-group margin-bottom>
    <ion-item-divider color="light">
      <h1>Basic</h1>
    </ion-item-divider>
    <ion-item>
      <select-searchable
        [(ngModel)]="port1"
        itemValueField="id"
        itemTextField="name"
        [items]="ports"
        (onChange)="portChange($event)">
        <ng-template selectSearchableLabelTemplate>
          Port
        </ng-template>
      </select-searchable>
    </ion-item>
  </ion-item-group>
  <ion-item-group margin-bottom>
    <ion-item-divider color="light">
      <h1>Initial value</h1>
    </ion-item-divider>
    <ion-item>
      <select-searchable
        [(ngModel)]="port2"
        itemValueField="id"
        itemTextField="name"
        [items]="ports"
        (onChange)="portChange($event)">
        <ng-template selectSearchableLabelTemplate>
          Port
        </ng-template>
      </select-searchable>
    </ion-item>
  </ion-item-group>
  <ion-item-group margin-bottom>
    <ion-item-divider color="light">
      <h1>Search</h1>
    </ion-item-divider>
    <ion-item>
      <select-searchable
        [(ngModel)]="port3"
        itemValueField="id"
        itemTextField="name"
        [items]="ports"
        [canSearch]="true"
        (onChange)="portChange($event)">
        <ng-template selectSearchableLabelTemplate>
          Port
        </ng-template>
      </select-searchable>
    </ion-item>
  </ion-item-group>
  <ion-item-group margin-bottom>
    <ion-item-divider color="light">
      <h1>Search (Async)</h1>
    </ion-item-divider>
    <ion-item>
      <select-searchable
        [(ngModel)]="port4"
        itemValueField="id"
        itemTextField="name"
        [items]="ports"
        [canSearch]="true"
        searchPlaceholder="Enter 3 or more characters, e.g. &quot;san&quot;"
        (onSearch)="searchPorts($event)"
        (onChange)="portChange($event)">
        <ng-template selectSearchableLabelTemplate>
          Port
        </ng-template>
      </select-searchable>
    </ion-item>
  </ion-item-group>
  <ion-item-group margin-bottom>
    <ion-item-divider color="light">
      <h1>Item template</h1>
    </ion-item-divider>
    <ion-item>
      <select-searchable
        [(ngModel)]="port5"
        itemValueField="id"
        itemTextField="name"
        [items]="ports"
        [canSearch]="true"
        (onChange)="portChange($event)">
        <ng-template selectSearchableLabelTemplate>
          Port
        </ng-template>
        <ng-template selectSearchableItemTemplate let-port="item">
          {{port.name}} ({{port.country}})
        </ng-template>
      </select-searchable>
    </ion-item>
  </ion-item-group>
  <ion-item-group margin-bottom>
    <ion-item-divider color="light">
      <h1>Multiple selection</h1>
    </ion-item-divider>
    <ion-item>
      <select-searchable
        [(ngModel)]="port6"
        itemValueField="id"
        itemTextField="name"
        [items]="ports"
        [canSearch]="true"
        [isMultiple]="true"
        (onChange)="portChange($event)">
        <ng-template selectSearchableLabelTemplate>
          Port
        </ng-template>
      </select-searchable>
    </ion-item>
  </ion-item-group>
  <ion-item-group margin-bottom>
    <ion-item-divider color="light">
      <h1>"Clear" button</h1>
    </ion-item-divider>
    <ion-item>
      <select-searchable
        [(ngModel)]="port7"
        itemValueField="id"
        itemTextField="name"
        [items]="ports"
        (onChange)="portChange($event)"
        [canReset]="true">
        <ng-template selectSearchableLabelTemplate>
          Port
        </ng-template>
      </select-searchable>
    </ion-item>
  </ion-item-group>
  <form [formGroup]="form" margin-bottom>
    <ion-item-group>
      <ion-item-divider color="light">
        <h1>Angular Forms support</h1>
      </ion-item-divider>
      <ion-item>
        <select-searchable
          formControlName="port8"
          itemValueField="id"
          itemTextField="name"
          [items]="ports"
          [canSearch]="true"
          (onChange)="portChange($event)">
          <ng-template selectSearchableLabelTemplate>
            Port
          </ng-template>
        </select-searchable>
      </ion-item>
      <ion-item>
        <ion-badge color="danger" *ngIf="!form.valid">Invalid</ion-badge>
        <ion-badge color="secondary" *ngIf="form.valid">Valid</ion-badge>
        <button ion-button item-right (click)="reset()" [disabled]="!form.valid">
          Reset
        </button>
      </ion-item>
    </ion-item-group>
  </form>
  <ion-item-group margin-bottom>
    <ion-item-divider color="light">
      <h1>Flat array, e.g. ['Vladivostok', ...]</h1>
    </ion-item-divider>
    <ion-item>
      <select-searchable
        [(ngModel)]="port9"
        [items]="portNames"
        [canSearch]="true"
        (onChange)="portChange($event)">
        <ng-template selectSearchableLabelTemplate>
          Port
        </ng-template>
      </select-searchable>
    </ion-item>
  </ion-item-group>
  <ion-item-group margin-bottom>
    <ion-item-divider color="light">
      <h1>Infinite scroll</h1>
    </ion-item-divider>
    <ion-item>
      <select-searchable
        [(ngModel)]="port10"
        itemValueField="id"
        itemTextField="name"
        [items]="ports10"
        [hasInfiniteScroll]="true"
        [canSearch]="true"
        (onInfiniteScroll)="getMorePorts($event)"
        (onChange)="portChange($event)">
        <ng-template selectSearchableLabelTemplate>
          Port
        </ng-template>
      </select-searchable>
    </ion-item>
  </ion-item-group>
  <ion-item-group margin-bottom>
    <ion-item-divider color="light">
      <h1>Inside modal</h1>
    </ion-item-divider>
    <ion-item>
      <button ion-button (click)="openModal()">Open</button>
    </ion-item>
  </ion-item-group>
</ion-content>
<ion-header>
  <ion-toolbar>
    <ion-title>
      Modal
    </ion-title>
    <ion-buttons start>
      <button ion-button (click)="dismiss()">
        <ion-icon name="md-close"></ion-icon>
      </button>
    </ion-buttons>
  </ion-toolbar>
</ion-header>
<ion-content>
  <ion-list>
    <ion-item>
      <select-searchable
        [(ngModel)]="port"
        itemValueField="id"
        itemTextField="name"
        [items]="ports">
        <ng-template selectSearchableLabelTemplate>
          Port
        </ng-template>
      </select-searchable>
    </ion-item>
  </ion-list>
</ion-content>
import { Component } from '@angular/core';
import { ViewController } from 'ionic-angular';
import { Port } from '../../types/index';
import { PortService } from '../../services/index';

@Component({
  selector: 'page-modal',
  templateUrl: './pages/modal/modal.html'
})
export class ModalPage {
  port: Port;
  ports: Port[];

  constructor(private viewController: ViewController, private portService: PortService) {
    this.ports = this.portService.getPorts();
  }

  dismiss() {
    this.viewController.dismiss();
  }
}