multi-select
This commit is contained in:
		
							parent
							
								
									420c2c18b6
								
							
						
					
					
						commit
						0f031101c9
					
				| @ -1 +1,29 @@ | ||||
| <p>multi-select works!</p> | ||||
| <ng-select [items]="data$ |async" | ||||
|            [bindLabel]="bindLabel"     | ||||
|            [bindValue]="bindValue"        | ||||
|            autofocus | ||||
|            [typeahead] = "searchInput$" | ||||
|            [trackByFn]="trackFn"    | ||||
|            [searchable]="true"    | ||||
|            [multiple]="true"  | ||||
|            (change)="valueChanged($event)"> | ||||
|            <ng-container *ngIf="hasOptionTemplate"> | ||||
|                <ng-template ng-option-tmp let-item="item" let-index="index"> | ||||
|                 <ng-container [ngTemplateOutlet]="selectOptionTemplate" | ||||
|                     [ngTemplateOutletContext]="{ | ||||
|                     $implicit: item, | ||||
|                     index: index        | ||||
|                     }"></ng-container> | ||||
|                </ng-template> | ||||
|            </ng-container> | ||||
| 
 | ||||
|            <ng-container *ngIf="hasLabelTemplate"> | ||||
|             <ng-template ng-label-tmp let-item="item" let-index="index"> | ||||
|              <ng-container [ngTemplateOutlet]="selectLabelTemplate" | ||||
|                  [ngTemplateOutletContext]="{ | ||||
|                  $implicit: item, | ||||
|                  index: index        | ||||
|                  }"></ng-container> | ||||
|             </ng-template> | ||||
|         </ng-container> | ||||
| </ng-select> | ||||
|  | ||||
| @ -1,15 +1,158 @@ | ||||
| import { Component, OnInit } from '@angular/core'; | ||||
| import { Component, OnInit, ContentChild, ViewChild, Input, Output, EventEmitter, ChangeDetectorRef, forwardRef } from '@angular/core'; | ||||
| import { SelectLabelTemplateDirective } from '../select-label-template.directive'; | ||||
| import { IDataSource, ISimpleFilter } from '@poweredsoft/data'; | ||||
| import { Observable, Subject, Subscription } from 'rxjs'; | ||||
| import { map, distinctUntilChanged, debounceTime } from 'rxjs/operators'; | ||||
| import { NgSelectComponent as SelectComponent } from '@ng-select/ng-select'; | ||||
| import { NG_VALUE_ACCESSOR } from '@angular/forms'; | ||||
| import { SelectOptionTemplateDirective } from '../select-option-template.directive'; | ||||
| 
 | ||||
| @Component({ | ||||
|   selector: 'ps-ng-multi-select', | ||||
|   templateUrl: './multi-select.component.html', | ||||
|   providers: [{ | ||||
|     provide: NG_VALUE_ACCESSOR, | ||||
|     useExisting: forwardRef(() => MultiSelectComponent), | ||||
|     multi: true | ||||
| }], | ||||
|   styleUrls: ['./multi-select.component.scss'] | ||||
| }) | ||||
| export class MultiSelectComponent implements OnInit { | ||||
| 
 | ||||
|   constructor() { } | ||||
|    | ||||
|   @ContentChild(SelectOptionTemplateDirective) optionTemplate: SelectOptionTemplateDirective; | ||||
|   @ContentChild(SelectLabelTemplateDirective) labelTemplate: SelectLabelTemplateDirective; | ||||
| 
 | ||||
|   @ViewChild(SelectComponent, { static: true }) selectComponent: SelectComponent; | ||||
|   @Input() dataSource: IDataSource<any>; | ||||
|   @Input() searchPath: string; | ||||
|   @Input() searchType: string; | ||||
|   @Input() sortingPath: string; | ||||
|   @Input() serverFiltering:boolean; | ||||
|   @Input() bindLabel:string; | ||||
|   @Input() bindValue: string; | ||||
| 
 | ||||
|   @Output('change') changeEvent = new EventEmitter(); | ||||
| 
 | ||||
|   trackFn: (item: any) => any; | ||||
|   data$ : Observable<any[]>; | ||||
|   isLoading:boolean = false; | ||||
|   searchInput$ = new Subject<string>(); | ||||
| 
 | ||||
|   private _loadingSubscription: Subscription;   | ||||
| 
 | ||||
|   constructor(private cdr: ChangeDetectorRef) {     | ||||
|     this.trackFn = this.trackBy.bind(this); | ||||
|    | ||||
|   } | ||||
| 
 | ||||
|   trackBy(item: any) { | ||||
|     return this.dataSource.resolveIdField(item); | ||||
|   } | ||||
|    | ||||
|   valueChanged(event) { | ||||
|     this.changeEvent.emit(event); | ||||
|   } | ||||
| 
 | ||||
|   writeValue(obj: any): void { | ||||
|     this.selectComponent.writeValue(obj); | ||||
|   } | ||||
|   registerOnChange(fn: any): void { | ||||
|     this.selectComponent.registerOnChange(fn); | ||||
|   } | ||||
|   registerOnTouched(fn: any): void { | ||||
|     this.selectComponent.registerOnTouched(fn); | ||||
|   } | ||||
|   setDisabledState?(isDisabled: boolean): void { | ||||
|     if (this.selectComponent.setDisabledState) | ||||
|       this.selectComponent.setDisabledState(isDisabled); | ||||
|   } | ||||
|   ngOnDestroy(): void { | ||||
|     this._loadingSubscription.unsubscribe(); | ||||
|   } | ||||
| 
 | ||||
|   ngOnInit(): void { | ||||
|     this.dataFetching();     | ||||
|     this.detectLoading(); | ||||
| 
 | ||||
|     console.log(this.serverFiltering); | ||||
| 
 | ||||
|     if(this.serverFiltering){ | ||||
|       this.searchOnServer(); | ||||
|     }else{ | ||||
|       this.refreshDataSource(); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   dataFetching(){ | ||||
|     this.data$ = this.dataSource.data$.pipe( | ||||
|       map(t => { | ||||
|         if (t == null)         | ||||
|           return []; | ||||
|         return t.data; | ||||
|       }) | ||||
|     ); | ||||
|   } | ||||
| 
 | ||||
|   detectLoading(){ | ||||
|     this._loadingSubscription = this.dataSource.loading$.subscribe(loading => {       | ||||
|       this.isLoading = loading; | ||||
|       this.cdr.detectChanges(); | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   searchOnServer(){ | ||||
|     this.searchInput$.pipe( | ||||
|       distinctUntilChanged(), // emit the difference from previous input
 | ||||
|       debounceTime(500)  // this is for delaying searching speed
 | ||||
|     ).subscribe(searchTerm => this.refreshDataSource(searchTerm, 1, 100)); // page: 1, pageSize: 50
 | ||||
| 
 | ||||
|     this.refreshDataSource(); //send the query to server to sorting & filtering by default
 | ||||
|   } | ||||
| 
 | ||||
|   get selectedModel() { | ||||
| 
 | ||||
|     return this.selectComponent.selectedItems.map(t => t.value); | ||||
|     //return this.selectComponent.hasValue ? this.selectComponent.selectedItems[0].value : null;
 | ||||
|   } | ||||
| 
 | ||||
|   refreshDataSource(searchTerm:any = null, page:number = null, pageSize:number = null){ | ||||
|     let searchfilters:ISimpleFilter[] = null; | ||||
|     if(searchTerm){ | ||||
|       searchfilters = [<ISimpleFilter>{ | ||||
|         path: this.searchPath || this.bindLabel,       | ||||
|         type: this.searchType || 'Contains', // Default: Contains
 | ||||
|         value: searchTerm | ||||
|       }] | ||||
|     } | ||||
|     this.dataSource.query({ | ||||
|       page: page, | ||||
|       pageSize: pageSize, | ||||
|       filters:searchfilters, | ||||
|       sorts:[ | ||||
|         {path: this.sortingPath || this.bindLabel, ascending: true}  | ||||
|       ] | ||||
|     }) | ||||
|   } | ||||
| 
 | ||||
|   get hasOptionTemplate() {     | ||||
|     return this.optionTemplate ? true : false; | ||||
|   } | ||||
| 
 | ||||
|   get selectOptionTemplate(){ | ||||
|     if (this.optionTemplate)     | ||||
|       return this.optionTemplate.template; | ||||
|     return null; | ||||
|   } | ||||
| 
 | ||||
|   get hasLabelTemplate() { | ||||
|     return this.labelTemplate ? true : false; | ||||
|   } | ||||
| 
 | ||||
|   get selectLabelTemplate(){ | ||||
|     if (this.labelTemplate)     | ||||
|       return this.labelTemplate.template; | ||||
|     return null; | ||||
|   } | ||||
| 
 | ||||
| } | ||||
|  | ||||
| @ -14,4 +14,14 @@ | ||||
|                     }"></ng-container> | ||||
|                </ng-template> | ||||
|            </ng-container> | ||||
| 
 | ||||
|            <ng-container *ngIf="hasLabelTemplate"> | ||||
|             <ng-template ng-label-tmp let-item="item" let-index="index"> | ||||
|              <ng-container [ngTemplateOutlet]="selectLabelTemplate" | ||||
|                  [ngTemplateOutletContext]="{ | ||||
|                  $implicit: item, | ||||
|                  index: index        | ||||
|                  }"></ng-container> | ||||
|             </ng-template> | ||||
|         </ng-container> | ||||
| </ng-select> | ||||
|  | ||||
| @ -5,6 +5,8 @@ import { Observable, Subject, Subscription } from 'rxjs'; | ||||
| import { map, distinctUntilChanged, debounceTime } from 'rxjs/operators'; | ||||
| import { NgSelectComponent as SelectComponent } from '@ng-select/ng-select'; | ||||
| import { NG_VALUE_ACCESSOR } from '@angular/forms'; | ||||
| import { SelectOptionTemplateDirective } from '../select-option-template.directive'; | ||||
| 
 | ||||
| 
 | ||||
| @Component({ | ||||
|   selector: 'ps-ng-select', | ||||
| @ -18,7 +20,10 @@ import { NG_VALUE_ACCESSOR } from '@angular/forms'; | ||||
| }) | ||||
| export class NgSelectComponent implements OnInit { | ||||
| 
 | ||||
|   @ContentChild(SelectLabelTemplateDirective) LabelTemplate: SelectLabelTemplateDirective; | ||||
|   @ContentChild(SelectOptionTemplateDirective) optionTemplate: SelectOptionTemplateDirective; | ||||
|   @ContentChild(SelectLabelTemplateDirective) labelTemplate: SelectLabelTemplateDirective; | ||||
| 
 | ||||
|    | ||||
|   @ViewChild(SelectComponent, { static: true }) selectComponent: SelectComponent; | ||||
|   @Input() dataSource: IDataSource<any>; | ||||
|   @Input() searchPath: string; | ||||
| @ -107,8 +112,8 @@ export class NgSelectComponent implements OnInit { | ||||
|     this.refreshDataSource(); //send the query to server to sorting & filtering by default
 | ||||
|   } | ||||
| 
 | ||||
|   get selectedModel() { | ||||
|     return this.selectComponent.hasValue ? this.selectComponent.selectedItems[0].value : null; | ||||
|   get selectedModel() {     | ||||
|     return this.selectComponent.hasValue ? this.selectComponent.selectedItems[0] : null; | ||||
|   } | ||||
| 
 | ||||
|   refreshDataSource(searchTerm:any = null, page:number = null, pageSize:number = null){ | ||||
| @ -131,13 +136,22 @@ export class NgSelectComponent implements OnInit { | ||||
|   } | ||||
| 
 | ||||
|   get hasOptionTemplate() {     | ||||
|     return this.LabelTemplate ? true : false; | ||||
|     return this.optionTemplate ? true : false; | ||||
|   } | ||||
| 
 | ||||
|   get selectOptionTemplate(){ | ||||
|     if (this.LabelTemplate)     | ||||
|       return this.LabelTemplate.template; | ||||
|     if (this.optionTemplate)     | ||||
|       return this.optionTemplate.template; | ||||
|     return null; | ||||
|   } | ||||
| 
 | ||||
|   get hasLabelTemplate() { | ||||
|     return this.labelTemplate ? true : false; | ||||
|   } | ||||
| 
 | ||||
|   get selectLabelTemplate(){ | ||||
|     if (this.labelTemplate)     | ||||
|       return this.labelTemplate.template; | ||||
|     return null; | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -5,11 +5,12 @@ import { MultiSelectComponent } from './multi-select/multi-select.component'; | ||||
| import { FormsModule } from '@angular/forms'; | ||||
| import { NgSelectModule } from '@ng-select/ng-select'; | ||||
| import { SelectLabelTemplateDirective } from './select-label-template.directive'; | ||||
| import { SelectOptionTemplateDirective } from './select-option-template.directive'; | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| @NgModule({ | ||||
|   declarations: [NgSelectComponent, MultiSelectComponent, SelectLabelTemplateDirective], | ||||
|   declarations: [NgSelectComponent, MultiSelectComponent, SelectLabelTemplateDirective, SelectOptionTemplateDirective], | ||||
|   imports: [ | ||||
|     CommonModule, | ||||
|     FormsModule, | ||||
| @ -18,7 +19,8 @@ import { SelectLabelTemplateDirective } from './select-label-template.directive' | ||||
|   exports:[ | ||||
|     NgSelectComponent, | ||||
|     MultiSelectComponent, | ||||
|     SelectLabelTemplateDirective | ||||
|     SelectLabelTemplateDirective, | ||||
|     SelectOptionTemplateDirective | ||||
|   ] | ||||
| }) | ||||
| export class PsNgSelectorsModule { } | ||||
|  | ||||
| @ -1,8 +0,0 @@ | ||||
| import { SelectLabelTemplateDirective } from './select-label-template.directive'; | ||||
| 
 | ||||
| describe('SelectLabelTemplateDirective', () => { | ||||
|   it('should create an instance', () => { | ||||
|     const directive = new SelectLabelTemplateDirective(); | ||||
|     expect(directive).toBeTruthy(); | ||||
|   }); | ||||
| }); | ||||
| @ -1,7 +1,7 @@ | ||||
| import { Directive, TemplateRef } from '@angular/core'; | ||||
| 
 | ||||
| @Directive({ | ||||
|   selector: '[psSelectOptionTemplate]' | ||||
|   selector: '[psNgSelectOption]' | ||||
| }) | ||||
| export class SelectOptionTemplateDirective { | ||||
| 
 | ||||
| @ -6,6 +6,7 @@ export * from './lib/ps-ng-selectors/ps-ng-selectors.module'; | ||||
| export * from './lib/ps-ng-selectors/ng-select/ng-select.component'; | ||||
| export * from './lib/ps-ng-selectors/multi-select/multi-select.component'; | ||||
| export * from './lib/ps-ng-selectors/select-label-template.directive'; | ||||
| export * from './lib/ps-ng-selectors/select-option-template.directive' | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|  | ||||
| @ -4,17 +4,17 @@ import { NgSelectComponent } from './ng-select/ng-select.component'; | ||||
| import { NgMultiSelectComponent } from './ng-multi-select/ng-multi-select.component'; | ||||
| import { FormsModule, ReactiveFormsModule } from '@angular/forms'; | ||||
| import { NgSelectModule } from '@ng-select/ng-select'; | ||||
| import { SelectOptionTemplateDirective } from './select-option-template.directive'; | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| @NgModule({ | ||||
|   declarations: [NgSelectComponent, NgMultiSelectComponent, SelectOptionTemplateDirective], | ||||
|   declarations: [NgSelectComponent, NgMultiSelectComponent ], | ||||
|   imports: [ | ||||
|     CommonModule, | ||||
|     FormsModule, | ||||
|     NgSelectModule, | ||||
|   ], | ||||
|   exports:[NgSelectComponent,NgMultiSelectComponent,SelectOptionTemplateDirective] | ||||
|   exports:[NgSelectComponent,NgMultiSelectComponent] | ||||
| }) | ||||
| export class PsSelectorsModule { } | ||||
|  | ||||
| @ -17,4 +17,3 @@ export * from './lib/data-grid/directives/data-grid-col-sort.directive'; | ||||
| export * from './lib/ps-selectors/ps-selectors.module'; | ||||
| export * from './lib/ps-selectors/ng-select/ng-select.component'; | ||||
| export * from './lib/ps-selectors/ng-multi-select/ng-multi-select.component'; | ||||
| export * from './lib/ps-selectors/select-option-template.directive'; | ||||
| @ -1,39 +1,34 @@ | ||||
| <h2>Single Select Demo</h2> | ||||
| <ps-ng-select [dataSource]="merchantDataSource" bindLabel="name" bindValue="id" [serverFiltering]="true"> | ||||
|     <div *psNgSelectLabel="let item"> | ||||
|         {{ item.name }} - {{ item.address }} | ||||
| <h2>Single Select Demo | ngModel | option template</h2> | ||||
| <ps-ng-select [dataSource]="merchantDataSource" bindLabel="name" bindValue="id" [(ngModel)]="myValue"> | ||||
|     <div *psNgSelectOption="let item"> | ||||
|         <!-- {{ item.name }} - {{ item.address }} --> | ||||
|         {{item | json}} | ||||
|     </div> | ||||
| </ps-ng-select> | ||||
| 
 | ||||
| selected: {{ myValue | json }}  | ||||
| 
 | ||||
| <!-- <h2>Multi-Select Demo</h2> | ||||
| <ps-ng-multi-select [dataSource]="merchantDataSource" [searchPath]="'name'" [sortingPath]="'name'" [disableServer]="false" [bindLabel]="'name'"></ps-ng-multi-select> --> | ||||
| 
 | ||||
| 
 | ||||
| <!-- <form> | ||||
|     <ps-ng-select [dataSource]="merchantDataSource" searchPath="name" sortingPath="name" formControlName="name" [disableServer]="false" bindLabel="name"> | ||||
|         <ng-template *psNgSelectLabel="let item" ng-label-tmp > | ||||
|             <span>Name: </span> {{item.name}} | <span>Adress: </span>{{item.address}} | <span>Date: </span>{{item.openDate}} | ||||
|         </ng-template> | ||||
|     </ps-ng-select> | ||||
| </form> --> | ||||
| 
 | ||||
| <!--  | ||||
| <h2>Single Select With Form | formGroup | option template</h2> | ||||
| <form #form [formGroup]="myForm"> | ||||
|     <ps-ng-select [dataSource]="merchantDataSource" bindLabel="name" bindValue="id" formControlName="merchantId"> | ||||
|         <div *psNgSelectLabel="let item"> | ||||
|     <ps-ng-select [dataSource]="merchantDataSource" bindLabel="name" bindValue="id" formControlName="merchantId" [serverFiltering]="true"> | ||||
|         <div *psNgSelectOption="let item"> | ||||
|             {{ item.name }} - {{ item.address }} | ||||
|         </div> | ||||
|     </ps-ng-select> | ||||
| </form> | ||||
| 
 | ||||
| {{ myForm.value | json }} | ||||
| selected:  {{ myForm.value | json }} | ||||
| 
 | ||||
| 
 | ||||
| <ps-ng-select [dataSource]="merchantDataSource" bindLabel="name" bindValue="id" [(ngModel)]="myValue"> | ||||
|     <div *psNgSelectLabel="let item"> | ||||
|         {{ item.name }} - {{ item.address }} | ||||
| <h2>Single Select Demo | label Template</h2> | ||||
| <ps-ng-select [dataSource]="merchantDataSource" bindLabel="name" bindValue="id" [(ngModel)]="myValue" [serverFiltering]="true"> | ||||
|     <div  *psNgSelectLabel="let item"> | ||||
|         <span>Name: </span>{{ item.name }} - <img src="/src/assets/avatar.png"><span> Address: </span>{{item.address }} | ||||
|     </div> | ||||
| </ps-ng-select> | ||||
| 
 | ||||
| {{ myValue | json }} --> | ||||
|  <h2>Multi-Select Demo</h2> | ||||
| <ps-ng-multi-select [dataSource]="merchantDataSource" bindLabel="name" bindValue="id"  [serverFiltering]="true" [(ngModel)]="myValue" > | ||||
| 
 | ||||
| </ps-ng-multi-select> | ||||
| selected: {{ myValue | json }}  | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										
											BIN
										
									
								
								src/assets/avatar.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								src/assets/avatar.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 194 B | 
		Loading…
	
		Reference in New Issue
	
	Block a user