├── .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 | [](https://badge.fury.io/js/ng2-select2) [](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 |
12 |
13 |
14 | `,
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 | }
--------------------------------------------------------------------------------