├── .gitignore ├── .npmignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── lib ├── ng2-select2.component.css ├── ng2-select2.component.ts ├── ng2-select2.interface.ts └── ng2-select2.ts ├── package.json ├── rollup.config.js ├── tools ├── cleanup.ts └── inline-styles.ts ├── tsconfig-esm.json └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Dependency directory 12 | node_modules 13 | 14 | # Optional npm cache directory 15 | .npm 16 | 17 | # IDEs and editors 18 | /.idea 19 | .project 20 | .classpath 21 | *.launch 22 | .settings/ 23 | 24 | #System Files 25 | .DS_Store 26 | Thumbs.db 27 | 28 | # Generated files 29 | dist 30 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | # dependencies 2 | /node_modules 3 | 4 | # IDEs and editors 5 | /.idea 6 | 7 | # misc 8 | /.sass-cache 9 | /connect.lock 10 | /coverage/* 11 | /libpeerconnection.log 12 | npm-debug.log 13 | testem.log 14 | yarn.lock 15 | yarn-error.log 16 | .npmignore 17 | 18 | #TS files 19 | **/*.ts 20 | *.ts 21 | !**/*.d.ts 22 | !*.d.ts 23 | tsconfig.json 24 | tsconfig-aot.json 25 | 26 | #System Files 27 | .DS_Store 28 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 1.0.0-beta 2 | 3 | * Multiple options [223f02f](https://github.com/NejcZdovc/ng2-select2/commit/223f02fc598cd4d550baf03f82874839ee95e2c1) 4 | * Updated dependencies [af513af](https://github.com/NejcZdovc/ng2-select2/commit/af513afc611701cb0826d05336216010232f945c) 5 | * Disable default style for select2 [2692aec](https://github.com/NejcZdovc/ng2-select2/commit/2692aecf6176a8c4a339715ed4fe6b89ba4040c8) 6 | * Support for custom matcher [d269db9](https://github.com/NejcZdovc/ng2-select2/commit/d269db9438b74c9200f5c4eca9c5dd3db71a9663) 7 | * Fixed no provider error [305a388](https://github.com/NejcZdovc/ng2-select2/commit/305a388acacffcb3f5ecc62a6b114a245b29558b) 8 | * Fixed multiple value emit [853837b](https://github.com/NejcZdovc/ng2-select2/commit/853837ba652422436a110511fc269b94fad5d532) 9 | * Added disabled options [b19a3ed](https://github.com/NejcZdovc/ng2-select2/commit/b19a3eda1c5583d2bfad26bf7752c162cf9838a7) 10 | * Fixed initial value when you are using custom matcher [e366b91](https://github.com/NejcZdovc/ng2-select2/commit/e366b91716510b72b48287cf1564e9eebb489c1a) 11 | * Added multiple value support via array's [4396df6](https://github.com/NejcZdovc/ng2-select2/commit/4396df6634a08594bfeb962f3b105e11cfec394b) 12 | * Fix async require oldMatcher [12f23188](https://github.com/NejcZdovc/ng2-select2/commit/12f23188f3bef3346802436c245c146c149a2b53) 13 | 14 | ### BREAKING CHANGE 15 | With version 1.0.0 you can now pass all options that are available for select 2. But to accomplish that `theme`, `templateSelection` and `templateResult` where removed from direct `@Inputs`. 16 | 17 | # 0.7.0 (15.12.2016) 18 | 19 | * Added better error handling ([acb4243](https://github.com/NejcZdovc/ng2-select2/commit/acb4243)) 20 | * Trigger valueChanged event when we change value via `@Input` ([81b90f9](https://github.com/NejcZdovc/ng2-select2/commit/81b90f9), [9a3b25e](https://github.com/NejcZdovc/ng2-select2/commit/9a3b25e)) 21 | * Improved README ([f954ecc](https://github.com/NejcZdovc/ng2-select2/commit/f954ecc)) 22 | * Added renderer ([369571b](https://github.com/NejcZdovc/ng2-select2/commit/369571b)) 23 | 24 | # 0.6.2 (14.12.2016) 25 | 26 | * Fixed recursive bug #28 ([4e40ac3](https://github.com/NejcZdovc/ng2-select2/commit/4e40ac3)) 27 | 28 | # 0.6.1 (18.11.2016) 29 | 30 | * Removed generated files from GIT 31 | * Added AOT build 32 | 33 | # 0.6.0 (16.11.2016) 34 | 35 | * Now plugin is using NgModule 36 | * Updated angular to version 2.2.0 37 | * Changed licence to MIT 38 | * Added support for async data #17 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Nejc Zdovc 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Angular wrapper for Select2 (ng2-select2) 2 | 3 | [![npm version](https://badge.fury.io/js/ng2-select2.svg)](https://badge.fury.io/js/ng2-select2) [![MIT Licence](https://badges.frapsoft.com/os/mit/mit.svg?v=103)](https://opensource.org/licenses/mit-license.php) 4 | 5 | For Angular version 2.x.x and up 6 | 7 | 8 | ## Prerequisites 9 | 10 | For this plugin to work you need to add two javascript libraries to your project 11 | - [Jquery](https://jquery.com/download/) 12 | - [Select2](https://select2.github.io/) 13 | 14 | First option and **preferred one** is to add libraries to your package builder. 15 | - You can find example of how to add libraries to the Angular CLI in [demo repository](https://github.com/NejcZdovc/ng2-select2-demo/blob/master/.angular-cli.json#L24-L25). 16 | - You can also add it to [webpack directly](https://stackoverflow.com/questions/28969861/managing-jquery-plugin-dependency-in-webpack#answer-2898947). 17 | 18 | Second option is to include libraries into your html head: 19 | 20 | ``` 21 | 22 | 23 | Ng2Select2Demo 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | ``` 32 | 33 | ## Installation 34 | 35 | Add package to your project `npm i -S ng2-select2` (this will save package to your `dependencies` in `package.json`) 36 | 37 | 38 | ## Basic implementation 39 | 40 | 1) Add declaration to [NgModule](https://github.com/NejcZdovc/ng2-select2-demo/blob/master/src/app/app.module.ts#L35) 41 | ``` 42 | import { Select2Module } from 'ng2-select2'; 43 | 44 | @NgModule({ 45 | imports: [ 46 | ...., 47 | Select2Module 48 | ], 49 | ... 50 | }) 51 | ``` 52 | 53 | 2) Add it to your [template](https://github.com/NejcZdovc/ng2-select2-demo/blob/master/src/app/demos/basic/basic.component.html#L3). You need to define at least `data` as `@Input`. 54 | 55 | Example of `exampleData` can be found [here](https://github.com/NejcZdovc/ng2-select2-demo/blob/master/src/app/demos/basic/basic.component.ts#L13). 56 | 57 | ``` 58 | 59 | ``` 60 | 61 | 62 | ## Options 63 | 64 | ### Inputs 65 | * **data** `Array`: Data used for generating select 2 - [inferface definition](https://github.com/NejcZdovc/ng2-select2/blob/master/lib/ng2-select2.interface.ts#L1) 66 | * **value** `string`: Default value for select 2 67 | * **cssImport** `boolean`: Disable or enable default style for select 2, default value is `false` 68 | * **width** `string`: Set width for the input, default value is `resolve` 69 | * **disabled** `boolean`: Disable select2, default value is `false` 70 | * **options** `Select2Options`: Set options for select 2, [all available options](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/4869992bc079b88280b9ff91213528904109e8ae/select2/index.d.ts#L40) for select 2 71 | 72 | ### Outputs 73 | * **valueChanged** `string`: Emitted when value changes in select 2 drop down 74 | 75 | 76 | ## Demo 77 | 78 | You can view a live demo [here](https://nejczdovc.github.io/ng2-select2-demo) or check out [demo repo](https://github.com/NejcZdovc/ng2-select2-demo/) where you can find source of this demo created with Angular CLI. 79 | -------------------------------------------------------------------------------- /lib/ng2-select2.component.css: -------------------------------------------------------------------------------- 1 | .select2-container{box-sizing:border-box;display:inline-block;margin:0;position:relative;vertical-align:middle;min-width:100px}.select2-container .select2-selection--single{box-sizing:border-box;cursor:pointer;display:block;height:28px;user-select:none;-webkit-user-select:none}.select2-container .select2-selection--single .select2-selection__rendered{display:block;padding-left:8px;padding-right:20px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.select2-container .select2-selection--single .select2-selection__clear{position:relative}.select2-container[dir=rtl] .select2-selection--single .select2-selection__rendered{padding-right:8px;padding-left:20px}.select2-container .select2-selection--multiple{box-sizing:border-box;cursor:pointer;display:block;min-height:32px;user-select:none;-webkit-user-select:none}.select2-container .select2-selection--multiple .select2-selection__rendered{display:inline-block;overflow:hidden;padding-left:8px;text-overflow:ellipsis;white-space:nowrap}.select2-container .select2-search--inline{float:left}.select2-container .select2-search--inline .select2-search__field{box-sizing:border-box;border:none;font-size:100%;margin-top:5px;padding:0}.select2-container .select2-search--inline .select2-search__field::-webkit-search-cancel-button{-webkit-appearance:none}.select2-dropdown{background-color:#fff;border:1px solid #aaa;border-radius:4px;box-sizing:border-box;display:block;position:absolute;left:-100000px;width:100%;z-index:1051}.select2-results{display:block}.select2-results__options{list-style:none;margin:0;padding:0}.select2-results__option{padding:6px;user-select:none;-webkit-user-select:none}.select2-results__option[aria-selected]{cursor:pointer}.select2-container--open .select2-dropdown{left:0}.select2-container--open .select2-dropdown--above{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0}.select2-container--open .select2-dropdown--below{border-top:none;border-top-left-radius:0;border-top-right-radius:0}.select2-search--dropdown{display:block;padding:4px}.select2-search--dropdown .select2-search__field{padding:4px;width:100%;box-sizing:border-box}.select2-search--dropdown .select2-search__field::-webkit-search-cancel-button{-webkit-appearance:none}.select2-search--dropdown.select2-search--hide{display:none}.select2-close-mask{border:0;margin:0;padding:0;display:block;position:fixed;left:0;top:0;min-height:100%;min-width:100%;height:auto;width:auto;opacity:0;z-index:99;background-color:#fff;filter:alpha(opacity=0)}.select2-hidden-accessible{border:0!important;clip:rect(0 0 0 0)!important;height:1px!important;margin:-1px!important;overflow:hidden!important;padding:0!important;position:absolute!important;width:1px!important}.select2-container--classic .select2-results>.select2-results__options,.select2-container--default .select2-results>.select2-results__options{max-height:200px;overflow-y:auto}.select2-container--default .select2-selection--single{background-color:#fff;border:1px solid #aaa;border-radius:4px}.select2-container--default .select2-selection--single .select2-selection__rendered{color:#444;line-height:28px}.select2-container--default .select2-selection--single .select2-selection__clear{cursor:pointer;float:right;font-weight:700}.select2-container--default .select2-selection--single .select2-selection__placeholder{color:#999}.select2-container--default .select2-selection--single .select2-selection__arrow{height:26px;position:absolute;top:1px;right:1px;width:20px}.select2-container--default .select2-selection--single .select2-selection__arrow b{border-color:#888 transparent transparent;border-style:solid;border-width:5px 4px 0;height:0;left:50%;margin-left:-4px;margin-top:-2px;position:absolute;top:50%;width:0}.select2-container--default[dir=rtl] .select2-selection--single .select2-selection__clear{float:left}.select2-container--default[dir=rtl] .select2-selection--single .select2-selection__arrow{left:1px;right:auto}.select2-container--default.select2-container--disabled .select2-selection--single{background-color:#eee;cursor:default}.select2-container--default.select2-container--disabled .select2-selection--single .select2-selection__clear{display:none}.select2-container--default.select2-container--open .select2-selection--single .select2-selection__arrow b{border-color:transparent transparent #888;border-width:0 4px 5px}.select2-container--default .select2-selection--multiple{background-color:#fff;border:1px solid #aaa;border-radius:4px;cursor:text}.select2-container--default .select2-selection--multiple .select2-selection__rendered{box-sizing:border-box;list-style:none;margin:0;padding:0 5px;width:100%}.select2-container--default .select2-selection--multiple .select2-selection__rendered li{list-style:none}.select2-container--default .select2-selection--multiple .select2-selection__placeholder{color:#999;margin-top:5px;float:left}.select2-container--default .select2-selection--multiple .select2-selection__clear{cursor:pointer;float:right;font-weight:700;margin-top:5px;margin-right:10px}.select2-container--default .select2-selection--multiple .select2-selection__choice{background-color:#e4e4e4;border:1px solid #aaa;border-radius:4px;cursor:default;float:left;margin-right:5px;margin-top:5px;padding:0 5px}.select2-container--default .select2-selection--multiple .select2-selection__choice__remove{color:#999;cursor:pointer;display:inline-block;font-weight:700;margin-right:2px}.select2-container--default .select2-selection--multiple .select2-selection__choice__remove:hover{color:#333}.select2-container--default[dir=rtl] .select2-selection--multiple .select2-search--inline,.select2-container--default[dir=rtl] .select2-selection--multiple .select2-selection__choice,.select2-container--default[dir=rtl] .select2-selection--multiple .select2-selection__placeholder{float:right}.select2-container--default[dir=rtl] .select2-selection--multiple .select2-selection__choice{margin-left:5px;margin-right:auto}.select2-container--default[dir=rtl] .select2-selection--multiple .select2-selection__choice__remove{margin-left:2px;margin-right:auto}.select2-container--default.select2-container--focus .select2-selection--multiple{border:1px solid #000;outline:0}.select2-container--default.select2-container--disabled .select2-selection--multiple{background-color:#eee;cursor:default}.select2-container--default.select2-container--disabled .select2-selection__choice__remove{display:none}.select2-container--default.select2-container--open.select2-container--above .select2-selection--multiple,.select2-container--default.select2-container--open.select2-container--above .select2-selection--single{border-top-left-radius:0;border-top-right-radius:0}.select2-container--default.select2-container--open.select2-container--below .select2-selection--multiple,.select2-container--default.select2-container--open.select2-container--below .select2-selection--single{border-bottom-left-radius:0;border-bottom-right-radius:0}.select2-container--default .select2-search--dropdown .select2-search__field{border:1px solid #aaa}.select2-container--default .select2-search--inline .select2-search__field{background:0 0;border:none;outline:0;box-shadow:none;-webkit-appearance:textfield}.select2-container--default .select2-results__option[role=group]{padding:0}.select2-container--default .select2-results__option[aria-disabled=true]{color:#999}.select2-container--default .select2-results__option[aria-selected=true]{background-color:#ddd}.select2-container--default .select2-results__option .select2-results__option{padding-left:1em}.select2-container--default .select2-results__option .select2-results__option .select2-results__group{padding-left:0}.select2-container--default .select2-results__option .select2-results__option .select2-results__option{margin-left:-1em;padding-left:2em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-2em;padding-left:3em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-3em;padding-left:4em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-4em;padding-left:5em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-5em;padding-left:6em}.select2-container--default .select2-results__option--highlighted[aria-selected]{background-color:#5897fb;color:#fff}.select2-container--default .select2-results__group{cursor:default;display:block;padding:6px}.select2-container--classic .select2-selection--single{background-color:#f7f7f7;border:1px solid #aaa;border-radius:4px;outline:0;background-image:-webkit-linear-gradient(top,#fff 50%,#eee 100%);background-image:-o-linear-gradient(top,#fff 50%,#eee 100%);background-image:linear-gradient(to bottom,#fff 50%,#eee 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFFFF', endColorstr='#FFEEEEEE', GradientType=0)}.select2-container--classic .select2-selection--single:focus{border:1px solid #5897fb}.select2-container--classic .select2-selection--single .select2-selection__rendered{color:#444;line-height:28px}.select2-container--classic .select2-selection--single .select2-selection__clear{cursor:pointer;float:right;font-weight:700;margin-right:10px}.select2-container--classic .select2-selection--single .select2-selection__placeholder{color:#999}.select2-container--classic .select2-selection--single .select2-selection__arrow{background-color:#ddd;border:none;border-left:1px solid #aaa;border-top-right-radius:4px;border-bottom-right-radius:4px;height:26px;position:absolute;top:1px;right:1px;width:20px;background-image:-webkit-linear-gradient(top,#eee 50%,#ccc 100%);background-image:-o-linear-gradient(top,#eee 50%,#ccc 100%);background-image:linear-gradient(to bottom,#eee 50%,#ccc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFEEEEEE', endColorstr='#FFCCCCCC', GradientType=0)}.select2-container--classic .select2-selection--single .select2-selection__arrow b{border-color:#888 transparent transparent;border-style:solid;border-width:5px 4px 0;height:0;left:50%;margin-left:-4px;margin-top:-2px;position:absolute;top:50%;width:0}.select2-container--classic[dir=rtl] .select2-selection--single .select2-selection__clear{float:left}.select2-container--classic[dir=rtl] .select2-selection--single .select2-selection__arrow{border:none;border-right:1px solid #aaa;border-radius:4px 0 0 4px;left:1px;right:auto}.select2-container--classic.select2-container--open .select2-selection--single{border:1px solid #5897fb}.select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow{background:0 0;border:none}.select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow b{border-color:transparent transparent #888;border-width:0 4px 5px}.select2-container--classic.select2-container--open.select2-container--above .select2-selection--single{border-top:none;border-top-left-radius:0;border-top-right-radius:0;background-image:-webkit-linear-gradient(top,#fff 0,#eee 50%);background-image:-o-linear-gradient(top,#fff 0,#eee 50%);background-image:linear-gradient(to bottom,#fff 0,#eee 50%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFFFF', endColorstr='#FFEEEEEE', GradientType=0)}.select2-container--classic.select2-container--open.select2-container--below .select2-selection--single{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0;background-image:-webkit-linear-gradient(top,#eee 50%,#fff 100%);background-image:-o-linear-gradient(top,#eee 50%,#fff 100%);background-image:linear-gradient(to bottom,#eee 50%,#fff 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFEEEEEE', endColorstr='#FFFFFFFF', GradientType=0)}.select2-container--classic .select2-selection--multiple{background-color:#fff;border:1px solid #aaa;border-radius:4px;cursor:text;outline:0}.select2-container--classic .select2-selection--multiple:focus{border:1px solid #5897fb}.select2-container--classic .select2-selection--multiple .select2-selection__rendered{list-style:none;margin:0;padding:0 5px}.select2-container--classic .select2-selection--multiple .select2-selection__clear{display:none}.select2-container--classic .select2-selection--multiple .select2-selection__choice{background-color:#e4e4e4;border:1px solid #aaa;border-radius:4px;cursor:default;float:left;margin-right:5px;margin-top:5px;padding:0 5px}.select2-container--classic .select2-selection--multiple .select2-selection__choice__remove{color:#888;cursor:pointer;display:inline-block;font-weight:700;margin-right:2px}.select2-container--classic .select2-selection--multiple .select2-selection__choice__remove:hover{color:#555}.select2-container--classic[dir=rtl] .select2-selection--multiple .select2-selection__choice{float:right;margin-left:5px;margin-right:auto}.select2-container--classic[dir=rtl] .select2-selection--multiple .select2-selection__choice__remove{margin-left:2px;margin-right:auto}.select2-container--classic.select2-container--open .select2-selection--multiple{border:1px solid #5897fb}.select2-container--classic.select2-container--open.select2-container--above .select2-selection--multiple{border-top:none;border-top-left-radius:0;border-top-right-radius:0}.select2-container--classic.select2-container--open.select2-container--below .select2-selection--multiple{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0}.select2-container--classic .select2-search--dropdown .select2-search__field{border:1px solid #aaa;outline:0}.select2-container--classic .select2-search--inline .select2-search__field{outline:0;box-shadow:none}.select2-container--classic .select2-dropdown{background-color:#fff;border:1px solid transparent}.select2-container--classic .select2-dropdown--above{border-bottom:none}.select2-container--classic .select2-dropdown--below{border-top:none}.select2-container--classic .select2-results__option[role=group]{padding:0}.select2-container--classic .select2-results__option[aria-disabled=true]{color:grey}.select2-container--classic .select2-results__option--highlighted[aria-selected]{background-color:#3875d7;color:#fff}.select2-container--classic .select2-results__group{cursor:default;display:block;padding:6px}.select2-container--classic.select2-container--open .select2-dropdown{border-color:#5897fb} -------------------------------------------------------------------------------- /lib/ng2-select2.component.ts: -------------------------------------------------------------------------------- 1 | import { 2 | AfterViewInit, ChangeDetectionStrategy, Component, ElementRef, EventEmitter, Input, OnChanges, OnDestroy, 3 | Output, SimpleChanges, ViewChild, ViewEncapsulation, Renderer, OnInit 4 | } from '@angular/core'; 5 | 6 | import { Select2OptionData } from './ng2-select2.interface'; 7 | 8 | @Component({ 9 | selector: 'select2', 10 | template: ` 11 | `, 15 | encapsulation: ViewEncapsulation.None, 16 | changeDetection: ChangeDetectionStrategy.OnPush 17 | }) 18 | export class Select2Component implements AfterViewInit, OnChanges, OnDestroy, OnInit { 19 | @ViewChild('selector') selector: ElementRef; 20 | 21 | // data for select2 drop down 22 | @Input() data: Array; 23 | 24 | // value for select2 25 | @Input() value: string | string[]; 26 | 27 | // enable / disable default style for select2 28 | @Input() cssImport: boolean = false; 29 | 30 | // width of select2 input 31 | @Input() width: string; 32 | 33 | // enable / disable select2 34 | @Input() disabled: boolean = false; 35 | 36 | // all additional options 37 | @Input() options: Select2Options; 38 | 39 | // emitter when value is changed 40 | @Output() valueChanged = new EventEmitter(); 41 | 42 | private element: JQuery = undefined; 43 | private check: boolean = false; 44 | 45 | constructor(private renderer: Renderer) { } 46 | 47 | ngOnInit() { 48 | if(this.cssImport) { 49 | const head = document.getElementsByTagName('head')[0]; 50 | const link: any = head.children[head.children.length-1]; 51 | 52 | if(!link.version) { 53 | const newLink = this.renderer.createElement(head, 'style'); 54 | this.renderer.setElementProperty(newLink, 'type', 'text/css'); 55 | this.renderer.setElementProperty(newLink, 'version', 'select2'); 56 | this.renderer.setElementProperty(newLink, 'innerHTML', this.style); 57 | } 58 | 59 | } 60 | } 61 | 62 | async ngOnChanges(changes: SimpleChanges) { 63 | if(!this.element) { 64 | return; 65 | } 66 | 67 | if(changes['data'] && JSON.stringify(changes['data'].previousValue) !== JSON.stringify(changes['data'].currentValue)) { 68 | await this.initPlugin(); 69 | 70 | const newValue: string = this.element.val() as string; 71 | this.valueChanged.emit({ 72 | value: newValue, 73 | data: this.element.select2('data') 74 | }); 75 | } 76 | 77 | if(changes['value'] && changes['value'].previousValue !== changes['value'].currentValue) { 78 | const newValue: string = changes['value'].currentValue; 79 | 80 | this.setElementValue(newValue); 81 | 82 | this.valueChanged.emit({ 83 | value: newValue, 84 | data: this.element.select2('data') 85 | }); 86 | } 87 | 88 | if(changes['disabled'] && changes['disabled'].previousValue !== changes['disabled'].currentValue) { 89 | this.renderer.setElementProperty(this.selector.nativeElement, 'disabled', this.disabled); 90 | } 91 | } 92 | 93 | async ngAfterViewInit() { 94 | this.element = jQuery(this.selector.nativeElement); 95 | await this.initPlugin(); 96 | 97 | if (typeof this.value !== 'undefined') { 98 | this.setElementValue(this.value); 99 | } 100 | 101 | this.element.on('select2:select select2:unselect', () => { 102 | this.valueChanged.emit({ 103 | value: this.element.val(), 104 | data: this.element.select2('data') 105 | }); 106 | }); 107 | } 108 | 109 | ngOnDestroy() { 110 | if (this.element && this.element.off) { 111 | this.element.off("select2:select"); 112 | } 113 | } 114 | 115 | private async initPlugin() { 116 | if(!this.element.select2) { 117 | if(!this.check) { 118 | this.check = true; 119 | console.log("Please add Select2 library (js file) to the project. You can download it from https://github.com/select2/select2/tree/master/dist/js."); 120 | } 121 | 122 | return; 123 | } 124 | 125 | // If select2 already initialized remove him and remove all tags inside 126 | if (this.element.hasClass('select2-hidden-accessible') == true) { 127 | this.element.select2('destroy'); 128 | this.renderer.setElementProperty(this.selector.nativeElement, 'innerHTML', ''); 129 | } 130 | 131 | let options: Select2Options = { 132 | data: this.data, 133 | width: (this.width) ? this.width : 'resolve' 134 | }; 135 | 136 | Object.assign(options, this.options); 137 | 138 | if(options.matcher) { 139 | let oldMatcher: any = await this.requireOldMatcher(); 140 | options.matcher = oldMatcher(options.matcher); 141 | this.element.select2(options); 142 | 143 | if (typeof this.value !== 'undefined') { 144 | this.setElementValue(this.value); 145 | } 146 | } else { 147 | this.element.select2(options); 148 | } 149 | 150 | if(this.disabled) { 151 | this.renderer.setElementProperty(this.selector.nativeElement, 'disabled', this.disabled); 152 | } 153 | } 154 | 155 | private async requireOldMatcher() : Promise { 156 | return new Promise(resolve => { 157 | jQuery.fn.select2.amd.require(['select2/compat/matcher'], (oldMatcher: any) => { 158 | resolve(oldMatcher); 159 | }); 160 | }); 161 | } 162 | 163 | private setElementValue (newValue: string | string[]) { 164 | if(Array.isArray(newValue)) { 165 | for (let option of this.selector.nativeElement.options) { 166 | if (newValue.indexOf(option.value) > -1) { 167 | this.renderer.setElementProperty(option, 'selected', 'true'); 168 | } 169 | } 170 | } else { 171 | this.renderer.setElementProperty(this.selector.nativeElement, 'value', newValue); 172 | } 173 | 174 | this.element.trigger('change.select2'); 175 | } 176 | 177 | private style: string = `CSS`; 178 | } 179 | -------------------------------------------------------------------------------- /lib/ng2-select2.interface.ts: -------------------------------------------------------------------------------- 1 | export interface Select2OptionData { 2 | id: string; 3 | text: string; 4 | disabled?: boolean; 5 | children?: Array; 6 | additional?: any; 7 | } 8 | 9 | export interface Select2TemplateFunction { 10 | (state: Select2OptionData): JQuery | string; 11 | } 12 | -------------------------------------------------------------------------------- /lib/ng2-select2.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | 3 | export { Select2OptionData, Select2TemplateFunction } from './ng2-select2.interface'; 4 | import { Select2Component } from './ng2-select2.component'; 5 | 6 | export { Select2Component } from './ng2-select2.component'; 7 | 8 | @NgModule({ 9 | declarations: [Select2Component], 10 | exports: [Select2Component] 11 | }) 12 | export class Select2Module {} -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ng2-select2", 3 | "version": "1.0.0-beta.16", 4 | "description": "Angular2 wrapper for select2", 5 | "main": "ng2-select2.bundle.js", 6 | "jsnext:main": "ng2-select2.js", 7 | "typings": "ng2-select2.d.ts", 8 | "module": "ng2-select2.js", 9 | "types": "ng2-select2.d.ts", 10 | "repository": { 11 | "type": "git", 12 | "url": "https://github.com/NejcZdovc/ng2-select2.git" 13 | }, 14 | "keywords": [ 15 | "angular2", 16 | "select2", 17 | "wrap" 18 | ], 19 | "author": "Nejc Zdovc ", 20 | "license": "MIT", 21 | "bugs": { 22 | "url": "https://github.com/NejcZdovc/ng2-select2/issues" 23 | }, 24 | "homepage": "https://github.com/NejcZdovc/ng2-select2", 25 | "scripts": { 26 | "finish": "mv lib/ng2-select2.component.ts.bak lib/ng2-select2.component.ts && cp README.md dist && rimraf dist/ng2-select2.component.css", 27 | "build": "rimraf dist && ts-node tools/inline-styles.ts && tsc -p tsconfig-esm.json && rollup -c rollup.config.js dist/ng2-select2.js > dist/ng2-select2.bundle.js && cp package.json dist && ts-node tools/cleanup.ts && ngc -c tsconfig-esm.json && npm run finish", 28 | "publish": "cd dist && npm publish" 29 | }, 30 | "dependencies": { 31 | "@types/jquery": "^2.0.39", 32 | "@types/select2": "4.0.42" 33 | }, 34 | "peerDependencies": { 35 | "@angular/core": ">=2.2.0" 36 | }, 37 | "devDependencies": { 38 | "@angular/common": "^2.4.4", 39 | "@angular/compiler": "^2.4.4", 40 | "@angular/compiler-cli": "^2.4.4", 41 | "@angular/core": "^2.4.4", 42 | "@angular/platform-browser": "^2.4.4", 43 | "@angular/platform-browser-dynamic": "^2.4.4", 44 | "@types/node": "^7.0.0", 45 | "core-js": "^2.4.1", 46 | "rimraf": "^2.5.4", 47 | "rollup": "^0.41.4", 48 | "rxjs": "^5.0.3", 49 | "ts-node": "^2.0.0", 50 | "typescript": "^2.1.5", 51 | "zone.js": "^0.7.4" 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | format: 'umd', 3 | moduleName: 'ng2-select2', 4 | external: [ 5 | '@angular/core', 6 | '@angular/common' 7 | ], 8 | globals: { 9 | '@angular/core': 'ng.core', 10 | } 11 | }; -------------------------------------------------------------------------------- /tools/cleanup.ts: -------------------------------------------------------------------------------- 1 | import { writeFileSync, readFileSync } from 'fs'; 2 | 3 | const packageJson = JSON.parse(readFileSync('./dist/package.json').toString()); 4 | delete packageJson.devDependencies; 5 | delete packageJson.scripts; 6 | writeFileSync('./dist/package.json', JSON.stringify(packageJson, null, 2)); -------------------------------------------------------------------------------- /tools/inline-styles.ts: -------------------------------------------------------------------------------- 1 | import { writeFileSync, readFileSync } from 'fs'; 2 | 3 | let lib = readFileSync('lib/ng2-select2.component.ts').toString(); 4 | writeFileSync('lib/ng2-select2.component.ts.bak', lib); 5 | 6 | const styles = readFileSync('lib/ng2-select2.component.css'); 7 | lib = lib.replace(/CSS/, `${styles}`); 8 | 9 | writeFileSync('lib/ng2-select2.component.ts', lib); -------------------------------------------------------------------------------- /tsconfig-esm.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "es2015", 5 | "sourceMap": true, 6 | "moduleResolution": "node", 7 | "emitDecoratorMetadata": true, 8 | "experimentalDecorators": true, 9 | "stripInternal": true, 10 | "declaration": true, 11 | "outDir": "./dist", 12 | "lib": ["es2015", "dom"] 13 | }, 14 | "exclude": [ 15 | "node_modules" 16 | ], 17 | "files": [ 18 | "./lib/ng2-select2.ts" 19 | ] 20 | } -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "commonjs", 5 | "sourceMap": true, 6 | "emitDecoratorMetadata": true, 7 | "experimentalDecorators": true, 8 | "stripInternal": true, 9 | "declaration": true, 10 | "outDir": "./dist", 11 | "lib": ["es2015", "dom"] 12 | }, 13 | "files": [ 14 | "./lib/ng2-select2.ts" 15 | ], 16 | "exclude": [ 17 | "node_modules" 18 | ], 19 | "angularCompilerOptions": { 20 | "skipTemplateCodegen": true 21 | } 22 | } --------------------------------------------------------------------------------