Repository: NileshPatel17/ng-multiselect-dropdown
Branch: main
Commit: 7e45686d51de
Files: 66
Total size: 121.4 KB
Directory structure:
gitextract_nsiqwz_z/
├── .all-contributorsrc
├── .editorconfig
├── .github/
│ └── workflows/
│ └── nodejs.yml
├── .gitignore
├── CHANGELOG.md
├── ISSUE_TEMPLATE.md
├── README.md
├── angular.json
├── custom-theme.md
├── e2e/
│ ├── app.e2e-spec.ts
│ ├── app.po.ts
│ └── tsconfig.e2e.json
├── jest.config.js
├── karma.conf.js
├── ng-multiselect-dropdown.theme.scss
├── ng-package.json
├── package-lib-template.json
├── package.json
├── protractor.conf.js
├── publish-package.md
├── src/
│ ├── app/
│ │ ├── app.component.html
│ │ ├── app.component.scss
│ │ ├── app.component.ts
│ │ ├── app.module.ts
│ │ ├── components/
│ │ │ ├── sample-section.component.html
│ │ │ ├── sample-section.component.ts
│ │ │ ├── select/
│ │ │ │ ├── multiple-demo.html
│ │ │ │ ├── multiple-demo.ts
│ │ │ │ ├── single-demo.html
│ │ │ │ └── single-demo.ts
│ │ │ └── select-section.ts
│ │ └── index.ts
│ ├── assets/
│ │ └── .gitkeep
│ ├── code-viewer/
│ │ ├── code-viewer.module.ts
│ │ └── code-viewer.ts
│ ├── environments/
│ │ ├── environment.prod.ts
│ │ └── environment.ts
│ ├── index.html
│ ├── jest-global-mocks.ts
│ ├── main.ts
│ ├── ng-multiselect-dropdown/
│ │ ├── src/
│ │ │ ├── click-outside.directive.ts
│ │ │ ├── index.ts
│ │ │ ├── list-filter.pipe.ts
│ │ │ ├── multi-select.component.html
│ │ │ ├── multi-select.component.scss
│ │ │ ├── multiselect.component.ts
│ │ │ ├── multiselect.model.ts
│ │ │ ├── ng-multiselect-dropdown.module.ts
│ │ │ └── public_api.ts
│ │ └── test/
│ │ ├── helper.ts
│ │ ├── list-filter.pipe.spec.ts
│ │ ├── multi-select-disabled-item.component.spec.ts
│ │ ├── multi-select.component.spec.ts
│ │ ├── multi-select.component1.spec.ts
│ │ ├── multi-select.component2.spec.ts
│ │ └── various-input-data.spec.ts
│ ├── polyfills.ts
│ ├── setup-jest.ts
│ ├── styles.scss
│ ├── test.ts
│ ├── tsconfig.app.json
│ ├── tsconfig.json
│ ├── tsconfig.spec.json
│ └── typings.d.ts
├── tsconfig.json
└── tslint.json
================================================
FILE CONTENTS
================================================
================================================
FILE: .all-contributorsrc
================================================
{
"projectName": "ng-multiselect-dropdown",
"projectOwner": "Nilesh Patel",
"repoType": "github",
"repoHost": "https://github.com",
"files": [
"README.md"
],
"imageSize": 100,
"commit": false,
"commitConvention": "angular",
"contributors": [
{
"login": "tomsaleeba",
"name": "Tom Saleeba",
"avatar_url": "https://avatars0.githubusercontent.com/u/1773838?v=4",
"profile": "http://blog.techotom.com",
"contributions": [
"code"
]
},
{
"login": "synap5e",
"name": "Simon Pinfold",
"avatar_url": "https://avatars0.githubusercontent.com/u/2515062?v=4",
"profile": "https://overtrack.gg",
"contributions": [
"code"
]
},
{
"login": "sushil-suthar",
"name": "Sushil Suthar",
"avatar_url": "https://avatars0.githubusercontent.com/u/32981723?v=4",
"profile": "http://helpfordeveloper.blogspot.in",
"contributions": [
"code"
]
},
{
"login": "sacgrover",
"name": "Sachin Grover",
"avatar_url": "https://avatars1.githubusercontent.com/u/1292182?v=4",
"profile": "http://sacgro.com",
"contributions": [
"code"
]
},
{
"login": "WWL-MikeRoberts",
"name": "Mike Roberts",
"avatar_url": "https://avatars3.githubusercontent.com/u/9750056?v=4",
"profile": "https://github.com/WWL-MikeRoberts",
"contributions": [
"code"
]
},
{
"login": "DsosaV",
"name": "David Sosa",
"avatar_url": "https://avatars2.githubusercontent.com/u/3926475?v=4",
"profile": "https://github.com/DsosaV",
"contributions": [
"code"
]
}
],
"contributorsPerLine": 7
}
================================================
FILE: .editorconfig
================================================
# Editor configuration, see http://editorconfig.org
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
max_line_length = off
trim_trailing_whitespace = false
================================================
FILE: .github/workflows/nodejs.yml
================================================
name: Node CI - run test
on: [pull_request]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [16.x]
steps:
- uses: actions/checkout@v1
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- name: npm install and test
run: |
npm install
npm run test:ci
================================================
FILE: .gitignore
================================================
# See http://help.github.com/ignore-files/ for more about ignoring files.
# compiled output
/dist
/dist-lib
/tmp
/out-tsc
/.angular
dist-lib.tgz
# dependencies
/node_modules
# IDEs and editors
/.idea
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace
# IDE - VSCode
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
.vscode
# misc
/.sass-cache
/connect.lock
/coverage
/libpeerconnection.log
npm-debug.log
testem.log
/typings
yarn-error.log
# e2e
/e2e/*.js
/e2e/*.map
# System Files
.DS_Store
Thumbs.db
package-lock.json
settings.json
TODO.md
ng-multiselect-dropdown - Copy
================================================
FILE: CHANGELOG.md
================================================
================================================
FILE: ISSUE_TEMPLATE.md
================================================
**Angular version**:
**ng-multiselect-dropdown version**:
**Description of issue**:
**Steps to reproduce**:
**Expected result**:
**Actual result**:
**Demo**: Please share sample code link using StackBlitz or codesandbox
Any relevant code:
```
```
================================================
FILE: README.md
================================================
# Angular Multiselect Dropdown
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
[](#contributors-)
<!-- ALL-CONTRIBUTORS-BADGE:END -->
[](https://www.npmjs.com/package/ng-multiselect-dropdown)
[](https://www.npmjs.com/package/ng-multiselect-dropdown)
[](https://www.npmjs.com/package/ng-multiselect-dropdown)
Angular multiselect dropdown component for web applications. Easy to integrate and use. It can be bind to any custom data source.
# [Demo](https://nileshpatel17.github.io/ng-multiselect-dropdown/)

## Getting Started
## Features
- dropdown with single/multiple selction option
- bind to any custom data source
- search item with custom placeholder text
- limit selection
- select/de-select all items
- custom theme
### Installation
```
npm install ng-multiselect-dropdown
```
And then include it in your module (see [app.module.ts](https://github.com/NileshPatel17/ng-multiselect-dropdown/blob/master/src/app/app.module.ts)):
```ts
import { NgMultiSelectDropDownModule } from 'ng-multiselect-dropdown';
// ...
@NgModule({
imports: [
NgMultiSelectDropDownModule.forRoot()
// ...
]
// ...
})
export class AppModule {}
```
### Usage
```ts
import { Component, OnInit } from '@angular/core';
import { IDropdownSettings } from 'ng-multiselect-dropdown';
export class AppComponent implements OnInit {
dropdownList = [];
selectedItems = [];
dropdownSettings = {};
ngOnInit() {
this.dropdownList = [
{ item_id: 1, item_text: 'Mumbai' },
{ item_id: 2, item_text: 'Bangaluru' },
{ item_id: 3, item_text: 'Pune' },
{ item_id: 4, item_text: 'Navsari' },
{ item_id: 5, item_text: 'New Delhi' }
];
this.selectedItems = [
{ item_id: 3, item_text: 'Pune' },
{ item_id: 4, item_text: 'Navsari' }
];
this.dropdownSettings:IDropdownSettings = {
singleSelection: false,
idField: 'item_id',
textField: 'item_text',
selectAllText: 'Select All',
unSelectAllText: 'UnSelect All',
itemsShowLimit: 3,
allowSearchFilter: true
};
}
onItemSelect(item: any) {
console.log(item);
}
onSelectAll(items: any) {
console.log(items);
}
}
```
```html
<ng-multiselect-dropdown
[placeholder]="'custom placeholder'"
[settings]="dropdownSettings"
[data]="dropdownList"
[(ngModel)]="selectedItems"
(onSelect)="onItemSelect($event)"
(onSelectAll)="onSelectAll($event)"
>
</ng-multiselect-dropdown>
```
### Settings
| Setting | Type | Description | Default Value |
| :----------------------------- | :--------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------ |
| singleSelection | Boolean | Mode of this component. If set `true` user can select more than one option. | false |
| placeholder | String | Text to be show in the dropdown, when no items are selected. | 'Select' |
| disabled | Boolean | Disable the dropdown | false |
| data | Array<any> | Array of items from which to select. Should be an array of objects with id and `text` properties. You can also use custom properties. In that case you need to map idField and `textField` properties. As convenience, you may also pass an array of strings, in which case the same string is used for both the ID and the text(no mapping is required) | n/a |
| idField | String | map id field in case of custom array of object | 'id' |
| textField | String | map text field in case of custom array of object | 'text' |
| enableCheckAll | Boolean | Enable the option to select all items in list | false |
| selectAllText | String | Text to display as the label of select all option | Select All |
| unSelectAllText | String | Text to display as the label of unSelect option | UnSelect All |
| allowSearchFilter | Boolean | Enable filter option for the list. | false |
| searchPlaceholderText | String | custom search placeholder | Search |
| clearSearchFilter | Boolean | clear search filter on dropdown close | true |
| maxHeight | Number | Set maximum height of the dropdown list in px. | 197 |
| itemsShowLimit | Number | Limit the number of items to show in the input field. If not set will show all selected. | All |
| limitSelection | Number | Limit the selection of number of items from the dropdown list. Once the limit is reached, all unselected items gets disabled. | none |
| searchPlaceholderText | String | Custom text for the search placeholder text. Default value would be 'Search' | 'Search' |
| noDataAvailablePlaceholderText | String | Custom text when no data is available. | 'No data available' |
| closeDropDownOnSelection | Boolean | Closes the dropdown when item is selected. applicable only in cas of single selection | false |
| defaultOpen | Boolean | open state of dropdown | false |
| allowRemoteDataSearch | Boolean | allow search remote api if no data is present. | false |
### Callback Methods
- `onSelect` - Return the selected item when an item is checked.
Example : (onSelect)="onItemSelect($event)"
- `onSelectAll` - Return the all items.
Example : (onSelectAll)="onSelectAll($event)".
- `onDeSelect` - Return the unselected item when an item is unchecked.
Example : (onDeSelect)="onItemDeSelect($event)"
- `onFilterChange` - Return the key press.
Example : (onFilterChange)="onFilterChange($event)"
- `onDropDownClose`-
Example : (onDropDownClose)="onDropDownClose()"
### Custom Theme
- The component package has a themes folder in node_modules at `ng-multiselet-dropdown\themes\ng-multiselect-dropdown.theme.scss`
- Include the `ng-multiselet-dropdown.theme.css` in `angular-cli.json` (for versions below angular 6) and `angular.json` (for version 6 or more).
- [Refer this file](https://github.com/NileshPatel17/ng-multiselect-dropdown/blob/master/custom-theme.md) on how to add the css file to your angular project.
<img src="Screenshots/theme-step-3.png" width="800">
<!--  -->
## Custom Template(in beta):
### Variables can be used in template
1. id: return id as number
2. option: return option text. return string
3. isSelected: determine if item is selected or not. returns boolean
Template for each item
```
<ng-template #optionsTemplate let-item let-option="option" let-id="id" let-isSelected="isSelected">
{{option}}
</ng-template>
```
Template for selected item
```
<ng-template #optionSelectedTemplate optionSelectedTemplate let-option="option" let-id="id">
{{option}}
</ng-template>
```
[Demo](https://codesandbox.io/s/custom-template-uyo0o?file=/src/app/app.component.html)
### Run locally
- Clone the repository or downlod the .zip,.tar files.
- Run `npm install`
- Run `ng serve` for a dev server
- Navigate to `http://localhost:4200/`
### Library Build / NPM Package
Run `yarn build:lib` to build the library and generate an NPM package. The build artifacts will be stored in the dist-lib/ folder.
## Running unit tests
Run `yarn test` to execute the unit tests.
## Development
This project was generated with Angular CLI version 1.7.1.
## Contributions
Contributions are welcome, please open an issue and preferrably file a pull request.
### Opening Issue
Please share sample code using codesandbox.com or stackblitz.com to help me re-produce the issue.
## License
MIT License.
## Contributors ✨
Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
<!-- prettier-ignore-start -->
<!-- markdownlint-disable -->
<table>
<tr>
<td align="center"><a href="http://blog.techotom.com"><img src="https://avatars0.githubusercontent.com/u/1773838?v=4" width="100px;" alt=""/><br /><sub><b>Tom Saleeba</b></sub></a><br /><a href="https://github.com/Nilesh Patel/ng-multiselect-dropdown/commits?author=tomsaleeba" title="Code">💻</a></td>
<td align="center"><a href="https://overtrack.gg"><img src="https://avatars0.githubusercontent.com/u/2515062?v=4" width="100px;" alt=""/><br /><sub><b>Simon Pinfold</b></sub></a><br /><a href="https://github.com/Nilesh Patel/ng-multiselect-dropdown/commits?author=synap5e" title="Code">💻</a></td>
<td align="center"><a href="http://helpfordeveloper.blogspot.in"><img src="https://avatars0.githubusercontent.com/u/32981723?v=4" width="100px;" alt=""/><br /><sub><b>Sushil Suthar</b></sub></a><br /><a href="https://github.com/Nilesh Patel/ng-multiselect-dropdown/commits?author=sushil-suthar" title="Code">💻</a></td>
<td align="center"><a href="http://sacgro.com"><img src="https://avatars1.githubusercontent.com/u/1292182?v=4" width="100px;" alt=""/><br /><sub><b>Sachin Grover</b></sub></a><br /><a href="https://github.com/Nilesh Patel/ng-multiselect-dropdown/commits?author=sacgrover" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/WWL-MikeRoberts"><img src="https://avatars3.githubusercontent.com/u/9750056?v=4" width="100px;" alt=""/><br /><sub><b>Mike Roberts</b></sub></a><br /><a href="https://github.com/Nilesh Patel/ng-multiselect-dropdown/commits?author=WWL-MikeRoberts" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/DsosaV"><img src="https://avatars2.githubusercontent.com/u/3926475?v=4" width="100px;" alt=""/><br /><sub><b>David Sosa</b></sub></a><br /><a href="https://github.com/Nilesh Patel/ng-multiselect-dropdown/commits?author=DsosaV" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/gserg"><img src="https://avatars.githubusercontent.com/u/687825?v=4" width="100px;" alt=""/><br /><sub><b>Sergiy Gedeon</b></sub></a><br /><a href="https://github.com/Nilesh Patel/ng-multiselect-dropdown/commits?author=gserg" title="Code">💻</a></td>
</tr>
</table>
<!-- markdownlint-enable -->
<!-- prettier-ignore-end -->
<!-- ALL-CONTRIBUTORS-LIST:END -->
This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!
================================================
FILE: angular.json
================================================
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"projects": {
"ng-multiselect-dropdown-base": {
"root": "",
"sourceRoot": "src",
"projectType": "application",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
"aot": true,
"outputPath": "dist",
"index": "src/index.html",
"main": "src/main.ts",
"tsConfig": "src/tsconfig.app.json",
"polyfills": "src/polyfills.ts",
"assets": [
"src/assets",
"src/favicon.ico"
],
"styles": [
"src/styles.scss"
],
"scripts": []
},
"configurations": {
"production": {
"budgets": [
{
"type": "anyComponentStyle",
"maximumWarning": "6kb"
}
],
"optimization": true,
"outputHashing": "all",
"sourceMap": false,
"extractCss": true,
"namedChunks": false,
"aot": true,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true,
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
]
}
}
},
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"options": {
"browserTarget": "ng-multiselect-dropdown-base:build"
},
"configurations": {
"production": {
"browserTarget": "ng-multiselect-dropdown-base:build:production"
}
}
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": {
"browserTarget": "ng-multiselect-dropdown-base:build"
}
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"main": "src/test.ts",
"karmaConfig": "./karma.conf.js",
"polyfills": "src/polyfills.ts",
"tsConfig": "src/tsconfig.spec.json",
"scripts": [],
"styles": [
"src/styles.scss"
],
"assets": [
"src/assets",
"src/favicon.ico"
]
}
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": [
"src/tsconfig.app.json",
"src/tsconfig.spec.json"
],
"exclude": [
"**/node_modules/**"
]
}
}
}
},
"ng-multiselect-dropdown-base-e2e": {
"root": "",
"sourceRoot": "e2e",
"projectType": "application",
"architect": {
"e2e": {
"builder": "@angular-devkit/build-angular:protractor",
"options": {
"protractorConfig": "./protractor.conf.js",
"devServerTarget": "ng-multiselect-dropdown-base:serve"
}
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": [
"e2e/tsconfig.e2e.json"
],
"exclude": [
"**/node_modules/**"
]
}
}
}
}
},
"schematics": {
"@schematics/angular:component": {
"prefix": "ng",
"style": "scss"
},
"@schematics/angular:directive": {
"prefix": "ng"
}
}
}
================================================
FILE: custom-theme.md
================================================
# Custom Theme
#### Step 1:
1. copy 'ng-multiselect-dropdown.theme.scss' file located at `node_modules\ng-multiselet-dropdown\themes\ng-multiselect-dropdown.theme.scss`
<img src="Screenshots/theme-step-1.png" width="700">
** if you are using version below 0.2.11, you need to get it from https://github.com/NileshPatel17/ng-multiselect-dropdown/themes/ng-multiselet-dropdown.theme.css
#### Step 2:
1. paste this file in your project wherever you want. Include this file `ng-multiselet-dropdown.theme.css` in `angular-cli.json` (for versions below angular 6) and `angular.json` (for version 6 or more). file name can be anything.

#### Step 3:
1. Change $base-color in 'ng-multiselect-dropdown.theme.scss'

### You can also checkout [sample code](https://codesandbox.io/s/custom-theme-p1556), i created in codesandbox.
================================================
FILE: e2e/app.e2e-spec.ts
================================================
import { NgTest2Page } from './app.po';
describe('ng-test2 App', () => {
let page: NgTest2Page;
beforeEach(() => {
page = new NgTest2Page();
});
it('should display welcome message', () => {
page.navigateTo();
expect(page.getParagraphText()).toEqual('Welcome to app!');
});
});
================================================
FILE: e2e/app.po.ts
================================================
import { browser, by, element } from 'protractor';
export class NgTest2Page {
navigateTo() {
return browser.get('/');
}
getParagraphText() {
return element(by.css('app-root h1')).getText();
}
}
================================================
FILE: e2e/tsconfig.e2e.json
================================================
{
"extends": "../tsconfig.json",
"compilerOptions": {
"outDir": "../out-tsc/e2e",
"baseUrl": "./",
"module": "commonjs",
"target": "es5",
"types": [
"jasmine",
"jasminewd2",
"node"
]
}
}
================================================
FILE: jest.config.js
================================================
const jestConfig = {
"preset": "jest-preset-angular",
"setupFilesAfterEnv": [
"<rootDir>/src/setup-jest.ts"
],
"testPathIgnorePatterns": [
"<rootDir>/node_modules/",
"<rootDir>/dist/",
"<rootDir>/dist-lib/",
"<rootDir>/src/test.ts"
],
"globals": {
"ts-jest": {
"tsConfig": "<rootDir>/src/tsconfig.spec.json",
"stringifyContentPathRegex": "\\.html$",
"astTransformers": [
"<rootDir>/node_modules/jest-preset-angular/InlineHtmlStripStylesTransformer"
]
}
}
}
module.exports = jestConfig;
================================================
FILE: karma.conf.js
================================================
// Karma configuration file, see link for more information
// https://karma-runner.github.io/0.13/config/configuration-file.html
module.exports = function (config) {
config.set({
basePath: '',
frameworks: ['jasmine', '@angular-devkit/build-angular'],
plugins: [
require('karma-jasmine'),
require('karma-chrome-launcher'),
require('karma-jasmine-html-reporter'),
require('karma-coverage-istanbul-reporter'),
require('@angular-devkit/build-angular/plugins/karma')
],
client:{
clearContext: false // leave Jasmine Spec Runner output visible in browser
},
coverageIstanbulReporter: {
dir: require('path').join(__dirname, 'coverage'), reports: [ 'html', 'lcovonly' ],
fixWebpackSourcePaths: true
},
reporters: ['progress', 'kjhtml'],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ['Chrome'],
singleRun: false
});
};
================================================
FILE: ng-multiselect-dropdown.theme.scss
================================================
$base-color: #337ab7;
$disable-background-color: #eceeef;
.multiselect-dropdown {
position: relative;
width: 100%;
font-size: inherit;
font-family: inherit;
.dropdown-btn {
display: inline-block;
border: 1px solid #adadad;
width: 100%;
padding: 6px 12px;
margin-bottom: 0;
font-weight: normal;
line-height: 1.52857143;
text-align: left;
vertical-align: middle;
cursor: pointer;
background-image: none;
border-radius: 4px;
.selected-item {
border: 1px solid $base-color;
margin-right: 4px;
background: $base-color;
padding: 0px 5px;
color: #fff;
border-radius: 2px;
float: left;
a {
text-decoration: none;
}
}
.selected-item:hover {
box-shadow: 1px 1px #959595;
}
.dropdown-down {
display: inline-block;
top: 10px;
width: 0;
height: 0;
border-top: 10px solid #adadad;
border-left: 10px solid transparent;
border-right: 10px solid transparent;
}
.dropdown-up {
display: inline-block;
width: 0;
height: 0;
border-bottom: 10px solid #adadad;
border-left: 10px solid transparent;
border-right: 10px solid transparent;
}
}
.disabled {
& > span {
background-color: $disable-background-color;
}
}
}
.dropdown-list {
position: absolute;
padding-top: 6px;
width: 100%;
z-index: 9999;
border: 1px solid #ccc;
border-radius: 3px;
background: #fff;
margin-top: 10px;
box-shadow: 0px 1px 5px #959595;
ul {
padding: 0px;
list-style: none;
overflow: auto;
margin: 0px;
}
li {
padding: 6px 10px;
cursor: pointer;
text-align: left;
}
.filter-textbox {
border-bottom: 1px solid #ccc;
position: relative;
padding: 10px;
input {
border: 0px;
width: 100%;
padding: 0px 0px 0px 26px;
}
input:focus {
outline: none;
}
}
}
.multiselect-item-checkbox input[type='checkbox'] {
border: 0;
clip: rect(0 0 0 0);
height: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
width: 1px;
}
.multiselect-item-checkbox input[type='checkbox']:focus + div:before,
.multiselect-item-checkbox input[type='checkbox']:hover + div:before {
border-color: $base-color;
background-color: #f2f2f2;
}
.multiselect-item-checkbox input[type='checkbox']:active + div:before {
transition-duration: 0s;
}
.multiselect-item-checkbox input[type='checkbox'] + div {
position: relative;
padding-left: 2em;
vertical-align: middle;
user-select: none;
cursor: pointer;
margin: 0px;
color: #000;
}
.multiselect-item-checkbox input[type='checkbox'] + div:before {
box-sizing: content-box;
content: '';
color: $base-color;
position: absolute;
top: 50%;
left: 0;
width: 14px;
height: 14px;
margin-top: -9px;
border: 2px solid $base-color;
text-align: center;
transition: all 0.4s ease;
}
.multiselect-item-checkbox input[type='checkbox'] + div:after {
box-sizing: content-box;
content: '';
background-color: $base-color;
position: absolute;
top: 50%;
left: 4px;
width: 10px;
height: 10px;
margin-top: -5px;
transform: scale(0);
transform-origin: 50%;
transition: transform 200ms ease-out;
}
.multiselect-item-checkbox input[type='checkbox']:disabled + div:before {
border-color: #cccccc;
}
.multiselect-item-checkbox
input[type='checkbox']:disabled:focus
+ div:before
.multiselect-item-checkbox
input[type='checkbox']:disabled:hover
+ div:before {
background-color: inherit;
}
.multiselect-item-checkbox
input[type='checkbox']:disabled:checked
+ div:before {
background-color: #cccccc;
}
.multiselect-item-checkbox input[type='checkbox'] + div:after {
background-color: transparent;
top: 50%;
left: 4px;
width: 8px;
height: 3px;
margin-top: -4px;
border-style: solid;
border-color: #ffffff;
border-width: 0 0 3px 3px;
border-image: none;
transform: rotate(-45deg) scale(0);
}
.multiselect-item-checkbox input[type='checkbox']:checked + div:after {
content: '';
transform: rotate(-45deg) scale(1);
transition: transform 200ms ease-out;
}
.multiselect-item-checkbox input[type='checkbox']:checked + div:before {
animation: borderscale 200ms ease-in;
background: $base-color;
}
.multiselect-item-checkbox input[type='checkbox']:checked + div:after {
transform: rotate(-45deg) scale(1);
}
@keyframes borderscale {
50% {
box-shadow: 0 0 0 2px $base-color;
}
}
================================================
FILE: ng-package.json
================================================
{
"dest": "dist-lib",
"lib": {
"entryFile": "src/ng-multiselect-dropdown/src/public_api.ts"
}
}
================================================
FILE: package-lib-template.json
================================================
{
"name": "ng-multiselect-dropdown",
"version": "0.1.0",
"description": "Angular Multi-Select Dropdown",
"keywords": [
"angular2",
"angular4",
"angular multiselect dropdown",
"angular2 multiselect dropdown",
"angular4 multiselect dropdown",
"ng2 multiselect dropdown",
"ng4 multiselect dropdown"
],
"author": "Nilesh Patel",
"license": "MIT",
"repository": {
"type": "git",
"url": "git+ssh://git@github.com/nileshpatel17/ng-multiselect-dropdown.git"
},
"bugs": {
"url": "https://github.com/nileshpatel17/ng-multiselect-dropdown/issues"
},
"homepage": "nileshpatel17/ng-multiselect-dropdown#readme",
"peerDependencies": {
"@angular/common": "^2.3.1 || >=4.0.0",
"@angular/core": "^2.3.1 || >=4.0.0",
"@angular/forms": "^2.3.1 || >=4.0.0"
}
}
================================================
FILE: package.json
================================================
{
"name": "ng-multiselect-dropdown",
"version": "1.0.0",
"private": true,
"description": "Angular Multi-Select Dropdown",
"author": "Nilesh Patel",
"license": "MIT",
"scripts": {
"ng": "ng",
"start": "ng serve --port 4201",
"build": "ng build",
"ng:test": "ng test",
"lint": "ng lint",
"test": "jest --watch",
"test:ci": "jest --runInBand",
"test:coverage": "jest --coverage",
"build:prod": "ng build --prod --base-href https://nileshpatel17.github.io/ng-multiselect-dropdown/",
"clear:lib": "rimraf dist-lib",
"postcopyfiles": "copyfiles -u 1 ./dist-lib/**/*.* node_modules/ng-multiselect-dropdown",
"copyfiles": "mkdir dist-lib/themes && copyfiles ng-multiselect-dropdown.theme.scss dist-lib/themes",
"build:lib": "npm run clear:lib && ng-packagr -p ng-package.json",
"postbuild:lib": "npm run copyfiles",
"prepublish": "npm run build:prod",
"publish": "ngh --no-silent false --name=\"nileshpatel17\" --email=\"nilesh.nvs@hotmail.com\"",
"deploy": "ng build --prod --base-href /ng-multiselect-dropdown/ && npm run deployOnly",
"deployOnly": "angular-cli-ghpages --no-silent --repo=https://github.com/NileshPatel17/ng-multiselect-dropdown.git --name=\"Nilesh Patel\" --email=nilesh.nvs@hotmail.com",
"contributors:add": "all-contributors add",
"contributors:generate": "all-contributors generate"
},
"keywords": [
"angular4",
"angular8",
"angular multiselect dropdown",
"angular4 multiselect dropdown",
"angular8 multiselect dropdown",
"ng multiselect dropdown",
"ng4 multiselect dropdown",
"ng8 multiselect dropdown"
],
"repository": {
"type": "git",
"url": "https://github.com/nileshpatel17/ng-multiselect-dropdown.git"
},
"bugs": {
"url": "https://github.com/nileshpatel17/ng-multiselect-dropdown/issues"
},
"homepage": "https://github.com/nileshpatel17/ng-multiselect-dropdown#readme",
"peerDependencies": {},
"devDependencies": {
"@angular-devkit/build-angular": "~16.1.6",
"@angular/animations": "16.1.7",
"@angular/cli": "^16.1.6",
"@angular/common": "16.1.7",
"@angular/compiler": "16.1.7",
"@angular/compiler-cli": "16.1.7",
"@angular/core": "16.1.7",
"@angular/forms": "16.1.7",
"@angular/http": "7.2.15",
"@angular/language-service": "16.1.7",
"@angular/platform-browser": "16.1.7",
"@angular/platform-browser-dynamic": "16.1.7",
"@angular/router": "16.1.7",
"@types/jasmine": "~3.4.0",
"@types/jasminewd2": "~2.0.2",
"@types/node": "^12.11.1",
"angular-cli-ghpages": "^0.6.0-rc.2",
"angular2-markdown": "^2.2.3",
"codelyzer": "^5.1.2",
"copyfiles": "^2.0.0",
"core-js": "^3.2.1",
"jasmine-core": "~3.5.0",
"jasmine-spec-reporter": "~5.0.0",
"jest": "^29.6.2",
"jest-preset-angular": "^7.1.1",
"karma": "~6.4.2",
"karma-chrome-launcher": "~3.1.0",
"karma-cli": "~2.0.0",
"karma-coverage-istanbul-reporter": "~3.0.2",
"karma-jasmine": "~4.0.0",
"karma-jasmine-html-reporter": "^1.5.0",
"ng-multiselect-dropdown": "^0.2.11",
"ng-packagr": "^16.1.0",
"ngx-bootstrap": "^5.1.1",
"protractor": "~7.0.0",
"rimraf": "^3.0.0",
"rxjs": "^6.2.1",
"rxjs-compat": "^6.2.1",
"ts-node": "~8.3.0",
"tslint": "~6.1.0",
"typescript": "4.9.5",
"zone.js": "~0.13.1"
},
"dependencies": {
"tslib": "^2.0.0"
}
}
================================================
FILE: protractor.conf.js
================================================
// Protractor configuration file, see link for more information
// https://github.com/angular/protractor/blob/master/lib/config.ts
const { SpecReporter } = require('jasmine-spec-reporter');
exports.config = {
allScriptsTimeout: 11000,
specs: [
'./e2e/**/*.e2e-spec.ts'
],
capabilities: {
'browserName': 'chrome'
},
directConnect: true,
baseUrl: 'http://localhost:4200/',
framework: 'jasmine',
jasmineNodeOpts: {
showColors: true,
defaultTimeoutInterval: 30000,
print: function() {}
},
onPrepare() {
require('ts-node').register({
project: 'e2e/tsconfig.e2e.json'
});
jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
}
};
================================================
FILE: publish-package.md
================================================
## step to publish
1. yarn build:lib
2. navigate to dist-lib folder
3. mark private to false
4. login to npm registry (npm login)
5. yarn publish
6. yarn deployOnly
## Angular Multiselect Dropdown
[](https://www.npmjs.com/package/ng-multiselect-dropdown)
[](https://www.npmjs.com/package/ng-multiselect-dropdown)
[](https://www.npmjs.com/package/ng-multiselect-dropdown)
[](https://www.npmjs.com/package/ng-multiselect-dropdown)
================================================
FILE: src/app/app.component.html
================================================
<main class="bd-pageheader">
<div class="container">
<h1>ng-multiselect-dropdown</h1>
<p>Native Angular component for Multiple Select</p>
<a class="btn btn-primary" href="https://github.com/nileshpatel17/ng-multiselect-dropdown">View on GitHub</a>
<div>
<iframe src="https://ghbtns.com/github-btn.html?user=NileshPatel17&repo=ng-multiselect-dropdown&type=star&count=true" frameborder="0"
scrolling="0" width="80px" height="20px">
</iframe>
<iframe src="https://ghbtns.com/github-btn.html?user=NileshPatel17&repo=ng-multiselect-dropdown&type=fork&count=true" frameborder="0"
scrolling="0" width="80px" height="20px">
</iframe>
</div>
</div>
</main>
<div class="container">
<select-section class="col-md-12"></select-section>
</div>
<footer class="footer">
<div class="container">
</div>
</footer>
================================================
FILE: src/app/app.component.scss
================================================
================================================
FILE: src/app/app.component.ts
================================================
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit {
ngOnInit() {
}
}
================================================
FILE: src/app/app.module.ts
================================================
import { NgModule } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { BrowserModule } from '@angular/platform-browser';
import { TabsModule } from 'ngx-bootstrap/tabs';
import { ButtonsModule } from 'ngx-bootstrap/buttons';
import { NgMultiSelectDropDownModule } from '../ng-multiselect-dropdown/src';
// import { NgMultiSelectDropDownModule } from 'ng-multiselect-dropdown';
import { SelectSectionComponent } from './components/select-section';
import { SampleSectionComponent } from './components/sample-section.component';
import { SingleDemoComponent } from './components/select/single-demo';
import { MultipleDemoComponent } from './components/select/multiple-demo';
import { ShCodeViewer } from '../code-viewer/code-viewer.module';
import { AppComponent } from './app.component';
@NgModule({
declarations: [SelectSectionComponent, SampleSectionComponent, SingleDemoComponent, MultipleDemoComponent, AppComponent],
imports: [
FormsModule,
ReactiveFormsModule,
BrowserModule,
TabsModule.forRoot(),
ButtonsModule.forRoot(),
NgMultiSelectDropDownModule.forRoot(),
ShCodeViewer
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule {}
================================================
FILE: src/app/components/sample-section.component.html
================================================
<ng-content></ng-content>
<!-- <div class="card card-block panel panel-default panel-body">
<br>
<div class="row" style="margin: 0px;">
<tabset>
<tab heading="Markup">
<div class="card card-block panel panel-default panel-body">
<pre class="prettyprint linenums lang-html">desc.html</pre>
</div>
</tab>
<tab heading="TypeScript">
<div class="card card-block panel panel-default panel-body">
<pre class="prettyprint linenums lang-js">desc.ts</pre>
</div>
</tab>
</tabset>
</div>
</div> -->
================================================
FILE: src/app/components/sample-section.component.ts
================================================
import { Component, Input } from '@angular/core';
@Component({
selector: 'sample-section',
templateUrl: './sample-section.component.html'
})
export class SampleSectionComponent{
@Input() public desc: any;
}
================================================
FILE: src/app/components/select/multiple-demo.html
================================================
<div style="margin-bottom: 20px;">
<div class="row">
<div class="col-md-4">
<h3>Select Multiple Cities</h3>
<form [formGroup]="myForm">
<ng-multiselect-dropdown
name="city" [placeholder]="'Select City'" [settings]="dropdownSettings" [data]="cities" formControlName="city" [disabled]="disabled" (onDropDownClose)="onDropDownClose()" (onSelect)="onItemSelect($event)" (onDeSelect)="onItemDeSelect($event)" (onSelectAll)="onSelectAll($event)">
</ng-multiselect-dropdown>
</form>
<p></p>
</div>
<div class="col-md-8">
<h3>Option</h3>
<div class="checkbox">
<label>
<input type="checkbox" [checked]="showAll" (change)="toogleShowAll()"> Show Select All
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" [checked]="ShowFilter" (change)="toogleShowFilter()"> Show Search filter
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" [checked]="disabled" [(ngModel)]="disabled"> Disabled
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" [checked]="limitSelection" [(ngModel)]="limitSelection" (change)="handleLimitSelection()"> Limit Selection to 2
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" [checked]="limitShow" [(ngModel)]="limitShow" (change)="handleLimitShow()"> Limit Items Shown to 3
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" [checked]="disableBangalore" [(ngModel)]="disableBangalore" (change)="handleDisableBangalore()"> Disable Bangalore
</label>
</div>
<div class="checkbox">
<label>
<input type="button" (click)="handleReset()" value="reset">
</label>
</div>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">Settings</div>
<div class="panel-body">
<pre>
{{dropdownSettings | json}}
</pre>
</div>
</div>
<tabset>
<tab heading="Html">
<sh-code-viewer [code]="htmlCode" [language]="'html'"></sh-code-viewer>
</tab>
<tab heading="Typescript">
<sh-code-viewer [code]="typescriptCode" [language]="'typescript'"></sh-code-viewer>
</tab>
</tabset>
</div>
================================================
FILE: src/app/components/select/multiple-demo.ts
================================================
import { FormBuilder, FormGroup } from '@angular/forms';
import { Component, OnInit } from '@angular/core';
import { IDropdownSettings } from '../../../ng-multiselect-dropdown/src';
@Component({
selector: 'multiple-demo',
templateUrl: './multiple-demo.html'
})
export class MultipleDemoComponent implements OnInit {
myForm: FormGroup;
disabled = false;
ShowFilter = true;
showAll = true;
limitSelection = false;
limitShow = false;
disableBangalore = true;
cities: Array<any> = [];
selectedItems: Array<any> = [];
dropdownSettings: IDropdownSettings = {};
htmlCode = `
<form [formGroup]="myForm">
<ng-multiselect-dropdown
name="city"
[placeholder]="'Select City'"
[data]="cities"
formControlName="city"
[disabled]="disabled"
[settings]="dropdownSettings"
(onSelect)="onItemSelect($event)"
(onDeSelect)="onItemDeSelect($event)">
</ng-multiselect-dropdown>
</form>
`;
typescriptCode = `
import { FormBuilder, FormGroup } from '@angular/forms';
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'multiple-demo',
templateUrl: './multiple-demo.html'
})
export class MultipleDemoComponent implements OnInit {
myForm:FormGroup;
disabled = false;
ShowFilter = false;
limitSelection = false;
limitShow = false;
cities: Array<any> = [];
selectedItems: Array<any> = [];
dropdownSettings: any = {};
constructor(private fb: FormBuilder) {}
ngOnInit() {
this.cities = [
{ item_id: 1, item_text: 'New Delhi' },
{ item_id: 2, item_text: 'Mumbai' },
{ item_id: 3, item_text: 'Bangalore' },
{ item_id: 4, item_text: 'Pune' },
{ item_id: 5, item_text: 'Chennai' },
{ item_id: 6, item_text: 'Navsari' }
];
this.selectedItems = [{ item_id: 4, item_text: 'Pune' }, { item_id: 6, item_text: 'Navsari' }];
this.dropdownSettings = {
singleSelection: false,
idField: 'item_id',
textField: 'item_text',
selectAllText: 'Select All',
unSelectAllText: 'UnSelect All',
itemsShowLimit: 99999,
allowSearchFilter: this.ShowFilter
};
this.myForm = this.fb.group({
city: [this.selectedItems]
});
}
onItemSelect(item: any) {
console.log('onItemSelect', item);
}
onSelectAll(items: any) {
console.log('onSelectAll', items);
}
toogleShowFilter() {
this.ShowFilter = !this.ShowFilter;
this.dropdownSettings = Object.assign({}, this.dropdownSettings, { allowSearchFilter: this.ShowFilter });
}
handleLimitSelection() {
if (this.limitSelection) {
this.dropdownSettings = Object.assign({}, this.dropdownSettings, { limitSelection: 2 });
} else {
this.dropdownSettings = Object.assign({}, this.dropdownSettings, { limitSelection: null });
}
}
handleLimitShow() {
if (this.limitShow) {
this.dropdownSettings = Object.assign({}, this.dropdownSettings, {
itemsShowLimit: 3
});
} else {
this.dropdownSettings = Object.assign({}, this.dropdownSettings, {
itemsShowLimit: 999999
});
}
console.log()
}
}
`;
constructor(private fb: FormBuilder) {}
ngOnInit() {
this.cities = [
{ item_id: 1, item_text: 'New Delhi' },
{ item_id: 2, item_text: 'Mumbai' },
{ item_id: 3, item_text: 'Bangalore', isDisabled: this.disableBangalore },
{ item_id: 4, item_text: 'Pune' },
{ item_id: 5, item_text: 'Chennai' },
{ item_id: 6, item_text: 'Navsari' }
];
this.selectedItems = [
{ item_id: 4, item_text: 'Pune' },
{ item_id: 6, item_text: 'Navsari' }
];
this.dropdownSettings = {
singleSelection: false,
defaultOpen: false,
idField: 'item_id',
textField: 'item_text',
selectAllText: 'Select All',
unSelectAllText: 'UnSelect All',
enableCheckAll: this.showAll,
itemsShowLimit: 999999,
allowSearchFilter: this.ShowFilter
};
this.myForm = this.fb.group({
city: [this.selectedItems]
});
}
onItemSelect(item: any) {
console.log('onItemSelect', item);
console.log('form model', this.myForm.get('city').value);
}
onItemDeSelect(item: any) {
console.log('onItem DeSelect', item);
console.log('form model', this.myForm.get('city').value);
}
onSelectAll(items: any) {
console.log('onSelectAll', items);
}
onDropDownClose() {
console.log('dropdown closed');
}
toogleShowAll() {
this.showAll = !this.showAll;
this.dropdownSettings = Object.assign({}, this.dropdownSettings, {
enableCheckAll: this.showAll
});
}
toogleShowFilter() {
this.ShowFilter = !this.ShowFilter;
this.dropdownSettings = Object.assign({}, this.dropdownSettings, {
allowSearchFilter: this.ShowFilter
});
}
handleLimitSelection() {
if (this.limitSelection) {
this.dropdownSettings = Object.assign({}, this.dropdownSettings, {
limitSelection: 2
});
} else {
this.dropdownSettings = Object.assign({}, this.dropdownSettings, {
limitSelection: -1
});
}
}
handleLimitShow() {
if (this.limitShow) {
this.dropdownSettings = Object.assign({}, this.dropdownSettings, {
itemsShowLimit: 3
});
} else {
this.dropdownSettings = Object.assign({}, this.dropdownSettings, {
itemsShowLimit: 999999
});
}
console.log()
}
handleDisableBangalore() {
this.cities[2].isDisabled = this.disableBangalore;
this.cities = [...this.cities];
}
handleReset() {
this.myForm.get('city').setValue([]);
}
}
================================================
FILE: src/app/components/select/single-demo.html
================================================
<div style="margin-bottom: 20px;">
<div class="row">
<div class="col-md-4">
<h3>Select a single city</h3>
<form>
<ng-multiselect-dropdown name="city" [data]="cities" [(ngModel)]="selectedItem" [settings]="dropdownSettings" (onSelect)="onItemSelect($event)"
[disabled]="disabled">
</ng-multiselect-dropdown>
</form>
</div>
<div class="col-md-8">
<h3>Option</h3>
<div class="checkbox">
<label>
<input type="checkbox" [checked]="closeDropdownSelection" (change)="toggleCloseDropdownSelection()">Close Dropdown on selection
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" [checked]="disabled" [(ngModel)]="disabled"> Disabled
</label>
</div>
<div class="checkbox">
<label>
<input type="button" (click)="handleReset()" value="reset">
</label>
</div>
</div>
</div>
<p></p>
<div class="panel panel-default">
<div class="panel-heading">Settings</div>
<div class="panel-body">
<pre>
{{dropdownSettings | json}}
</pre>
</div>
</div>
<tabset>
<tab heading="Html">
<sh-code-viewer [code]="htmlCode" [language]="'html'"></sh-code-viewer>
</tab>
<tab heading="Typescript">
<sh-code-viewer [code]="typescriptCode" [language]="'typescript'"></sh-code-viewer>
</tab>
</tabset>
</div>
================================================
FILE: src/app/components/select/single-demo.ts
================================================
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'single-demo',
templateUrl: './single-demo.html'
})
export class SingleDemoComponent implements OnInit {
cities: Array<string> = [];
selectedItem: Array<string> = [];
dropdownSettings: any = {};
closeDropdownSelection = false;
disabled = false;
htmlCode = `
<ng-multiselect-dropdown
name="city"
[data]="cities"
[(ngModel)]="selectedItem"
[settings]="dropdownSettings"
(onSelect)="onItemSelect($event)"
[disabled]="disabled"
</ng-multiselect-dropdown>
`;
typescriptCode = `
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'single-demo',
templateUrl: './single-demo.html'
})
export class SingleDemoComponent implements OnInit {
cities: Array<string> = [];
selectedItem: Array<string> = [];
dropdownSettings: any = {};
closeDropdownSelection=false;
disabled=false;
ngOnInit() {
this.cities = ['Mumbai', 'New Delhi', 'Bangaluru', 'Pune', 'Navsari'];
this.selectedItem = ['Pune'];
this.dropdownSettings = {
singleSelection: true,
selectAllText: 'Select All',
unSelectAllText: 'UnSelect All',
allowSearchFilter: true,
closeDropDownOnSelection: this.closeDropdownSelection
};
}
onItemSelect(item: any) {
console.log('onItemSelect', item);
}
toggleCloseDropdownSelection() {
this.closeDropdownSelection = !this.closeDropdownSelection;
this.dropdownSettings = Object.assign({}, this.dropdownSettings,{closeDropDownOnSelection: this.closeDropdownSelection});
}
}
`;
ngOnInit() {
this.cities = ['Mumbai', 'New Delhi', 'Bangaluru', 'Pune', 'Navsari'];
this.dropdownSettings = {
singleSelection: true,
selectAllText: 'Select All',
unSelectAllText: 'UnSelect All',
allowSearchFilter: true,
closeDropDownOnSelection: this.closeDropdownSelection
};
this.selectedItem = ['Mumbai'];
}
onItemSelect(item: any) {
console.log('onItemSelect', item);
console.log('selectedItem', this.selectedItem);
}
toggleCloseDropdownSelection() {
this.closeDropdownSelection = !this.closeDropdownSelection;
this.dropdownSettings = Object.assign({}, this.dropdownSettings, { closeDropDownOnSelection: this.closeDropdownSelection });
}
handleReset() {
this.selectedItem = [];
}
}
================================================
FILE: src/app/components/select-section.ts
================================================
import { Component } from '@angular/core';
const tabDesc: any = {
single: {
heading: 'Single'
}
,
multiple1: {
heading: 'Multiple-Example1'
}
};
@Component({
selector: 'select-section',
template: `
<section>
<div class="row">
<div class="col-md-12">
<tabset>
<tab heading="Multiple">
<sample-section [desc]="tabDesc.multiple1"><multiple-demo></multiple-demo></sample-section>
</tab>
<tab heading="Single">
<sample-section [desc]="tabDesc.single"><single-demo></single-demo></sample-section>
</tab>
</tabset>
</div>
</div>
</section>
`
})
export class SelectSectionComponent {
public currentHeading = 'Single';
public tabDesc: any = tabDesc;
}
================================================
FILE: src/app/index.ts
================================================
export * from './app.component';
export * from './app.module';
================================================
FILE: src/assets/.gitkeep
================================================
================================================
FILE: src/code-viewer/code-viewer.module.ts
================================================
import {NgModule, ModuleWithProviders} from '@angular/core';
import {CommonModule} from '@angular/common';
import {CodeViewerComponent} from './code-viewer';
@NgModule({
imports: [
CommonModule
],
declarations: [
CodeViewerComponent
],
exports: [CodeViewerComponent]
})
export class ShCodeViewer {
static forRoot(): ModuleWithProviders<ShCodeViewer> {
return {
ngModule: ShCodeViewer,
providers: []
};
}
}
================================================
FILE: src/code-viewer/code-viewer.ts
================================================
import { ElementRef, Input, OnInit, OnChanges, Component, ViewEncapsulation, ViewChild, AfterViewChecked, SimpleChanges } from '@angular/core';
declare let hljs: any;
@Component({
selector: 'sh-code-viewer',
template: `
<pre>
<code #codeView [className]="language" [innerHTML]="code"></code>
</pre>
`,
encapsulation: ViewEncapsulation.None,
styles: [
`
pre{
padding: 0;
margin: 0;
}
code{
margin: 0;
padding-top: 0;
}
/*
Monokai Sublime style. Derived from Monokai by noformnocontent http://nn.mit-license.org/
*/
.hljs {
display: block;
overflow-x: auto;
padding: 0.5em;
background: #23241f;
}
.hljs,
.hljs-tag,
.hljs-subst {
color: #f8f8f2;
}
.hljs-strong,
.hljs-emphasis {
color: #a8a8a2;
}
.hljs-bullet,
.hljs-quote,
.hljs-number,
.hljs-regexp,
.hljs-literal,
.hljs-link {
color: #ae81ff;
}
.hljs-code,
.hljs-title,
.hljs-section,
.hljs-selector-class {
color: #a6e22e;
}
.hljs-strong {
font-weight: bold;
}
.hljs-emphasis {
font-style: italic;
}
.hljs-keyword,
.hljs-selector-tag,
.hljs-name,
.hljs-attr {
color: #f92672;
}
.hljs-symbol,
.hljs-attribute {
color: #66d9ef;
}
.hljs-params,
.hljs-class .hljs-title {
color: #f8f8f2;
}
.hljs-string,
.hljs-type,
.hljs-built_in,
.hljs-builtin-name,
.hljs-selector-id,
.hljs-selector-attr,
.hljs-selector-pseudo,
.hljs-addition,
.hljs-variable,
.hljs-template-variable {
color: #e6db74;
}
.hljs-comment,
.hljs-deletion,
.hljs-meta {
color: #75715e;
}
`
]
})
export class CodeViewerComponent implements OnInit, OnChanges, AfterViewChecked {
@Input() useBr: boolean;
@Input() code: string;
@Input() language: string;
@ViewChild('codeView') codeView: ElementRef;
private needUpdate: boolean;
constructor(private elementRef: ElementRef) {}
ngOnInit() {
if (this.useBr) {
hljs.configure({ useBR: true });
}
}
ngOnChanges(changes: SimpleChanges) {
if (changes['code'] && changes['code'].currentValue) {
this.needUpdate = true;
}
}
ngAfterViewChecked() {
if (!this.needUpdate) {
return;
}
this.needUpdate = false;
if (this.codeView.nativeElement.innerHTML) {
hljs.highlightBlock(this.codeView.nativeElement);
}
}
}
================================================
FILE: src/environments/environment.prod.ts
================================================
export const environment = {
production: true
};
================================================
FILE: src/environments/environment.ts
================================================
// The file contents for the current environment will overwrite these during build.
// The build system defaults to the dev environment which uses `environment.ts`, but if you do
// `ng build --env=prod` then `environment.prod.ts` will be used instead.
// The list of which env maps to which file can be found in `.angular-cli.json`.
export const environment = {
production: false
};
================================================
FILE: src/index.html
================================================
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Angular Multi-Select Dropdown</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="A multiselect dropdown component for angular applications.">
<meta content='Angular dropdown, angular multiselect dropdown, ng-multiselect, ng-multiselect-dropdown' name='keywords'/>
<meta property="og:description" content="A multiselect dropdown component for angular applications."
/>
<meta property="og:url" content="/components/multiselectDropdown/" />
<meta property="article:tag" content="Angular" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.css">
<link rel="icon" type="image/x-icon" href="favicon.ico">
<style media="screen">
.centered {
display: flex;
flex-direction: column;
text-align: center;
align-content: center;
justify-content: center;
height: 100vh;
}
</style>
</head>
<body>
<app-root>
<span class="centered">
<h1>LOADING..</h1>
</span>
</app-root>
<script>
(function (i, s, o, g, r, a, m) {
i['GoogleAnalyticsObject'] = r;
i[r] = i[r] || function () {
(i[r].q = i[r].q || []).push(arguments)
}, i[r].l = 1 * new Date();
a = s.createElement(o),
m = s.getElementsByTagName(o)[0];
a.async = 1;
a.src = g;
m.parentNode.insertBefore(a, m)
})(window, document, 'script', 'https://www.google-analytics.com/analytics.js', 'ga');
ga('create', 'UA-103052734-3', 'auto');
ga('send', 'pageview');
</script>
<script src="assets/hljs.min.js"></script>
</body>
</html>
================================================
FILE: src/jest-global-mocks.ts
================================================
// @ts-ignore
global.CSS = null;
const webStorageMock = () => {
let storage: Record<string, any> = {};
return {
getItem: (key: string) => (key in storage ? storage[key] : null),
setItem: (key: string, value: any) => (storage[key] = value || ''),
removeItem: (key: string) => delete storage[key],
clear: () => (storage = {}),
};
};
Object.defineProperty(window, 'localStorage', { value: webStorageMock() });
Object.defineProperty(window, 'sessionStorage', { value: webStorageMock() });
Object.defineProperty(document, 'doctype', {
value: '<!DOCTYPE html>',
});
Object.defineProperty(window, 'getComputedStyle', {
value: () => {
return {
display: 'none',
appearance: ['-webkit-appearance'],
};
},
});
/**
* ISSUE: https://github.com/angular/material2/issues/7101
* Workaround for JSDOM missing transform property
*/
Object.defineProperty(document.body.style, 'transform', {
value: () => {
return {
enumerable: true,
configurable: true,
};
},
});
================================================
FILE: src/main.ts
================================================
import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
import { environment } from './environments/environment';
if (environment.production) {
enableProdMode();
}
platformBrowserDynamic().bootstrapModule(AppModule);
================================================
FILE: src/ng-multiselect-dropdown/src/click-outside.directive.ts
================================================
import {Directive, ElementRef, Output, EventEmitter, HostListener} from '@angular/core';
@Directive({
selector: '[clickOutside]'
})
export class ClickOutsideDirective {
constructor(private _elementRef: ElementRef) {
}
@Output()
public clickOutside = new EventEmitter<MouseEvent>();
@HostListener('document:click', ['$event', '$event.target'])
public onClick(event: MouseEvent, targetElement: HTMLElement): void {
if (!targetElement) {
return;
}
const clickedInside = this._elementRef.nativeElement.contains(targetElement);
if (!clickedInside) {
this.clickOutside.emit(event);
}
}
}
================================================
FILE: src/ng-multiselect-dropdown/src/index.ts
================================================
export { MultiSelectComponent } from './multiselect.component';
export { ClickOutsideDirective } from './click-outside.directive';
export { ListFilterPipe } from './list-filter.pipe';
export { NgMultiSelectDropDownModule } from './ng-multiselect-dropdown.module';
export { IDropdownSettings } from './multiselect.model'
================================================
FILE: src/ng-multiselect-dropdown/src/list-filter.pipe.ts
================================================
import { Pipe, PipeTransform } from '@angular/core';
import { ListItem } from './multiselect.model';
@Pipe({
name: 'multiSelectFilter',
pure: false
})
export class ListFilterPipe implements PipeTransform {
transform(items: ListItem[], filter: ListItem): ListItem[] {
if (!items || !filter) {
return items;
}
return items.filter((item: ListItem) => this.applyFilter(item, filter));
}
applyFilter(item: ListItem, filter: ListItem): boolean {
if (typeof item.text === 'string' && typeof filter.text === 'string') {
return !(filter.text && item.text && item.text.toLowerCase().indexOf(filter.text.toLowerCase()) === -1);
} else {
return !(filter.text && item.text && item.text.toString().toLowerCase().indexOf(filter.text.toString().toLowerCase()) === -1);
}
}
}
================================================
FILE: src/ng-multiselect-dropdown/src/multi-select.component.html
================================================
<div tabindex="0" (blur)="onTouched()" class="multiselect-dropdown" (clickOutside)="closeDropdown()">
<div [class.disabled]="disabled">
<span tabindex="-1" class="dropdown-btn" (click)="toggleDropdown($event)">
<span *ngIf="selectedItems.length == 0">{{_placeholder}}</span>
<span *ngFor="let item of selectedItems; trackBy: trackByFn;let k = index" class="selected-item-container" >
<span class="selected-item" [hidden]="k > (this._settings.itemsShowLimit-1)">
<span >{{item.text}} </span>
<a style="padding-left:2px;color:white" (click)="onItemClick($event,item)">x</a>
</span>
</span>
<span [ngClass]="{ 'dropdown-multiselect--active': _settings.defaultOpen }" style="float:right !important;padding-right:4px">
<span style="padding-right: 15px;" *ngIf="itemShowRemaining()>0">+{{itemShowRemaining()}}</span>
<span class="dropdown-multiselect__caret"></span>
</span>
</span>
</div>
<div class="dropdown-list" [hidden]="!_settings.defaultOpen">
<ul class="item1">
<li (click)="toggleSelectAll()" *ngIf="(_data.length > 0 || _settings.allowRemoteDataSearch) && !_settings.singleSelection && _settings.enableCheckAll && _settings.limitSelection===-1" class="multiselect-item-checkbox" style="border-bottom: 1px solid #ccc;padding:10px">
<input type="checkbox" aria-label="multiselect-select-all" [checked]="isAllItemsSelected()" [disabled]="disabled || isLimitSelectionReached()" />
<div>{{!isAllItemsSelected() ? _settings.selectAllText : _settings.unSelectAllText}}</div>
</li>
<li class="filter-textbox" *ngIf="(_data.length>0 || _settings.allowRemoteDataSearch) && _settings.allowSearchFilter">
<input type="text" aria-label="multiselect-search" [readOnly]="disabled" [placeholder]="_settings.searchPlaceholderText" [(ngModel)]="filter.text" (ngModelChange)="onFilterTextChange($event)">
</li>
</ul>
<ul class="item2" [style.maxHeight]="_settings.maxHeight+'px'">
<li *ngFor="let item of _data | multiSelectFilter:filter; let i = index;" (click)="onItemClick($event,item)" class="multiselect-item-checkbox">
<input type="checkbox" [attr.aria-label]="item.text" [checked]="isSelected(item)" [disabled]="disabled || (isLimitSelectionReached() && !isSelected(item)) || item.isDisabled" />
<div>{{item.text}}</div>
</li>
<li class='no-filtered-data' *ngIf="_data.length != 0 && (_data | multiSelectFilter:filter).length == 0 && !_settings.allowRemoteDataSearch">
<h5>{{_settings.noFilteredDataAvailablePlaceholderText}}</h5>
</li>
<li class='no-data' *ngIf="_data.length == 0 && !_settings.allowRemoteDataSearch">
<h5>{{_settings.noDataAvailablePlaceholderText}}</h5>
</li>
</ul>
</div>
</div>
================================================
FILE: src/ng-multiselect-dropdown/src/multi-select.component.scss
================================================
$base-color: #337ab7;
$disable-background-color: #eceeef;
.multiselect-dropdown {
position: relative;
width: 100%;
font-size: inherit;
font-family: inherit;
.dropdown-btn {
display: inline-block;
border: 1px solid #adadad;
width: 100%;
padding: 6px 12px;
margin-bottom: 0;
font-weight: normal;
line-height: 1.52857143;
text-align: left;
vertical-align: middle;
cursor: pointer;
background-image: none;
border-radius: 4px;
.selected-item-container {
display: flex;
float: left;
.selected-item{
border: 1px solid $base-color;
margin-right: 4px;
background: $base-color;
padding: 0px 5px;
color: #fff;
border-radius: 2px;
float: left;
max-width: 100px;
span {
overflow: hidden;
text-overflow: ellipsis;
}
a {
text-decoration: none;
}
}
}
.selected-item:hover {
box-shadow: 1px 1px #959595;
}
.dropdown-multiselect__caret {
line-height: 16px;
display: block;
position: absolute;
box-sizing: border-box;
width: 40px;
height: 38px;
right: 1px;
top: 0px;
padding: 4px 8px;
margin: 0;
text-decoration: none;
text-align: center;
cursor: pointer;
transition: transform 0.2s ease;
}
.dropdown-multiselect__caret:before {
position: relative;
right: 0;
top: 65%;
color: #999;
margin-top: 4px;
border-style: solid;
border-width: 8px 8px 0 8px;
border-color: #999999 transparent;
content: "";
}
.dropdown-multiselect--active .dropdown-multiselect__caret {
transform: rotateZ(180deg);
}
}
.disabled {
& > span {
background-color: $disable-background-color;
}
}
}
.dropdown-list {
position: absolute;
padding-top: 6px;
width: 100%;
z-index: 9999;
border: 1px solid #ccc;
border-radius: 3px;
background: #fff;
margin-top: 10px;
box-shadow: 0px 1px 5px #959595;
ul {
padding: 0px;
list-style: none;
overflow: auto;
margin: 0px;
}
li {
padding: 6px 10px;
cursor: pointer;
text-align: left;
}
.filter-textbox {
border-bottom: 1px solid #ccc;
position: relative;
padding: 10px;
input {
border: 0px;
width: 100%;
padding: 0px 0px 0px 26px;
}
input:focus {
outline: none;
}
}
}
.multiselect-item-checkbox:hover{
background-color: #e4e3e3;
}
.multiselect-item-checkbox input[type='checkbox'] {
border: 0;
clip: rect(0 0 0 0);
height: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
width: 1px;
}
.multiselect-item-checkbox input[type='checkbox']:focus + div:before,
.multiselect-item-checkbox input[type='checkbox']:hover + div:before {
border-color: $base-color;
background-color: #f2f2f2;
}
.multiselect-item-checkbox input[type='checkbox']:active + div:before {
transition-duration: 0s;
}
.multiselect-item-checkbox input[type='checkbox'] + div {
position: relative;
padding-left: 2em;
vertical-align: middle;
user-select: none;
cursor: pointer;
margin: 0px;
color: #000;
}
.multiselect-item-checkbox input[type='checkbox'] + div:before {
box-sizing: content-box;
content: '';
color: $base-color;
position: absolute;
top: 50%;
left: 0;
width: 14px;
height: 14px;
margin-top: -9px;
border: 2px solid $base-color;
text-align: center;
transition: all 0.4s ease;
}
.multiselect-item-checkbox input[type='checkbox'] + div:after {
box-sizing: content-box;
content: '';
background-color: $base-color;
position: absolute;
top: 50%;
left: 4px;
width: 10px;
height: 10px;
margin-top: -5px;
transform: scale(0);
transform-origin: 50%;
transition: transform 200ms ease-out;
}
.multiselect-item-checkbox input[type='checkbox']:disabled + div:before {
border-color: #cccccc;
}
.multiselect-item-checkbox
input[type='checkbox']:disabled:focus
+ div:before
.multiselect-item-checkbox
input[type='checkbox']:disabled:hover
+ div:before {
background-color: inherit;
}
.multiselect-item-checkbox
input[type='checkbox']:disabled:checked
+ div:before {
background-color: #cccccc;
}
.multiselect-item-checkbox input[type='checkbox'] + div:after {
background-color: transparent;
top: 50%;
left: 4px;
width: 8px;
height: 3px;
margin-top: -4px;
border-style: solid;
border-color: #ffffff;
border-width: 0 0 3px 3px;
border-image: none;
transform: rotate(-45deg) scale(0);
}
.multiselect-item-checkbox input[type='checkbox']:checked + div:after {
content: '';
transform: rotate(-45deg) scale(1);
transition: transform 200ms ease-out;
}
.multiselect-item-checkbox input[type='checkbox']:checked + div:before {
animation: borderscale 200ms ease-in;
background: $base-color;
}
.multiselect-item-checkbox input[type='checkbox']:checked + div:after {
transform: rotate(-45deg) scale(1);
}
@keyframes borderscale {
50% {
box-shadow: 0 0 0 2px $base-color;
}
}
================================================
FILE: src/ng-multiselect-dropdown/src/multiselect.component.ts
================================================
import { Component, HostListener, forwardRef, Input, Output, EventEmitter, ChangeDetectionStrategy, ChangeDetectorRef } from "@angular/core";
import { NG_VALUE_ACCESSOR, ControlValueAccessor } from "@angular/forms";
import { ListItem, IDropdownSettings } from "./multiselect.model";
import { ListFilterPipe } from "./list-filter.pipe";
export const DROPDOWN_CONTROL_VALUE_ACCESSOR: any = {
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => MultiSelectComponent),
multi: true
};
const noop = () => {};
@Component({
selector: "ng-multiselect-dropdown",
templateUrl: "./multi-select.component.html",
styleUrls: ["./multi-select.component.scss"],
providers: [DROPDOWN_CONTROL_VALUE_ACCESSOR],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class MultiSelectComponent implements ControlValueAccessor {
public _settings: IDropdownSettings;
public _data: Array<ListItem> = [];
public selectedItems: Array<ListItem> = [];
public isDropdownOpen = true;
_placeholder = "Select";
private _sourceDataType = null; // to keep note of the source data type. could be array of string/number/object
private _sourceDataFields: Array<String> = []; // store source data fields names
filter: ListItem = new ListItem(this.data);
defaultSettings: IDropdownSettings = {
singleSelection: false,
idField: "id",
textField: "text",
disabledField: "isDisabled",
enableCheckAll: true,
selectAllText: "Select All",
unSelectAllText: "UnSelect All",
allowSearchFilter: false,
limitSelection: -1,
clearSearchFilter: true,
maxHeight: 197,
itemsShowLimit: 999999999999,
searchPlaceholderText: "Search",
noDataAvailablePlaceholderText: "No data available",
noFilteredDataAvailablePlaceholderText: "No filtered data available",
closeDropDownOnSelection: false,
showSelectedItemsAtTop: false,
defaultOpen: false,
allowRemoteDataSearch: false
};
@Input()
public set placeholder(value: string) {
if (value) {
this._placeholder = value;
} else {
this._placeholder = "Select";
}
}
@Input()
disabled = false;
@Input()
public set settings(value: IDropdownSettings) {
if (value) {
this._settings = Object.assign(this.defaultSettings, value);
} else {
this._settings = Object.assign(this.defaultSettings);
}
}
@Input()
public set data(value: Array<any>) {
if (!value) {
this._data = [];
} else {
const firstItem = value[0];
this._sourceDataType = typeof firstItem;
this._sourceDataFields = this.getFields(firstItem);
this._data = value.map((item: any) =>
typeof item === "string" || typeof item === "number"
? new ListItem(item)
: new ListItem({
id: item[this._settings.idField],
text: item[this._settings.textField],
isDisabled: item[this._settings.disabledField]
})
);
}
}
@Output("onFilterChange")
onFilterChange: EventEmitter<ListItem> = new EventEmitter<any>();
@Output("onDropDownClose")
onDropDownClose: EventEmitter<ListItem> = new EventEmitter<any>();
@Output("onSelect")
onSelect: EventEmitter<ListItem> = new EventEmitter<any>();
@Output("onDeSelect")
onDeSelect: EventEmitter<ListItem> = new EventEmitter<any>();
@Output("onSelectAll")
onSelectAll: EventEmitter<Array<ListItem>> = new EventEmitter<Array<any>>();
@Output("onDeSelectAll")
onDeSelectAll: EventEmitter<Array<ListItem>> = new EventEmitter<Array<any>>();
private onTouchedCallback: () => void = noop;
private onChangeCallback: (_: any) => void = noop;
onFilterTextChange($event) {
this.onFilterChange.emit($event);
}
constructor(
private listFilterPipe:ListFilterPipe,
private cdr: ChangeDetectorRef
) {}
onItemClick($event: any, item: ListItem) {
if (this.disabled || item.isDisabled) {
return false;
}
const found = this.isSelected(item);
const allowAdd = this._settings.limitSelection === -1 || (this._settings.limitSelection > 0 && this.selectedItems.length < this._settings.limitSelection);
if (!found) {
if (allowAdd) {
this.addSelected(item);
}
} else {
this.removeSelected(item);
}
if (this._settings.singleSelection && this._settings.closeDropDownOnSelection) {
this.closeDropdown();
}
}
writeValue(value: any) {
if (value !== undefined && value !== null && value.length > 0) {
if (this._settings.singleSelection) {
try {
if (value.length >= 1) {
const firstItem = value[0];
this.selectedItems = [
typeof firstItem === "string" || typeof firstItem === "number"
? new ListItem(firstItem)
: new ListItem({
id: firstItem[this._settings.idField],
text: firstItem[this._settings.textField],
isDisabled: firstItem[this._settings.disabledField]
})
];
}
} catch (e) {
// console.error(e.body.msg);
}
} else {
const _data = value.map((item: any) =>
typeof item === "string" || typeof item === "number"
? new ListItem(item)
: new ListItem({
id: item[this._settings.idField],
text: item[this._settings.textField],
isDisabled: item[this._settings.disabledField]
})
);
if (this._settings.limitSelection > 0) {
this.selectedItems = _data.splice(0, this._settings.limitSelection);
} else {
this.selectedItems = _data;
}
}
} else {
this.selectedItems = [];
}
this.onChangeCallback(value);
this.cdr.markForCheck();
}
// From ControlValueAccessor interface
registerOnChange(fn: any) {
this.onChangeCallback = fn;
}
// From ControlValueAccessor interface
registerOnTouched(fn: any) {
this.onTouchedCallback = fn;
}
// Set touched on blur
@HostListener("blur")
public onTouched() {
// this.closeDropdown();
this.onTouchedCallback();
}
trackByFn(index, item) {
return item.id;
}
isSelected(clickedItem: ListItem) {
let found = false;
this.selectedItems.forEach(item => {
if (clickedItem.id === item.id) {
found = true;
}
});
return found;
}
isLimitSelectionReached(): boolean {
return this._settings.limitSelection === this.selectedItems.length;
}
isAllItemsSelected(): boolean {
// get disabld item count
let filteredItems = this.listFilterPipe.transform(this._data,this.filter);
const itemDisabledCount = filteredItems.filter(item => item.isDisabled).length;
// take disabled items into consideration when checking
if ((!this.data || this.data.length === 0) && this._settings.allowRemoteDataSearch) {
return false;
}
return filteredItems.length === this.selectedItems.length + itemDisabledCount;
}
showButton(): boolean {
if (!this._settings.singleSelection) {
if (this._settings.limitSelection > 0) {
return false;
}
// this._settings.enableCheckAll = this._settings.limitSelection === -1 ? true : false;
return true; // !this._settings.singleSelection && this._settings.enableCheckAll && this._data.length > 0;
} else {
// should be disabled in single selection mode
return false;
}
}
itemShowRemaining(): number {
return this.selectedItems.length - this._settings.itemsShowLimit;
}
addSelected(item: ListItem) {
if (this._settings.singleSelection) {
this.selectedItems = [];
this.selectedItems.push(item);
} else {
this.selectedItems.push(item);
}
this.onChangeCallback(this.emittedValue(this.selectedItems));
this.onSelect.emit(this.emittedValue(item));
}
removeSelected(itemSel: ListItem) {
this.selectedItems.forEach(item => {
if (itemSel.id === item.id) {
this.selectedItems.splice(this.selectedItems.indexOf(item), 1);
}
});
this.onChangeCallback(this.emittedValue(this.selectedItems));
this.onDeSelect.emit(this.emittedValue(itemSel));
}
emittedValue(val: any): any {
const selected = [];
if (Array.isArray(val)) {
val.map(item => {
selected.push(this.objectify(item));
});
} else {
if (val) {
return this.objectify(val);
}
}
return selected;
}
objectify(val: ListItem) {
if (this._sourceDataType === 'object') {
const obj = {};
obj[this._settings.idField] = val.id;
obj[this._settings.textField] = val.text;
if (this._sourceDataFields.includes(this._settings.disabledField)) {
obj[this._settings.disabledField] = val.isDisabled;
}
return obj;
}
if (this._sourceDataType === 'number') {
return Number(val.id);
} else {
return val.text;
}
}
toggleDropdown(evt) {
evt.preventDefault();
if (this.disabled && this._settings.singleSelection) {
return;
}
this._settings.defaultOpen = !this._settings.defaultOpen;
if (!this._settings.defaultOpen) {
this.onDropDownClose.emit();
}
}
closeDropdown() {
this._settings.defaultOpen = false;
// clear search text
if (this._settings.clearSearchFilter) {
this.filter.text = "";
}
this.onDropDownClose.emit();
}
toggleSelectAll() {
if (this.disabled) {
return false;
}
if (!this.isAllItemsSelected()) {
// filter out disabled item first before slicing
this.selectedItems = this.listFilterPipe.transform(this._data,this.filter).filter(item => !item.isDisabled).slice();
this.onSelectAll.emit(this.emittedValue(this.selectedItems));
} else {
this.selectedItems = [];
this.onDeSelectAll.emit(this.emittedValue(this.selectedItems));
}
this.onChangeCallback(this.emittedValue(this.selectedItems));
}
getFields(inputData) {
const fields = [];
if (typeof inputData !== "object") {
return fields;
}
// tslint:disable-next-line:forin
for (const prop in inputData) {
fields.push(prop);
}
return fields;
}
}
================================================
FILE: src/ng-multiselect-dropdown/src/multiselect.model.ts
================================================
export interface IDropdownSettings {
singleSelection?: boolean;
idField?: string;
textField?: string;
disabledField?: string;
enableCheckAll?: boolean;
selectAllText?: string;
unSelectAllText?: string;
allowSearchFilter?: boolean;
clearSearchFilter?: boolean;
maxHeight?: number;
itemsShowLimit?: number;
limitSelection?: number;
searchPlaceholderText?: string;
noDataAvailablePlaceholderText?: string;
noFilteredDataAvailablePlaceholderText?: string;
closeDropDownOnSelection?: boolean;
showSelectedItemsAtTop?: boolean;
defaultOpen?: boolean;
allowRemoteDataSearch?: boolean;
}
export class ListItem {
id: String | number;
text: String | number;
isDisabled?: boolean;
public constructor(source: any) {
if (typeof source === 'string' || typeof source === 'number') {
this.id = this.text = source;
this.isDisabled = false;
}
if (typeof source === 'object') {
this.id = source.id;
this.text = source.text;
this.isDisabled = source.isDisabled;
}
}
}
================================================
FILE: src/ng-multiselect-dropdown/src/ng-multiselect-dropdown.module.ts
================================================
import { NgModule, ModuleWithProviders } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { MultiSelectComponent } from './multiselect.component';
import { ClickOutsideDirective } from './click-outside.directive';
import { ListFilterPipe } from './list-filter.pipe';
@NgModule({
imports: [CommonModule, FormsModule],
declarations: [MultiSelectComponent, ClickOutsideDirective, ListFilterPipe],
providers: [ListFilterPipe],
exports: [MultiSelectComponent]
})
export class NgMultiSelectDropDownModule {
static forRoot(): ModuleWithProviders<NgMultiSelectDropDownModule> {
return {
ngModule: NgMultiSelectDropDownModule
};
}
}
================================================
FILE: src/ng-multiselect-dropdown/src/public_api.ts
================================================
export { MultiSelectComponent } from './multiselect.component';
export { NgMultiSelectDropDownModule } from './ng-multiselect-dropdown.module';
export { IDropdownSettings } from './multiselect.model';
================================================
FILE: src/ng-multiselect-dropdown/test/helper.ts
================================================
import { Type } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { TestBed, ComponentFixture, tick } from '@angular/core/testing';
import { NgMultiSelectDropDownModule } from './../src/ng-multiselect-dropdown.module';
export function newEvent(eventName: string, bubbles = false, cancelable = false) {
let evt = document.createEvent('CustomEvent'); // MUST be 'CustomEvent'
evt.initCustomEvent(eventName, bubbles, cancelable, null);
return evt;
}
export function createTestingModule<T>(cmp: Type<T>, template: string): ComponentFixture<T> {
TestBed.configureTestingModule({
imports: [FormsModule, NgMultiSelectDropDownModule],
declarations: [cmp]
})
.overrideComponent(cmp, {
set: {
template: template
}
})
.compileComponents();
const fixture = TestBed.createComponent(cmp);
fixture.detectChanges();
return fixture;
}
export function tickAndDetectChanges(fixture) {
fixture.detectChanges();
tick();
}
================================================
FILE: src/ng-multiselect-dropdown/test/list-filter.pipe.spec.ts
================================================
import { ListFilterPipe } from '../src/list-filter.pipe'
describe('multiSelectFilter', () => {
let pipe: ListFilterPipe;
beforeEach(() => {
pipe = new ListFilterPipe();
})
it('should create an instance', () => {
expect(pipe).toBeTruthy();
});
it('bad inputs:should return source data if filter data is null', () => {
const sourceData = [
{
id: 1, text: 'Navsari'
}, {
id: 2, text: 'Pune'
}];
expect(pipe.transform(sourceData, null)).toEqual(sourceData);
})
it('transform string data', () => {
const sourceData = [
{
id: 1, text: 'Navsari'
}, {
id: 2, text: 'Pune'
}];
const filterData = { id: 1, text: 'Nav' };
const expectedData = [{ id: 1, text: 'Navsari' }]
expect(pipe.transform(sourceData, filterData)).toEqual(expectedData);
})
it('transform numbers data', () => {
const sourceData = [
{
id: 1111, text: 1111
}, {
id: 2222, text: 2222
}];
const filterData = { id: 1111, text: 1111 };
const expectedData = [{ id: 1111, text: 1111 }]
expect(pipe.transform(sourceData, filterData)).toEqual(expectedData);
})
})
================================================
FILE: src/ng-multiselect-dropdown/test/multi-select-disabled-item.component.spec.ts
================================================
import { Component, Type, ViewChild, DebugElement } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { ComponentFixture, fakeAsync } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { MultiSelectComponent } from './../src/multiselect.component';
import { createTestingModule, tickAndDetectChanges } from './helper';
@Component({
template: ``
})
class Ng2MultiSelectDropdownMultipleSelectWithDisableItemComponent {
@ViewChild(MultiSelectComponent)
select: MultiSelectComponent;
cities = [
{ item_id: 1, item_text: 'Mumbai' },
{ item_id: 2, item_text: 'Bangalore' },
{ item_id: 3, item_text: 'Pune', isDisabled: true },
{ item_id: 4, item_text: 'Navsari' },
{ item_id: 5, item_text: 'New Delhi' }
];
selectedItem = [{ item_id: 1, item_text: 'Mumbai' }, { item_id: 4, item_text: 'Navsari' }];
dropdownSettings = {
singleSelection: false,
idField: 'item_id',
textField: 'item_text',
selectAllText: 'Select All',
unSelectAllText: 'UnSelect All',
badgeShowLimit: 3,
disabled: false,
allowSearchFilter: true,
closeDropDownOnSelection: true
};
}
describe('Multiple Selection:disable item', () => {
let fixture: ComponentFixture<Ng2MultiSelectDropdownMultipleSelectWithDisableItemComponent>;
beforeEach(fakeAsync(() => {
fixture = createTestingModule(
Ng2MultiSelectDropdownMultipleSelectWithDisableItemComponent,
`<div class='container'>
<ng-multiselect-dropdown name="city" [data]="cities"
[(ngModel)]="selectedItem" [settings]="dropdownSettings"
(onSelect)="onItemSelect($event)"
[disabled]="disabled">
</ng-multiselect-dropdown>
</div>`
);
}));
it('should have 4 items enabled and 1 item disabled', fakeAsync(() => {
let selCheckBoxes: HTMLLIElement[];
const sel = fixture.nativeElement.querySelectorAll('.multiselect-item-checkbox');
selCheckBoxes = Array.from(sel);
// tickAndDetectChanges(fixture);
// Mumbai
expect(selCheckBoxes[1].querySelector('div').textContent).toContain('Mumbai');
expect(selCheckBoxes[1].querySelector('input').disabled).toBe(false);
// Bangalore
expect(selCheckBoxes[2].querySelector('div').textContent).toContain('Bangalore');
expect(selCheckBoxes[2].querySelector('input').disabled).toBe(false);
expect(selCheckBoxes[3].querySelector('div').textContent).toContain('Pune');
expect(selCheckBoxes[3].querySelector('input').disabled).toBe(true); // Pune should have disable attribute
// Navsari
expect(selCheckBoxes[4].querySelector('div').textContent).toContain('Navsari');
expect(selCheckBoxes[4].querySelector('input').disabled).toBe(false);
// New Delhi
expect(selCheckBoxes[5].querySelector('div').textContent).toContain('New Delhi');
expect(selCheckBoxes[5].querySelector('input').disabled).toBe(false);
expect(fixture.componentInstance.selectedItem.length).toEqual(2);
}));
it('should not select disabled item-Pune', fakeAsync(() => {
const index = 3; // 0 is select all checkbox
let selCheckBoxes: HTMLLIElement[];
const sel = fixture.nativeElement.querySelectorAll('.multiselect-item-checkbox');
selCheckBoxes = Array.from(sel);
selCheckBoxes[index].click();
selCheckBoxes[index - 1].click(); // select Bangalore
tickAndDetectChanges(fixture);
expect(selCheckBoxes[index - 1].querySelector('input').disabled).toBe(false); // Bangalore should not have disable attribute
expect(selCheckBoxes[index].querySelector('input').disabled).toBe(true); // Pune should have disable attribute
expect(selCheckBoxes[index].querySelector('div').textContent).toContain('Pune');
expect(fixture.componentInstance.selectedItem.length).toEqual(3);
}));
it('should not select disabled item when selecting all items', fakeAsync(() => {
const index = 0; // 0 is select all checkbox
let selCheckBoxes: HTMLLIElement[];
const sel = fixture.nativeElement.querySelectorAll('.multiselect-item-checkbox');
selCheckBoxes = Array.from(sel);
selCheckBoxes[index].click(); // click on "select all"
tickAndDetectChanges(fixture);
expect(selCheckBoxes[3].querySelector('div').textContent).toContain('Pune');
expect(selCheckBoxes[3].querySelector('input').disabled).toBe(true); // Pune should have disable attribute
expect(fixture.componentInstance.selectedItem.length).toEqual(4);
}));
});
================================================
FILE: src/ng-multiselect-dropdown/test/multi-select.component.spec.ts
================================================
import { Component, Type, ViewChild, DebugElement } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { ComponentFixture, fakeAsync } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { MultiSelectComponent } from './../src/multiselect.component';
import { createTestingModule, tickAndDetectChanges } from './helper';
@Component({
template: ``
})
class Ng2MultiSelectDropdownSingleSelect {
@ViewChild(MultiSelectComponent)
select: MultiSelectComponent;
cities = [
{ item_id: 1, item_text: 'Mumbai' },
{ item_id: 2, item_text: 'Bangalore' },
{ item_id: 3, item_text: 'Pune', isDisabled: true },
{ item_id: 4, item_text: 'Navsari' },
{ item_id: 5, item_text: 'New Delhi' }
];
selectedItem = [{ item_id: 4, item_text: 'Navsari' }];
dropdownSettings = {
singleSelection: true,
idField: 'item_id',
textField: 'item_text',
selectAllText: 'Select All',
unSelectAllText: 'UnSelect All',
badgeShowLimit: 3,
disabled: false,
allowSearchFilter: false,
closeDropDownOnSelection: true
};
}
@Component({
template: ``
})
class Ng2MultiSelectDropdownMultipleSelect {
@ViewChild(MultiSelectComponent)
select: MultiSelectComponent;
cities = [
{ item_id: 1, item_text: 'Mumbai' },
{ item_id: 2, item_text: 'Bangalore' },
{ item_id: 3, item_text: 'Pune' },
{ item_id: 4, item_text: 'Navsari' },
{ item_id: 5, item_text: 'New Delhi' }
];
selectedItem = [
{ item_id: 1, item_text: 'Mumbai' },
{ item_id: 4, item_text: 'Navsari' }
];
dropdownSettings = {
singleSelection: false,
idField: 'item_id',
textField: 'item_text',
selectAllText: 'Select All',
unSelectAllText: 'UnSelect All',
badgeShowLimit: 3,
disabled: false,
allowSearchFilter: true,
closeDropDownOnSelection: true
};
}
describe('ng-multiselect-component', function() {
describe('Single Selection', () => {
let fixture: ComponentFixture<Ng2MultiSelectDropdownSingleSelect>;
beforeEach(fakeAsync(() => {
fixture = createTestingModule(
Ng2MultiSelectDropdownSingleSelect,
`<div class='container'>
<ng-multiselect-dropdown name="city" [data]="cities"
[(ngModel)]="selectedItem" [settings]="dropdownSettings"
(onSelect)="onItemSelect($event)"
[disabled]="disabled">
</ng-multiselect-dropdown>
</div>`
);
}));
it('should update internal model on select an item', fakeAsync(() => {
let index = 4;
let selCheckBoxes: HTMLLIElement[];
const sel = fixture.nativeElement.querySelectorAll(
'.multiselect-item-checkbox'
);
selCheckBoxes = Array.from(sel);
selCheckBoxes[index].click();
tickAndDetectChanges(fixture);
expect(fixture.componentInstance.selectedItem.length).toBe(1);
let selItem = fixture.componentInstance.cities[index];
expect(fixture.componentInstance.selectedItem[0]).toEqual(selItem);
index = 3;
selCheckBoxes[index].click();
tickAndDetectChanges(fixture);
expect(fixture.componentInstance.selectedItem.length).toBe(1);
selItem = fixture.componentInstance.cities[index];
expect(fixture.componentInstance.selectedItem[0]).toEqual(selItem);
index = 4;
selCheckBoxes[index].click();
tickAndDetectChanges(fixture);
expect(fixture.componentInstance.selectedItem.length).toBe(1);
selItem = fixture.componentInstance.cities[index];
expect(fixture.componentInstance.selectedItem[0]).toEqual(selItem);
}));
it('should dropdown gets close once item is selected', fakeAsync(() => {
tickAndDetectChanges(fixture);
const selDropdown: HTMLElement = fixture.nativeElement.querySelector(
'.multiselect-dropdown'
);
selDropdown.click();
tickAndDetectChanges(fixture);
expect(fixture.componentInstance.select._settings.defaultOpen).toBe(
false
);
}));
it('selected item should be correct', fakeAsync(() => {
expect(fixture.componentInstance.selectedItem.length).toBe(1);
const selItem = fixture.componentInstance.cities[3];
expect(fixture.componentInstance.selectedItem[0]).toEqual(selItem);
}));
it('should have default placeholder as "Select"', () => {
const de: DebugElement = fixture.debugElement.query(
By.css('.dropdown-btn>span')
);
const el = de.nativeElement;
expect(el.textContent).toContain('Select');
});
it('close dropdown if opened and clicked outside dropdown container', fakeAsync(() => {
fixture.componentInstance.select.isDropdownOpen = true;
const de: DebugElement = fixture.debugElement.query(By.css('.container'));
const el = de.nativeElement;
el.click();
tickAndDetectChanges(fixture);
expect(fixture.componentInstance.select._settings.defaultOpen).toBe(
false
);
}));
// it('search filter should work', () => {
// const inputSearch = fixture.nativeElement.query(By.css('input[type=text]')) as HTMLInputElement;
// inputSearch.value = 'navsari';
// inputSearch.dispatchEvent(newEvent('input'));
// tickAndDetectChanges(fixture);
// const selItems: HTMLLIElement[] = Array.from(document.querySelectorAll('.multiselect-item-checkbox'));
// expect(selItems.length).toBe(1);
// });
it('dropdown should not open when component is disabled', fakeAsync(() => {
fixture.componentInstance.select.isDropdownOpen = false;
fixture.componentInstance.dropdownSettings.disabled = true;
const de: DebugElement = fixture.debugElement.query(
By.css('.dropdown-btn')
);
const el = de.nativeElement;
tickAndDetectChanges(fixture);
expect(fixture.componentInstance.select.isDropdownOpen).toBe(false);
}));
it('should not select disabled item', fakeAsync(() => {
const selectedItems = [...fixture.componentInstance.selectedItem]; // currently selected items
const index = 2;
let selCheckBoxes: HTMLLIElement[];
const sel = fixture.nativeElement.querySelectorAll(
'.multiselect-item-checkbox'
);
selCheckBoxes = Array.from(sel);
selCheckBoxes[index].click();
tickAndDetectChanges(fixture);
expect(fixture.componentInstance.select.isDropdownOpen).toBeTruthy();
expect(fixture.componentInstance.selectedItem).toEqual(selectedItems); // selected items must've not changed
}));
});
describe('Multiple Selection', () => {
let fixture: ComponentFixture<Ng2MultiSelectDropdownMultipleSelect>;
beforeEach(fakeAsync(() => {
fixture = createTestingModule(
Ng2MultiSelectDropdownMultipleSelect,
`<div class='container'>
<ng-multiselect-dropdown name="city" [data]="cities"
[(ngModel)]="selectedItem" [settings]="dropdownSettings"
(onSelect)="onItemSelect($event)"
[disabled]="disabled">
</ng-multiselect-dropdown>
</div>`
);
}));
// it('should update internal model on select an item', fakeAsync(() => {
// let index = 4;
// let selCheckBoxes: HTMLLIElement[];
// const sel = fixture.nativeElement.querySelectorAll('.multiselect-item-checkbox');
// selCheckBoxes = Array.from(sel);
// selCheckBoxes[index].click();
// tickAndDetectChanges(fixture);
// expect(fixture.componentInstance.selectedItem.length).toBe(1);
// let selItem = fixture.componentInstance.cities[index];
// expect(fixture.componentInstance.selectedItem[0]).toEqual(selItem);
// index = 3;
// selCheckBoxes[index].click();
// tickAndDetectChanges(fixture);
// expect(fixture.componentInstance.selectedItem.length).toBe(1);
// selItem = fixture.componentInstance.cities[index];
// expect(fixture.componentInstance.selectedItem[0]).toEqual(selItem);
// index = 4;
// selCheckBoxes[index].click();
// tickAndDetectChanges(fixture);
// expect(fixture.componentInstance.selectedItem.length).toBe(1);
// selItem = fixture.componentInstance.cities[index];
// expect(fixture.componentInstance.selectedItem[0]).toEqual(selItem);
// }));
it('should dropdown gets close once item is selected', fakeAsync(() => {
tickAndDetectChanges(fixture);
const selDropdown: HTMLElement = fixture.nativeElement.querySelector(
'.multiselect-dropdown'
);
selDropdown.click();
tickAndDetectChanges(fixture);
expect(fixture.componentInstance.select._settings.defaultOpen).toBe(
false
);
}));
it('selected item should be correct', fakeAsync(() => {
expect(fixture.componentInstance.selectedItem.length).toBe(2);
// const selItem = fixture.componentInstance.cities[3];
// expect(fixture.componentInstance.selectedItem[0]).toEqual(selItem);
}));
it('should have default placeholder as "Select"', () => {
const de: DebugElement = fixture.debugElement.query(
By.css('.dropdown-btn>span')
);
const el = de.nativeElement;
expect(el.textContent).toContain('Select');
});
it('should have default placeholder for search textbox as "Search"', () => {
const de: DebugElement = fixture.debugElement.query(
By.css('.filter-textbox>input')
);
const el = de.nativeElement;
expect(el.placeholder).toBe('Search');
});
it('close dropdown if opened and clicked outside dropdown container', fakeAsync(() => {
fixture.componentInstance.select.isDropdownOpen = true;
const de: DebugElement = fixture.debugElement.query(By.css('.container'));
const el = de.nativeElement;
el.click();
tickAndDetectChanges(fixture);
expect(fixture.componentInstance.select._settings.defaultOpen).toBe(
false
);
}));
it('should have custom placeholder for "select all text" button', () => {
const de: DebugElement = fixture.debugElement.query(
By.css('.item1>li>div')
);
const el = de.nativeElement;
expect(el.textContent).toContain('Select All');
});
});
});
================================================
FILE: src/ng-multiselect-dropdown/test/multi-select.component1.spec.ts
================================================
import { Component, Type, ViewChild, DebugElement } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { ComponentFixture, fakeAsync } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { MultiSelectComponent, IDropdownSettings } from './../src';
import { createTestingModule, tickAndDetectChanges } from './helper'
@Component({
template: ``
})
class Ng2MultiSelectDropdownMultipleSelect_defaultPlaceHolderText {
@ViewChild(MultiSelectComponent) select: MultiSelectComponent;
cities = [];
selectedItem = [];
dropdownSettings: IDropdownSettings = {
singleSelection: false,
idField: 'item_id',
textField: 'item_text',
selectAllText: 'Select All',
unSelectAllText: 'UnSelect All',
allowSearchFilter: true,
closeDropDownOnSelection: true,
};
}
const NO_DATA_AVAILABLE = 'NO DATA AVAILABLE'
@Component({
template: ``
})
class Ng2MultiSelectDropdownMultipleSelect_CustomPlaceHolderText {
@ViewChild(MultiSelectComponent) select: MultiSelectComponent;
cities = [];
selectedItem = [];
dropdownSettings: IDropdownSettings = {
singleSelection: false,
idField: 'item_id',
textField: 'item_text',
selectAllText: 'Select All',
unSelectAllText: 'UnSelect All',
allowSearchFilter: true,
closeDropDownOnSelection: true,
noDataAvailablePlaceholderText: NO_DATA_AVAILABLE
};
}
describe('ng-multiselect-component: default placeholder when no data is available to show', function () {
let fixture: ComponentFixture<Ng2MultiSelectDropdownMultipleSelect_defaultPlaceHolderText>;
beforeEach(
fakeAsync(() => {
fixture = createTestingModule(
Ng2MultiSelectDropdownMultipleSelect_defaultPlaceHolderText,
`<div class='container'>
<ng-multiselect-dropdown name="city" [data]="cities"
[(ngModel)]="selectedItem" [settings]="dropdownSettings"
(onSelect)="onItemSelect($event)"
[disabled]="disabled">
</ng-multiselect-dropdown>
</div>`
);
})
);
it('should have default placeholder when no data is available to show', () => {
const de: DebugElement = fixture.debugElement.query(By.css('.no-data'));
const el = de.nativeElement;
expect(el.textContent).toContain('No data available')
})
});
describe('ng-multiselect-component: custom placeholder when no data is available to show', function () {
let fixture: ComponentFixture<Ng2MultiSelectDropdownMultipleSelect_CustomPlaceHolderText>;
beforeEach(
fakeAsync(() => {
fixture = createTestingModule(
Ng2MultiSelectDropdownMultipleSelect_CustomPlaceHolderText,
`<div class='container'>
<ng-multiselect-dropdown name="city" [data]="cities"
[(ngModel)]="selectedItem" [settings]="dropdownSettings"
(onSelect)="onItemSelect($event)"
[disabled]="disabled">
</ng-multiselect-dropdown>
</div>`
);
})
);
it('should have custom placeholder when no data is available to show', () => {
const de: DebugElement = fixture.debugElement.query(By.css('.no-data'));
const el = de.nativeElement;
expect(el.textContent).toContain(NO_DATA_AVAILABLE)
})
});
================================================
FILE: src/ng-multiselect-dropdown/test/multi-select.component2.spec.ts
================================================
import { Component, Type, ViewChild, DebugElement } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { ComponentFixture, fakeAsync } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { MultiSelectComponent, IDropdownSettings } from './../src';
import { createTestingModule, tickAndDetectChanges } from './helper'
@Component({
template: ``
})
class Ng2MultiSelectDropdownMultipleSelect {
@ViewChild(MultiSelectComponent) select: MultiSelectComponent;
cities = [
{ item_id: 0, item_text: 'Navsari' },
{ item_id: 1, item_text: 'Mumbai' },
{ item_id: 2, item_text: 'Bangalore' },
{ item_id: 3, item_text: 'Pune' },
{ item_id: 5, item_text: 'New Delhi' }
];
selectedItem = [{ item_id: 0, item_text: 'Navsari' }];
dropdownSettings: IDropdownSettings = {
singleSelection: false,
idField: 'item_id',
textField: 'item_text',
selectAllText: 'Select All',
unSelectAllText: 'UnSelect All',
allowSearchFilter: true,
closeDropDownOnSelection: true,
};
}
// https://github.com/NileshPatel17/ng-multiselect-dropdown/issues/67
describe('ng-multiselect-component: Issue No: 67( Option with value = 0 does not work)', function () {
let fixture: ComponentFixture<Ng2MultiSelectDropdownMultipleSelect>;
beforeEach(
fakeAsync(() => {
fixture = createTestingModule(
Ng2MultiSelectDropdownMultipleSelect,
`<div class='container'>
<ng-multiselect-dropdown name="city" [data]="cities"
[(ngModel)]="selectedItem" [settings]="dropdownSettings"
(onSelect)="onItemSelect($event)"
[disabled]="disabled">
</ng-multiselect-dropdown>
</div>`
);
})
);
it('should have 5 total items', () => {
let selCheckBoxes: HTMLLIElement[];
const de: DebugElement[] = fixture.debugElement.queryAll(By.css('.item2>li'));
expect(fixture.componentInstance.cities.length).toBe(5)
expect(de.length).toBe(5)
expect(fixture.componentInstance.selectedItem.length).toBe(1)
})
});
================================================
FILE: src/ng-multiselect-dropdown/test/various-input-data.spec.ts
================================================
import { Component, ViewChild } from '@angular/core';
import { ComponentFixture, fakeAsync } from '@angular/core/testing';
import { MultiSelectComponent } from './../src/multiselect.component';
import { createTestingModule, tickAndDetectChanges } from './helper';
// #region String Data
const ALL_CITIES = ['New Delhi', 'Mumbai', 'Bangalore', 'Pune', 'Chennai', 'Navsari'];
const SELECTED_CITIES = ['Mumbai', 'Navsari'];
@Component({
template: ``
})
class SingleDimensionString {
@ViewChild(MultiSelectComponent)
select: MultiSelectComponent;
cities: Array<string> = ALL_CITIES;
selectedItem: Array<string> = SELECTED_CITIES;
dropdownSettings = {
singleSelection: false,
selectAllText: 'Select All',
unSelectAllText: 'UnSelect All',
badgeShowLimit: 3,
disabled: false,
allowSearchFilter: true,
closeDropDownOnSelection: true
};
}
describe('Multiple Selection:String Data', () => {
let fixture: ComponentFixture<SingleDimensionString>;
beforeEach(fakeAsync(() => {
fixture = createTestingModule(
SingleDimensionString,
`<div class='container'>
<ng-multiselect-dropdown name='city' [data]='cities'
[(ngModel)]='selectedItem' [settings]='dropdownSettings'
(onSelect)='onItemSelect($event)'
[disabled]='disabled'>
</ng-multiselect-dropdown>
</div>`
);
}));
it('selected item should be array of string', fakeAsync(() => {
const index = 0; // 0 is select all checkbox
let selCheckBoxes: HTMLLIElement[];
const sel = fixture.nativeElement.querySelectorAll('.multiselect-item-checkbox');
selCheckBoxes = Array.from(sel);
selCheckBoxes[index].click();
tickAndDetectChanges(fixture);
expect(fixture.componentInstance.selectedItem.length).toEqual(ALL_CITIES.length);
expect(fixture.componentInstance.selectedItem).toEqual(ALL_CITIES);
}));
});
// #endregion
// #region Numeric data
const NUMBERS = [1, 3, 5, 6];
@Component({
template: ``
})
class SingleDimensionNumber {
@ViewChild(MultiSelectComponent)
select: MultiSelectComponent;
cities: Array<number> = NUMBERS;
selectedItem: Array<number> = [3];
dropdownSettings = {
singleSelection: false,
selectAllText: 'Select All',
unSelectAllText: 'UnSelect All',
badgeShowLimit: 3,
disabled: false,
allowSearchFilter: true,
closeDropDownOnSelection: true
};
}
describe('Multiple Selection:Numeric Data', () => {
let fixture: ComponentFixture<SingleDimensionNumber>;
beforeEach(fakeAsync(() => {
fixture = createTestingModule(
SingleDimensionNumber,
`<div class='container'>
<ng-multiselect-dropdown name='city' [data]='cities'
[(ngModel)]='selectedItem' [settings]='dropdownSettings'
(onSelect)='onItemSelect($event)'
[disabled]='disabled'>
</ng-multiselect-dropdown>
</div>`
);
}));
it('selected item should be array of number', fakeAsync(() => {
const index = 0; // 0 is select all checkbox
let selCheckBoxes: HTMLLIElement[];
const sel = fixture.nativeElement.querySelectorAll('.multiselect-item-checkbox');
selCheckBoxes = Array.from(sel);
selCheckBoxes[index].click();
tickAndDetectChanges(fixture);
expect(fixture.componentInstance.selectedItem.length).toEqual(NUMBERS.length);
expect(fixture.componentInstance.selectedItem).toEqual(NUMBERS);
}));
});
// #endregion
// #region Object data
interface ICity {
item_id: number;
item_text: string;
}
const CITIES: Array<ICity> = [
{ item_id: 1, item_text: 'New Delhi' },
{ item_id: 2, item_text: 'Mumbai' },
{ item_id: 3, item_text: 'Bangalore' },
{ item_id: 4, item_text: 'Pune' },
{ item_id: 5, item_text: 'Chennai' },
{ item_id: 6, item_text: 'Navsari' }
];
const SEL_CITIES: Array<ICity> = [
{ item_id: 2, item_text: 'Mumbai' },
{ item_id: 4, item_text: 'Pune' }
];
@Component({
template: ``
})
class SingleDimensionObjectComponent {
@ViewChild(MultiSelectComponent)
select: MultiSelectComponent;
cities: Array<ICity> = CITIES;
selectedItem: Array<ICity> = SEL_CITIES;
dropdownSettings = {
singleSelection: false,
idField: 'item_id',
textField: 'item_text',
selectAllText: 'Select All',
unSelectAllText: 'UnSelect All',
badgeShowLimit: 3,
disabled: false,
allowSearchFilter: true,
closeDropDownOnSelection: true
};
}
describe('Multiple Selection:Object Data', () => {
let fixture: ComponentFixture<SingleDimensionObjectComponent>;
beforeEach(fakeAsync(() => {
fixture = createTestingModule(
SingleDimensionObjectComponent,
`<div class='container'>
<ng-multiselect-dropdown name='city' [data]='cities'
[(ngModel)]='selectedItem' [settings]='dropdownSettings'
(onSelect)='onItemSelect($event)'
[disabled]='disabled'>
</ng-multiselect-dropdown>
</div>`
);
}));
it('selected item should be array of Object', fakeAsync(() => {
const index = 0; // 0 is select all checkbox
let selCheckBoxes: HTMLLIElement[];
const sel = fixture.nativeElement.querySelectorAll('.multiselect-item-checkbox');
selCheckBoxes = Array.from(sel);
selCheckBoxes[index].click();
tickAndDetectChanges(fixture);
expect(fixture.componentInstance.selectedItem.length).toEqual(CITIES.length);
expect(fixture.componentInstance.selectedItem).toEqual(CITIES);
}));
});
// #endregion
================================================
FILE: src/polyfills.ts
================================================
/**
* This file includes polyfills needed by Angular and is loaded before the app.
* You can add your own extra polyfills to this file.
*
* This file is divided into 2 sections:
* 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
* 2. Application imports. Files imported after ZoneJS that should be loaded before your main
* file.
*
* The current setup is for so-called "evergreen" browsers; the last versions of browsers that
* automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
* Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
*
* Learn more in https://angular.io/guide/browser-support
*/
/***************************************************************************************************
* BROWSER POLYFILLS
*/
/** IE10 and IE11 requires the following for NgClass support on SVG elements */
// import 'classlist.js'; // Run `npm install --save classlist.js`.
/**
* Web Animations `@angular/platform-browser/animations`
* Only required if AnimationBuilder is used within the application and using IE/Edge or Safari.
* Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0).
*/
// import 'web-animations-js'; // Run `npm install --save web-animations-js`.
/**
* By default, zone.js will patch all possible macroTask and DomEvents
* user can disable parts of macroTask/DomEvents patch by setting following flags
* because those flags need to be set before `zone.js` being loaded, and webpack
* will put import in the top of bundle, so user need to create a separate file
* in this directory (for example: zone-flags.ts), and put the following flags
* into that file, and then add the following code before importing zone.js.
* import './zone-flags.ts';
*
* The flags allowed in zone-flags.ts are listed here.
*
* The following flags will work for all browsers.
*
* (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame
* (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick
* (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames
*
* in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js
* with the following flag, it will bypass `zone.js` patch for IE/Edge
*
* (window as any).__Zone_enable_cross_context_check = true;
*
*/
/***************************************************************************************************
* Zone JS is required by default for Angular itself.
*/
import 'zone.js/dist/zone'; // Included with Angular CLI.
/***************************************************************************************************
* APPLICATION IMPORTS
*/
================================================
FILE: src/setup-jest.ts
================================================
import 'jest-preset-angular';
import './jest-global-mocks'; // browser mocks globally available for every test
================================================
FILE: src/styles.scss
================================================
/* You can add global styles to this file, and also import other style files */
.h1, .h2, .h3, h1, h2, h3 {
margin-top: 20px;
margin-bottom: 10px;
}
.h1, h1 {
font-size: 36px;
}
.btn-group-lg > .btn, .btn-lg {
font-size: 18px;
}
section {
padding-top: 30px;
}
.bd-pageheader {
// margin-top: 51px;
}
.page-header {
padding-bottom: 9px;
margin: 40px 0 20px;
border-bottom: 1px solid #eee;
}
.navbar-default .navbar-nav > li > a {
color: #777;
}
.navbar {
padding: 0;
}
.navbar-nav .nav-item {
margin-left: 0 !important;
}
.nav > li > a {
position: relative;
display: block;
padding: 10px 15px;
}
.nav .navbar-brand {
float: left;
height: 50px;
padding: 15px 15px;
font-size: 18px;
line-height: 20px;
margin-right: 0 !important;
}
.navbar-brand {
color: #777;
float: left;
height: 50px;
padding: 15px 15px;
font-size: 18px;
line-height: 20px;
}
.navbar-toggler {
margin-top: 8px;
margin-right: 15px;
}
.navbar-default .navbar-nav > li > a:focus, .navbar-default .navbar-nav > li > a:hover {
color: #333;
background-color: transparent;
}
.bd-pageheader, .bs-docs-masthead {
position: relative;
padding: 30px 0;
color: #cdbfe3;
text-align: center;
text-shadow: 0 1px 0 rgba(0, 0, 0, .1);
background-color: #6f5499;
background-image: -webkit-gradient(linear, left top, left bottom, from(#563d7c), to(#6f5499));
background-image: -webkit-linear-gradient(top, #563d7c 0, #6f5499 100%);
background-image: -o-linear-gradient(top, #563d7c 0, #6f5499 100%);
background-image: linear-gradient(to bottom, #563d7c 0, #6f5499 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#563d7c', endColorstr='#6F5499', GradientType=0);
background-repeat: repeat-x;
}
.bd-pageheader {
// margin-bottom: 40px;
font-size: 20px;
}
.bd-pageheader h1 {
margin-top: 0;
color: #fff;
}
.bd-pageheader p {
margin-bottom: 0;
font-weight: 300;
line-height: 1.4;
}
.bd-pageheader .btn {
margin: 10px 0;
}
.scrollable-menu .nav-link {
color: #337ab7;
font-size: 14px;
}
.scrollable-menu .nav-link:hover {
color: #23527c;
background-color: #eee;
}
@media (min-width: 992px) {
.bd-pageheader h1, .bd-pageheader p {
margin-right: 380px;
}
}
@media (min-width: 768px) {
.bd-pageheader {
// padding-top: 60px;
// padding-bottom: 60px;
font-size: 24px;
text-align: left;
}
.bd-pageheader h1 {
font-size: 60px;
line-height: 1;
}
.navbar-nav > li > a.nav-link {
padding-top: 15px;
padding-bottom: 15px;
font-size: 14px;
}
.navbar > .container .navbar-brand, .navbar > .container-fluid .navbar-brand {
margin-left: -15px;
}
}
@media (max-width: 767px) {
.hidden-xs {
display: none !important;
}
.navbar .container {
width: 100%;
max-width: 100%;
}
.navbar .container,
.navbar .container .navbar-header {
padding: 0;
margin: 0;
}
}
@media (max-width: 400px) {
code, kbd {
font-size: 60%;
}
}
.scrollable-menu {
height: 90vh !important;
width: 100vw;
overflow-x: hidden;
padding: 0 0 20px;
}
/**
* iPad with portrait orientation.
*/
@media all and (device-width: 768px) and (device-height: 1024px) and (orientation: portrait) {
.scrollable-menu {
height: 1024px !important;
}
}
/**
* iPad with landscape orientation.
*/
@media all and (device-width: 768px) and (device-height: 1024px) and (orientation: landscape) {
.scrollable-menu {
height: 768px !important;
}
}
/**
* iPhone 5
* You can also target devices with aspect ratio.
*/
@media screen and (device-aspect-ratio: 40/71) {
.scrollable-menu {
height: 500px !important;
}
}
.navbar-default .navbar-toggle .icon-bar {
background-color: #888;
}
.navbar-toggle:focus {
outline: 0
}
.navbar-toggle .icon-bar {
display: block;
width: 22px;
height: 2px;
border-radius: 1px
}
.navbar-toggle .icon-bar + .icon-bar {
margin-top: 4px
}
pre {
white-space: pre-wrap; /* CSS 3 */
white-space: -moz-pre-wrap; /* Mozilla, since 1999 */
white-space: -pre-wrap; /* Opera 4-6 */
white-space: -o-pre-wrap; /* Opera 7 */
word-wrap: break-word; /* Internet Explorer 5.5+ */
}
.chart-legend, .bar-legend, .line-legend, .pie-legend, .radar-legend, .polararea-legend, .doughnut-legend {
list-style-type: none;
margin-top: 5px;
text-align: center;
-webkit-padding-start: 0;
-moz-padding-start: 0;
padding-left: 0
}
.chart-legend li, .bar-legend li, .line-legend li, .pie-legend li, .radar-legend li, .polararea-legend li, .doughnut-legend li {
display: inline-block;
white-space: nowrap;
position: relative;
margin-bottom: 4px;
border-radius: 5px;
padding: 2px 8px 2px 28px;
font-size: smaller;
cursor: default
}
.chart-legend li span, .bar-legend li span, .line-legend li span, .pie-legend li span, .radar-legend li span, .polararea-legend li span, .doughnut-legend li span {
display: block;
position: absolute;
left: 0;
top: 0;
width: 20px;
height: 20px;
border-radius: 5px
}
================================================
FILE: src/test.ts
================================================
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
import 'zone.js/dist/long-stack-trace-zone';
import 'zone.js/dist/proxy.js';
import 'zone.js/dist/sync-test';
import 'zone.js/dist/jasmine-patch';
import 'zone.js/dist/async-test';
import 'zone.js/dist/fake-async-test';
import { getTestBed } from '@angular/core/testing';
import {
BrowserDynamicTestingModule,
platformBrowserDynamicTesting
} from '@angular/platform-browser-dynamic/testing';
// Unfortunately there's no typing for the `__karma__` variable. Just declare it as any.
declare const __karma__: any;
declare const require: any;
// Prevent Karma from running prematurely.
__karma__.loaded = function () {};
// First, initialize the Angular testing environment.
getTestBed().initTestEnvironment(
BrowserDynamicTestingModule,
platformBrowserDynamicTesting()
);
// Then we find all the tests.
const context = require.context('./', true, /\.spec\.ts$/);
// And load the modules.
context.keys().map(context);
// Finally, start Karma to run the tests.
__karma__.start();
================================================
FILE: src/tsconfig.app.json
================================================
{
"extends": "../tsconfig.json",
"compilerOptions": {
"outDir": "../out-tsc/app",
"baseUrl": "./",
"types": []
},
"files": [
"main.ts",
"polyfills.ts"
],
"include": [
"src/**/*.d.ts"
]
}
================================================
FILE: src/tsconfig.json
================================================
{
"compileOnSave": false,
"compilerOptions": {
"outDir": "./temp/out-tsc",
"sourceMap": true,
"declaration": false,
"moduleResolution": "node",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"target": "es5",
"mapRoot": "./",
"typeRoots": ["../node_modules/@types"],
"lib": ["es2015", "dom"]
}
}
================================================
FILE: src/tsconfig.spec.json
================================================
{
"extends": "../tsconfig.json",
"compilerOptions": {
"outDir": "../out-tsc/spec",
"baseUrl": "./",
"target": "es5",
"types": [
"jasmine",
"node"
]
},
"files": [
"test.ts",
"polyfills.ts"
],
"include": [
"**/*.spec.ts",
"**/*.d.ts"
]
}
================================================
FILE: src/typings.d.ts
================================================
/* SystemJS module definition */
declare var module: NodeModule;
interface NodeModule {
id: string;
}
================================================
FILE: tsconfig.json
================================================
{
"compileOnSave": false,
"compilerOptions": {
"module": "es2020",
"outDir": "./dist/out-tsc",
"sourceMap": true,
"declaration": false,
"moduleResolution": "node",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"target": "es2018",
"typeRoots": ["node_modules/@types"],
"lib": ["es2016","es2015", "dom"]
}
}
================================================
FILE: tslint.json
================================================
{
"rulesDirectory": [
"node_modules/codelyzer"
],
"rules": {
"arrow-return-shorthand": true,
"callable-types": true,
"class-name": true,
"comment-format": [
true,
"check-space"
],
"curly": true,
"eofline": true,
"forin": true,
"deprecation": {
"severity": "warning"
},
"import-blacklist": [
true
],
"import-spacing": true,
"indent": [
true,
"spaces"
],
"interface-over-type-literal": true,
"label-position": true,
"max-line-length": [
true,
140
],
"member-access": false,
"member-ordering": [
true,
{
"order": [
"static-field",
"instance-field",
"static-method",
"instance-method"
]
}
],
"no-arg": true,
"no-bitwise": true,
"no-console": [
true,
"debug",
"info",
"time",
"timeEnd",
"trace"
],
"no-construct": true,
"no-debugger": true,
"no-duplicate-super": true,
"no-empty": false,
"no-empty-interface": true,
"no-eval": true,
"no-inferrable-types": [
true,
"ignore-params"
],
"no-misused-new": true,
"no-non-null-assertion": true,
"no-shadowed-variable": true,
"no-string-literal": false,
"no-string-throw": true,
"no-switch-case-fall-through": true,
"no-trailing-whitespace": true,
"no-unnecessary-initializer": true,
"no-unused-expression": true,
"no-var-keyword": true,
"object-literal-sort-keys": false,
"one-line": [
true,
"check-open-brace",
"check-catch",
"check-else",
"check-whitespace"
],
"prefer-const": true,
"quotemark": [
true,
"single"
],
"radix": true,
"semicolon": [
true,
"always"
],
"triple-equals": [
true,
"allow-null-check"
],
"typedef-whitespace": [
true,
{
"call-signature": "nospace",
"index-signature": "nospace",
"parameter": "nospace",
"property-declaration": "nospace",
"variable-declaration": "nospace"
}
],
"typeof-compare": true,
"unified-signatures": true,
"variable-name": false,
"whitespace": [
true,
"check-branch",
"check-decl",
"check-operator",
"check-separator",
"check-type"
],
"directive-selector": [
true,
"attribute",
"app",
"camelCase"
],
"component-selector": [
true,
"element",
"app",
"kebab-case"
],
"use-input-property-decorator": true,
"use-output-property-decorator": true,
"use-host-property-decorator": true,
"no-input-rename": true,
"no-output-rename": true,
"use-life-cycle-interface": true,
"use-pipe-transform-interface": true,
"component-class-suffix": true,
"directive-class-suffix": true,
"no-access-missing-member": true,
"templates-use-public": true,
"invoke-injectable": true
}
}
gitextract_nsiqwz_z/ ├── .all-contributorsrc ├── .editorconfig ├── .github/ │ └── workflows/ │ └── nodejs.yml ├── .gitignore ├── CHANGELOG.md ├── ISSUE_TEMPLATE.md ├── README.md ├── angular.json ├── custom-theme.md ├── e2e/ │ ├── app.e2e-spec.ts │ ├── app.po.ts │ └── tsconfig.e2e.json ├── jest.config.js ├── karma.conf.js ├── ng-multiselect-dropdown.theme.scss ├── ng-package.json ├── package-lib-template.json ├── package.json ├── protractor.conf.js ├── publish-package.md ├── src/ │ ├── app/ │ │ ├── app.component.html │ │ ├── app.component.scss │ │ ├── app.component.ts │ │ ├── app.module.ts │ │ ├── components/ │ │ │ ├── sample-section.component.html │ │ │ ├── sample-section.component.ts │ │ │ ├── select/ │ │ │ │ ├── multiple-demo.html │ │ │ │ ├── multiple-demo.ts │ │ │ │ ├── single-demo.html │ │ │ │ └── single-demo.ts │ │ │ └── select-section.ts │ │ └── index.ts │ ├── assets/ │ │ └── .gitkeep │ ├── code-viewer/ │ │ ├── code-viewer.module.ts │ │ └── code-viewer.ts │ ├── environments/ │ │ ├── environment.prod.ts │ │ └── environment.ts │ ├── index.html │ ├── jest-global-mocks.ts │ ├── main.ts │ ├── ng-multiselect-dropdown/ │ │ ├── src/ │ │ │ ├── click-outside.directive.ts │ │ │ ├── index.ts │ │ │ ├── list-filter.pipe.ts │ │ │ ├── multi-select.component.html │ │ │ ├── multi-select.component.scss │ │ │ ├── multiselect.component.ts │ │ │ ├── multiselect.model.ts │ │ │ ├── ng-multiselect-dropdown.module.ts │ │ │ └── public_api.ts │ │ └── test/ │ │ ├── helper.ts │ │ ├── list-filter.pipe.spec.ts │ │ ├── multi-select-disabled-item.component.spec.ts │ │ ├── multi-select.component.spec.ts │ │ ├── multi-select.component1.spec.ts │ │ ├── multi-select.component2.spec.ts │ │ └── various-input-data.spec.ts │ ├── polyfills.ts │ ├── setup-jest.ts │ ├── styles.scss │ ├── test.ts │ ├── tsconfig.app.json │ ├── tsconfig.json │ ├── tsconfig.spec.json │ └── typings.d.ts ├── tsconfig.json └── tslint.json
SYMBOL INDEX (91 symbols across 22 files)
FILE: e2e/app.po.ts
class NgTest2Page (line 3) | class NgTest2Page {
method navigateTo (line 4) | navigateTo() {
method getParagraphText (line 8) | getParagraphText() {
FILE: protractor.conf.js
method onPrepare (line 22) | onPrepare() {
FILE: src/app/app.component.ts
class AppComponent (line 8) | class AppComponent implements OnInit {
method ngOnInit (line 10) | ngOnInit() {
FILE: src/app/app.module.ts
class AppModule (line 32) | class AppModule {}
FILE: src/app/components/sample-section.component.ts
class SampleSectionComponent (line 7) | class SampleSectionComponent{
FILE: src/app/components/select-section.ts
class SelectSectionComponent (line 32) | class SelectSectionComponent {
FILE: src/app/components/select/multiple-demo.ts
class MultipleDemoComponent (line 9) | class MultipleDemoComponent implements OnInit {
method constructor (line 111) | constructor(private fb: FormBuilder) {}
method ngOnInit (line 113) | ngOnInit() {
method onItemSelect (line 142) | onItemSelect(item: any) {
method onItemDeSelect (line 146) | onItemDeSelect(item: any) {
method onSelectAll (line 151) | onSelectAll(items: any) {
method onDropDownClose (line 155) | onDropDownClose() {
method toogleShowAll (line 159) | toogleShowAll() {
method toogleShowFilter (line 165) | toogleShowFilter() {
method handleLimitSelection (line 172) | handleLimitSelection() {
method handleLimitShow (line 184) | handleLimitShow() {
method handleDisableBangalore (line 200) | handleDisableBangalore() {
method handleReset (line 205) | handleReset() {
FILE: src/app/components/select/single-demo.ts
class SingleDemoComponent (line 7) | class SingleDemoComponent implements OnInit {
method ngOnInit (line 61) | ngOnInit() {
method onItemSelect (line 74) | onItemSelect(item: any) {
method toggleCloseDropdownSelection (line 79) | toggleCloseDropdownSelection() {
method handleReset (line 84) | handleReset() {
FILE: src/code-viewer/code-viewer.module.ts
class ShCodeViewer (line 14) | class ShCodeViewer {
method forRoot (line 15) | static forRoot(): ModuleWithProviders<ShCodeViewer> {
FILE: src/code-viewer/code-viewer.ts
class CodeViewerComponent (line 109) | class CodeViewerComponent implements OnInit, OnChanges, AfterViewChecked {
method constructor (line 116) | constructor(private elementRef: ElementRef) {}
method ngOnInit (line 118) | ngOnInit() {
method ngOnChanges (line 124) | ngOnChanges(changes: SimpleChanges) {
method ngAfterViewChecked (line 130) | ngAfterViewChecked() {
FILE: src/ng-multiselect-dropdown/src/click-outside.directive.ts
class ClickOutsideDirective (line 6) | class ClickOutsideDirective {
method constructor (line 7) | constructor(private _elementRef: ElementRef) {
method onClick (line 14) | public onClick(event: MouseEvent, targetElement: HTMLElement): void {
FILE: src/ng-multiselect-dropdown/src/list-filter.pipe.ts
class ListFilterPipe (line 9) | class ListFilterPipe implements PipeTransform {
method transform (line 10) | transform(items: ListItem[], filter: ListItem): ListItem[] {
method applyFilter (line 17) | applyFilter(item: ListItem, filter: ListItem): boolean {
FILE: src/ng-multiselect-dropdown/src/multiselect.component.ts
constant DROPDOWN_CONTROL_VALUE_ACCESSOR (line 6) | const DROPDOWN_CONTROL_VALUE_ACCESSOR: any = {
class MultiSelectComponent (line 20) | class MultiSelectComponent implements ControlValueAccessor {
method placeholder (line 52) | public set placeholder(value: string) {
method settings (line 63) | public set settings(value: IDropdownSettings) {
method data (line 72) | public set data(value: Array<any>) {
method onFilterTextChange (line 111) | onFilterTextChange($event) {
method constructor (line 115) | constructor(
method onItemClick (line 120) | onItemClick($event: any, item: ListItem) {
method writeValue (line 139) | writeValue(value: any) {
method registerOnChange (line 183) | registerOnChange(fn: any) {
method registerOnTouched (line 188) | registerOnTouched(fn: any) {
method onTouched (line 194) | public onTouched() {
method trackByFn (line 199) | trackByFn(index, item) {
method isSelected (line 203) | isSelected(clickedItem: ListItem) {
method isLimitSelectionReached (line 213) | isLimitSelectionReached(): boolean {
method isAllItemsSelected (line 217) | isAllItemsSelected(): boolean {
method showButton (line 228) | showButton(): boolean {
method itemShowRemaining (line 241) | itemShowRemaining(): number {
method addSelected (line 245) | addSelected(item: ListItem) {
method removeSelected (line 256) | removeSelected(itemSel: ListItem) {
method emittedValue (line 266) | emittedValue(val: any): any {
method objectify (line 280) | objectify(val: ListItem) {
method toggleDropdown (line 297) | toggleDropdown(evt) {
method closeDropdown (line 308) | closeDropdown() {
method toggleSelectAll (line 317) | toggleSelectAll() {
method getFields (line 332) | getFields(inputData) {
FILE: src/ng-multiselect-dropdown/src/multiselect.model.ts
type IDropdownSettings (line 1) | interface IDropdownSettings {
class ListItem (line 23) | class ListItem {
method constructor (line 28) | public constructor(source: any) {
FILE: src/ng-multiselect-dropdown/src/ng-multiselect-dropdown.module.ts
class NgMultiSelectDropDownModule (line 15) | class NgMultiSelectDropDownModule {
method forRoot (line 16) | static forRoot(): ModuleWithProviders<NgMultiSelectDropDownModule> {
FILE: src/ng-multiselect-dropdown/test/helper.ts
function newEvent (line 6) | function newEvent(eventName: string, bubbles = false, cancelable = false) {
function createTestingModule (line 12) | function createTestingModule<T>(cmp: Type<T>, template: string): Compone...
function tickAndDetectChanges (line 28) | function tickAndDetectChanges(fixture) {
FILE: src/ng-multiselect-dropdown/test/multi-select-disabled-item.component.spec.ts
class Ng2MultiSelectDropdownMultipleSelectWithDisableItemComponent (line 8) | @Component({
FILE: src/ng-multiselect-dropdown/test/multi-select.component.spec.ts
class Ng2MultiSelectDropdownSingleSelect (line 8) | @Component({
class Ng2MultiSelectDropdownMultipleSelect (line 34) | @Component({
FILE: src/ng-multiselect-dropdown/test/multi-select.component1.spec.ts
class Ng2MultiSelectDropdownMultipleSelect_defaultPlaceHolderText (line 8) | @Component({
constant NO_DATA_AVAILABLE (line 26) | const NO_DATA_AVAILABLE = 'NO DATA AVAILABLE'
class Ng2MultiSelectDropdownMultipleSelect_CustomPlaceHolderText (line 27) | @Component({
FILE: src/ng-multiselect-dropdown/test/multi-select.component2.spec.ts
class Ng2MultiSelectDropdownMultipleSelect (line 8) | @Component({
FILE: src/ng-multiselect-dropdown/test/various-input-data.spec.ts
constant ALL_CITIES (line 7) | const ALL_CITIES = ['New Delhi', 'Mumbai', 'Bangalore', 'Pune', 'Chennai...
constant SELECTED_CITIES (line 8) | const SELECTED_CITIES = ['Mumbai', 'Navsari'];
class SingleDimensionString (line 10) | @Component({
constant NUMBERS (line 59) | const NUMBERS = [1, 3, 5, 6];
class SingleDimensionNumber (line 60) | @Component({
type ICity (line 108) | interface ICity {
constant CITIES (line 112) | const CITIES: Array<ICity> = [
constant SEL_CITIES (line 120) | const SEL_CITIES: Array<ICity> = [
class SingleDimensionObjectComponent (line 125) | @Component({
FILE: src/typings.d.ts
type NodeModule (line 3) | interface NodeModule {
Condensed preview — 66 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (134K chars).
[
{
"path": ".all-contributorsrc",
"chars": 1757,
"preview": "{\n \"projectName\": \"ng-multiselect-dropdown\",\n \"projectOwner\": \"Nilesh Patel\",\n \"repoType\": \"github\",\n \"repoHost\": \"h"
},
{
"path": ".editorconfig",
"chars": 245,
"preview": "# Editor configuration, see http://editorconfig.org\nroot = true\n\n[*]\ncharset = utf-8\nindent_style = space\nindent_size = "
},
{
"path": ".github/workflows/nodejs.yml",
"chars": 427,
"preview": "name: Node CI - run test\n\non: [pull_request]\n\njobs:\n build:\n\n runs-on: ubuntu-latest\n\n strategy:\n matrix:\n "
},
{
"path": ".gitignore",
"chars": 645,
"preview": "# See http://help.github.com/ignore-files/ for more about ignoring files.\n\n# compiled output\n/dist\n/dist-lib\n/tmp\n/out-t"
},
{
"path": "CHANGELOG.md",
"chars": 0,
"preview": ""
},
{
"path": "ISSUE_TEMPLATE.md",
"chars": 255,
"preview": "\n**Angular version**:\n\n**ng-multiselect-dropdown version**:\n\n**Description of issue**:\n\n**Steps to reproduce**:\n\n**Expec"
},
{
"path": "README.md",
"chars": 17149,
"preview": "# Angular Multiselect Dropdown\n<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->\n[![All Contr"
},
{
"path": "angular.json",
"chars": 3876,
"preview": "{\n \"$schema\": \"./node_modules/@angular/cli/lib/config/schema.json\",\n \"version\": 1,\n \"newProjectRoot\": \"projects\",\n \""
},
{
"path": "custom-theme.md",
"chars": 892,
"preview": "# Custom Theme\n\n#### Step 1:\n\n1. copy 'ng-multiselect-dropdown.theme.scss' file located at `node_modules\\ng-multiselet-d"
},
{
"path": "e2e/app.e2e-spec.ts",
"chars": 302,
"preview": "import { NgTest2Page } from './app.po';\n\ndescribe('ng-test2 App', () => {\n let page: NgTest2Page;\n\n beforeEach(() => {"
},
{
"path": "e2e/app.po.ts",
"chars": 212,
"preview": "import { browser, by, element } from 'protractor';\n\nexport class NgTest2Page {\n navigateTo() {\n return browser.get('"
},
{
"path": "e2e/tsconfig.e2e.json",
"chars": 235,
"preview": "{\n \"extends\": \"../tsconfig.json\",\n \"compilerOptions\": {\n \"outDir\": \"../out-tsc/e2e\",\n \"baseUrl\": \"./\",\n \"modu"
},
{
"path": "jest.config.js",
"chars": 560,
"preview": "const jestConfig = {\n \"preset\": \"jest-preset-angular\",\n \"setupFilesAfterEnv\": [\n \"<rootDir>/src/setup-jest.ts\"\n ],"
},
{
"path": "karma.conf.js",
"chars": 963,
"preview": "// Karma configuration file, see link for more information\n// https://karma-runner.github.io/0.13/config/configuration-f"
},
{
"path": "ng-multiselect-dropdown.theme.scss",
"chars": 4534,
"preview": "$base-color: #337ab7;\n$disable-background-color: #eceeef;\n.multiselect-dropdown {\n position: relative;\n width: 100%;\n "
},
{
"path": "ng-package.json",
"chars": 105,
"preview": "{\n \"dest\": \"dist-lib\",\n \"lib\": {\n \"entryFile\": \"src/ng-multiselect-dropdown/src/public_api.ts\"\n }\n}"
},
{
"path": "package-lib-template.json",
"chars": 821,
"preview": "{\n \"name\": \"ng-multiselect-dropdown\",\n \"version\": \"0.1.0\",\n \"description\": \"Angular Multi-Select Dropdown\",\n \"keywor"
},
{
"path": "package.json",
"chars": 3437,
"preview": "{\n \"name\": \"ng-multiselect-dropdown\",\n \"version\": \"1.0.0\",\n \"private\": true,\n \"description\": \"Angular Multi-Select D"
},
{
"path": "protractor.conf.js",
"chars": 722,
"preview": "// Protractor configuration file, see link for more information\n// https://github.com/angular/protractor/blob/master/lib"
},
{
"path": "publish-package.md",
"chars": 683,
"preview": "## step to publish\n\n1. yarn build:lib\n2. navigate to dist-lib folder\n3. mark private to false\n4. login to npm regist"
},
{
"path": "src/app/app.component.html",
"chars": 868,
"preview": "<main class=\"bd-pageheader\">\n <div class=\"container\">\n <h1>ng-multiselect-dropdown</h1>\n <p>Native Angular compon"
},
{
"path": "src/app/app.component.scss",
"chars": 0,
"preview": ""
},
{
"path": "src/app/app.component.ts",
"chars": 248,
"preview": "import { Component, OnInit } from '@angular/core';\n\n@Component({\n selector: 'app-root',\n templateUrl: './app.compo"
},
{
"path": "src/app/app.module.ts",
"chars": 1242,
"preview": "import { NgModule } from '@angular/core';\nimport { FormsModule, ReactiveFormsModule } from '@angular/forms';\nimport { Br"
},
{
"path": "src/app/components/sample-section.component.html",
"chars": 579,
"preview": "<ng-content></ng-content>\n<!-- <div class=\"card card-block panel panel-default panel-body\">\n <br>\n <div class=\"row\" st"
},
{
"path": "src/app/components/sample-section.component.ts",
"chars": 214,
"preview": "import { Component, Input } from '@angular/core';\n\n@Component({\n selector: 'sample-section',\n templateUrl: './sample-s"
},
{
"path": "src/app/components/select/multiple-demo.html",
"chars": 2398,
"preview": "<div style=\"margin-bottom: 20px;\">\n <div class=\"row\">\n <div class=\"col-md-4\">\n <h3>Select Multiple Cities</h3>\n"
},
{
"path": "src/app/components/select/multiple-demo.ts",
"chars": 6191,
"preview": "import { FormBuilder, FormGroup } from '@angular/forms';\nimport { Component, OnInit } from '@angular/core';\nimport { IDr"
},
{
"path": "src/app/components/select/single-demo.html",
"chars": 1444,
"preview": "<div style=\"margin-bottom: 20px;\">\n\n <div class=\"row\">\n <div class=\"col-md-4\">\n <h3>Select a single city</h3>\n "
},
{
"path": "src/app/components/select/single-demo.ts",
"chars": 2598,
"preview": "import { Component, OnInit } from '@angular/core';\n\n@Component({\n selector: 'single-demo',\n templateUrl: './single-dem"
},
{
"path": "src/app/components/select-section.ts",
"chars": 734,
"preview": "import { Component } from '@angular/core';\n\nconst tabDesc: any = {\n single: {\n heading: 'Single'\n }\n ,\n multiple1"
},
{
"path": "src/app/index.ts",
"chars": 63,
"preview": "export * from './app.component';\nexport * from './app.module';\n"
},
{
"path": "src/assets/.gitkeep",
"chars": 0,
"preview": ""
},
{
"path": "src/code-viewer/code-viewer.module.ts",
"chars": 449,
"preview": "import {NgModule, ModuleWithProviders} from '@angular/core';\nimport {CommonModule} from '@angular/common';\nimport {CodeV"
},
{
"path": "src/code-viewer/code-viewer.ts",
"chars": 2320,
"preview": "import { ElementRef, Input, OnInit, OnChanges, Component, ViewEncapsulation, ViewChild, AfterViewChecked, SimpleChanges "
},
{
"path": "src/environments/environment.prod.ts",
"chars": 51,
"preview": "export const environment = {\n production: true\n};\n"
},
{
"path": "src/environments/environment.ts",
"chars": 387,
"preview": "// The file contents for the current environment will overwrite these during build.\n// The build system defaults to the "
},
{
"path": "src/index.html",
"chars": 1742,
"preview": "<!doctype html>\n<html lang=\"en\">\n\n<head>\n <meta charset=\"utf-8\">\n <title>Angular Multi-Select Dropdown</title>\n <base"
},
{
"path": "src/jest-global-mocks.ts",
"chars": 1020,
"preview": "// @ts-ignore\nglobal.CSS = null;\n\nconst webStorageMock = () => {\n let storage: Record<string, any> = {};\n return {\n "
},
{
"path": "src/main.ts",
"chars": 336,
"preview": "import { enableProdMode } from '@angular/core';\nimport { platformBrowserDynamic } from '@angular/platform-browser-dynami"
},
{
"path": "src/ng-multiselect-dropdown/src/click-outside.directive.ts",
"chars": 682,
"preview": "import {Directive, ElementRef, Output, EventEmitter, HostListener} from '@angular/core';\n\n@Directive({\n selector: '[c"
},
{
"path": "src/ng-multiselect-dropdown/src/index.ts",
"chars": 319,
"preview": "export { MultiSelectComponent } from './multiselect.component';\nexport { ClickOutsideDirective } from './click-outside.d"
},
{
"path": "src/ng-multiselect-dropdown/src/list-filter.pipe.ts",
"chars": 870,
"preview": "import { Pipe, PipeTransform } from '@angular/core';\n\nimport { ListItem } from './multiselect.model';\n\n@Pipe({\n name:"
},
{
"path": "src/ng-multiselect-dropdown/src/multi-select.component.html",
"chars": 2838,
"preview": "<div tabindex=\"0\" (blur)=\"onTouched()\" class=\"multiselect-dropdown\" (clickOutside)=\"closeDropdown()\">\n <div [class.disa"
},
{
"path": "src/ng-multiselect-dropdown/src/multi-select.component.scss",
"chars": 5132,
"preview": "$base-color: #337ab7;\n$disable-background-color: #eceeef;\n.multiselect-dropdown {\n position: relative;\n width: 100%;\n "
},
{
"path": "src/ng-multiselect-dropdown/src/multiselect.component.ts",
"chars": 10268,
"preview": "import { Component, HostListener, forwardRef, Input, Output, EventEmitter, ChangeDetectionStrategy, ChangeDetectorRef } "
},
{
"path": "src/ng-multiselect-dropdown/src/multiselect.model.ts",
"chars": 1044,
"preview": "export interface IDropdownSettings {\n singleSelection?: boolean;\n idField?: string;\n textField?: string;\n disabledFi"
},
{
"path": "src/ng-multiselect-dropdown/src/ng-multiselect-dropdown.module.ts",
"chars": 736,
"preview": "import { NgModule, ModuleWithProviders } from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { "
},
{
"path": "src/ng-multiselect-dropdown/src/public_api.ts",
"chars": 201,
"preview": "export { MultiSelectComponent } from './multiselect.component';\nexport { NgMultiSelectDropDownModule } from './ng-multis"
},
{
"path": "src/ng-multiselect-dropdown/test/helper.ts",
"chars": 1049,
"preview": "import { Type } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\nimport { TestBed, ComponentFixture, "
},
{
"path": "src/ng-multiselect-dropdown/test/list-filter.pipe.spec.ts",
"chars": 1357,
"preview": "import { ListFilterPipe } from '../src/list-filter.pipe'\ndescribe('multiSelectFilter', () => {\n let pipe: ListFilterP"
},
{
"path": "src/ng-multiselect-dropdown/test/multi-select-disabled-item.component.spec.ts",
"chars": 4455,
"preview": "import { Component, Type, ViewChild, DebugElement } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n"
},
{
"path": "src/ng-multiselect-dropdown/test/multi-select.component.spec.ts",
"chars": 10179,
"preview": "import { Component, Type, ViewChild, DebugElement } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n"
},
{
"path": "src/ng-multiselect-dropdown/test/multi-select.component1.spec.ts",
"chars": 3385,
"preview": "import { Component, Type, ViewChild, DebugElement } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n"
},
{
"path": "src/ng-multiselect-dropdown/test/multi-select.component2.spec.ts",
"chars": 2179,
"preview": "import { Component, Type, ViewChild, DebugElement } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n"
},
{
"path": "src/ng-multiselect-dropdown/test/various-input-data.spec.ts",
"chars": 5430,
"preview": "import { Component, ViewChild } from '@angular/core';\nimport { ComponentFixture, fakeAsync } from '@angular/core/testing"
},
{
"path": "src/polyfills.ts",
"chars": 2838,
"preview": "/**\n * This file includes polyfills needed by Angular and is loaded before the app.\n * You can add your own extra polyfi"
},
{
"path": "src/setup-jest.ts",
"chars": 111,
"preview": "import 'jest-preset-angular';\n\nimport './jest-global-mocks'; // browser mocks globally available for every test"
},
{
"path": "src/styles.scss",
"chars": 5063,
"preview": "/* You can add global styles to this file, and also import other style files */\n.h1, .h2, .h3, h1, h2, h3 {\n margin-top"
},
{
"path": "src/test.ts",
"chars": 1085,
"preview": "// This file is required by karma.conf.js and loads recursively all the .spec and framework files\n\nimport 'zone.js/dist/"
},
{
"path": "src/tsconfig.app.json",
"chars": 225,
"preview": "{\n \"extends\": \"../tsconfig.json\",\n \"compilerOptions\": {\n \"outDir\": \"../out-tsc/app\",\n \"baseUrl\": \"./\",\n \"type"
},
{
"path": "src/tsconfig.json",
"chars": 357,
"preview": "{\n \"compileOnSave\": false,\n \"compilerOptions\": {\n \"outDir\": \"./temp/out-tsc\",\n \"sourceMap\": true,\n \"declarati"
},
{
"path": "src/tsconfig.spec.json",
"chars": 298,
"preview": "{\n \"extends\": \"../tsconfig.json\",\n \"compilerOptions\": {\n \"outDir\": \"../out-tsc/spec\",\n \"baseUrl\": \"./\",\n \"tar"
},
{
"path": "src/typings.d.ts",
"chars": 104,
"preview": "/* SystemJS module definition */\ndeclare var module: NodeModule;\ninterface NodeModule {\n id: string;\n}\n"
},
{
"path": "tsconfig.json",
"chars": 369,
"preview": "{\n \"compileOnSave\": false,\n \"compilerOptions\": {\n \"module\": \"es2020\",\n \"outDir\": \"./dist/out-tsc\",\n \"sourceMa"
},
{
"path": "tslint.json",
"chars": 3047,
"preview": "{\n \"rulesDirectory\": [\n \"node_modules/codelyzer\"\n ],\n \"rules\": {\n \"arrow-return-shorthand\": true,\n \"callable"
}
]
About this extraction
This page contains the full source code of the NileshPatel17/ng-multiselect-dropdown GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 66 files (121.4 KB), approximately 32.2k tokens, and a symbol index with 91 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.