Browse Source

fix(admin-ui): Fix asset search component

Michael Bromley 4 years ago
parent
commit
d65277e6ed

+ 56 - 0
packages/admin-ui/src/lib/core/src/common/single-search-selection-model.ts

@@ -0,0 +1,56 @@
+import { NgOption, SelectionModel } from '@ng-select/ng-select';
+
+/**
+ * A custom SelectionModel for the NgSelect component which only allows a single
+ * search term at a time.
+ */
+export class SingleSearchSelectionModel implements SelectionModel {
+    private _selected: NgOption[] = [];
+
+    get value(): NgOption[] {
+        return this._selected;
+    }
+
+    select(item: NgOption, multiple: boolean, groupAsModel: boolean) {
+        item.selected = true;
+        if (groupAsModel || !item.children) {
+            if ((item.value as any).label) {
+                const isSearchTerm = (i: any) => !!i.value.label;
+                const searchTerms = this._selected.filter(isSearchTerm);
+                if (searchTerms.length > 0) {
+                    // there is already a search term, so replace it with this new one.
+                    this._selected = this._selected.filter(i => !isSearchTerm(i)).concat(item);
+                } else {
+                    this._selected.push(item);
+                }
+            } else {
+                this._selected.push(item);
+            }
+        }
+    }
+
+    unselect(item: NgOption, multiple: boolean) {
+        this._selected = this._selected.filter(x => x !== item);
+        item.selected = false;
+    }
+
+    clear(keepDisabled: boolean) {
+        this._selected = keepDisabled ? this._selected.filter(x => x.disabled) : [];
+    }
+
+    private _setChildrenSelectedState(children: NgOption[], selected: boolean) {
+        children.forEach(x => (x.selected = selected));
+    }
+
+    private _removeChildren(parent: NgOption) {
+        this._selected = this._selected.filter(x => x.parent !== parent);
+    }
+
+    private _removeParent(parent: NgOption) {
+        this._selected = this._selected.filter(x => x !== parent);
+    }
+}
+
+export function SingleSearchSelectionModelFactory() {
+    return new SingleSearchSelectionModel();
+}

+ 2 - 2
packages/admin-ui/src/lib/core/src/shared/components/asset-search-input/asset-search-input.component.html

@@ -1,5 +1,5 @@
 <ng-select
 <ng-select
-    [addTag]="true"
+    [addTag]="addTagFn"
     [placeholder]="'catalog.search-asset-name-or-tag' | translate"
     [placeholder]="'catalog.search-asset-name-or-tag' | translate"
     [items]="tags"
     [items]="tags"
     [searchFn]="filterTagResults"
     [searchFn]="filterTagResults"
@@ -24,7 +24,7 @@
             <vdr-chip [colorFrom]="item.value" icon="close" (iconClick)="clear(item)"><clr-icon shape="tag" class="mr2"></clr-icon> {{ item.value }}</vdr-chip>
             <vdr-chip [colorFrom]="item.value" icon="close" (iconClick)="clear(item)"><clr-icon shape="tag" class="mr2"></clr-icon> {{ item.value }}</vdr-chip>
         </ng-container>
         </ng-container>
         <ng-container *ngIf="!item.value">
         <ng-container *ngIf="!item.value">
-            <vdr-chip [icon]="'times'" (iconClick)="clear(item)">"{{ item.label }}"</vdr-chip>
+            <vdr-chip [icon]="'times'" (iconClick)="clear(item)">"{{ item.label || item }}"</vdr-chip>
         </ng-container>
         </ng-container>
     </ng-template>
     </ng-template>
     <ng-template ng-option-tmp let-item="item" let-index="index" let-search="searchTerm">
     <ng-template ng-option-tmp let-item="item" let-index="index" let-search="searchTerm">

+ 19 - 2
packages/admin-ui/src/lib/core/src/shared/components/asset-search-input/asset-search-input.component.ts

@@ -1,14 +1,16 @@
 import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output, ViewChild } from '@angular/core';
 import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output, ViewChild } from '@angular/core';
-import { NgSelectComponent } from '@ng-select/ng-select';
+import { NgSelectComponent, SELECTION_MODEL_FACTORY } from '@ng-select/ng-select';
 import { notNullOrUndefined } from '@vendure/common/lib/shared-utils';
 import { notNullOrUndefined } from '@vendure/common/lib/shared-utils';
 
 
 import { SearchProducts, TagFragment } from '../../../common/generated-types';
 import { SearchProducts, TagFragment } from '../../../common/generated-types';
+import { SingleSearchSelectionModelFactory } from '../../../common/single-search-selection-model';
 
 
 @Component({
 @Component({
     selector: 'vdr-asset-search-input',
     selector: 'vdr-asset-search-input',
     templateUrl: './asset-search-input.component.html',
     templateUrl: './asset-search-input.component.html',
     styleUrls: ['./asset-search-input.component.scss'],
     styleUrls: ['./asset-search-input.component.scss'],
     changeDetection: ChangeDetectionStrategy.OnPush,
     changeDetection: ChangeDetectionStrategy.OnPush,
+    providers: [{ provide: SELECTION_MODEL_FACTORY, useValue: SingleSearchSelectionModelFactory }],
 })
 })
 export class AssetSearchInputComponent {
 export class AssetSearchInputComponent {
     @Input() tags: TagFragment[];
     @Input() tags: TagFragment[];
@@ -67,7 +69,18 @@ export class AssetSearchInputComponent {
         if (!Array.isArray(selectedItems)) {
         if (!Array.isArray(selectedItems)) {
             selectedItems = [selectedItems];
             selectedItems = [selectedItems];
         }
         }
-        const searchTermItem = selectedItems.find(item => !this.isTag(item)) as { label: string } | undefined;
+
+        const searchTermItems = selectedItems.filter(item => !this.isTag(item));
+        if (1 < searchTermItems.length) {
+            for (let i = 0; i < searchTermItems.length - 1; i++) {
+                // this.selectComponent.unselect(searchTermItems[i] as any);
+            }
+        }
+
+        const searchTermItem = searchTermItems[searchTermItems.length - 1] as
+            | { label: string }
+            | undefined;
+
         const searchTerm = searchTermItem ? searchTermItem.label : '';
         const searchTerm = searchTermItem ? searchTermItem.label : '';
 
 
         const tags = selectedItems.filter(this.isTag);
         const tags = selectedItems.filter(this.isTag);
@@ -86,6 +99,10 @@ export class AssetSearchInputComponent {
         return this.selectComponent.itemsList.markedIndex === -1;
         return this.selectComponent.itemsList.markedIndex === -1;
     }
     }
 
 
+    addTagFn(item: any) {
+        return { label: item };
+    }
+
     private isTag = (input: unknown): input is TagFragment => {
     private isTag = (input: unknown): input is TagFragment => {
         return typeof input === 'object' && !!input && input.hasOwnProperty('value');
         return typeof input === 'object' && !!input && input.hasOwnProperty('value');
     };
     };