diff --git a/demo-shell/src/app/components/search/search-bar.component.html b/demo-shell/src/app/components/search/search-bar.component.html index 81df2e9ae0..929de529cb 100644 --- a/demo-shell/src/app/components/search/search-bar.component.html +++ b/demo-shell/src/app/components/search/search-bar.component.html @@ -1,4 +1,7 @@ + diff --git a/docs/search-control.component.md b/docs/search-control.component.md index 92e91f21e0..bbb4f32b1a 100644 --- a/docs/search-control.component.md +++ b/docs/search-control.component.md @@ -47,3 +47,18 @@ Displays a input text which shows find-as-you-type suggestions. Example of a component that uses the search control. In this example the search term is simply logged to the console but instead the component could emit an event to be consumed upstream, or it could trigger a change inside a search results component embedded inside the same component. + +## Customizable template for no result +It is possible to customize with your own template what to show when no result are found for the search. + +```html + + + + YOUR CUSTOM MESSAGE + + +``` +All you need to add is the `adf-empty-search-result` tag in the `adf-search-control` and then put inside the template you want to render when no results are found. \ No newline at end of file diff --git a/lib/content-services/mock/public-api.ts b/lib/content-services/mock/public-api.ts index c84c947e57..e6bdcf342f 100644 --- a/lib/content-services/mock/public-api.ts +++ b/lib/content-services/mock/public-api.ts @@ -20,3 +20,4 @@ export * from './document-list.component.mock'; export * from './document-list.service.mock'; export * from './search.component.mock'; export * from './search.service.mock'; +export * from './search-control.component.mock'; diff --git a/lib/content-services/mock/search-control.component.mock.ts b/lib/content-services/mock/search-control.component.mock.ts new file mode 100644 index 0000000000..eb707d3cdf --- /dev/null +++ b/lib/content-services/mock/search-control.component.mock.ts @@ -0,0 +1,41 @@ +/*! + * @license + * Copyright 2016 Alfresco Software, Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Component } from '@angular/core'; + +@Component({ + template: ` + + + {{customMessage}} + + + ` + }) + + export class SimpleSearchTestCustomEmptyComponent { + + customMessage: string = ''; + + constructor() { + } + + setCustomMessageForNoResult(message: string) { + this.customMessage = message; + } + + } diff --git a/lib/content-services/search/components/empty-search-result.component.html b/lib/content-services/search/components/empty-search-result.component.html new file mode 100644 index 0000000000..18b0bb114f --- /dev/null +++ b/lib/content-services/search/components/empty-search-result.component.html @@ -0,0 +1,3 @@ +
+ +
diff --git a/lib/content-services/search/components/empty-search-result.component.ts b/lib/content-services/search/components/empty-search-result.component.ts new file mode 100644 index 0000000000..46c464f059 --- /dev/null +++ b/lib/content-services/search/components/empty-search-result.component.ts @@ -0,0 +1,25 @@ +/*! + * @license + * Copyright 2016 Alfresco Software, Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Component, ViewEncapsulation } from '@angular/core'; + +@Component({ + selector: 'adf-empty-search-result', + templateUrl: './empty-search-result.component.html', + encapsulation: ViewEncapsulation.None +}) +export class EmptySearchResultComponent {} diff --git a/lib/content-services/search/components/search-control.component.html b/lib/content-services/search/components/search-control.component.html index 3d33f1ac6c..09b18f6816 100644 --- a/lib/content-services/search/components/search-control.component.html +++ b/lib/content-services/search/components/search-control.component.html @@ -57,11 +57,16 @@

{{item?.entry.createdByUser.displayName}}

- -

{{ 'SEARCH.RESULTS.NONE' | translate:{searchTerm: searchTerm} }}

+ + + +

{{ 'SEARCH.RESULTS.NONE' | translate:{searchTerm: searchTerm} }}

+
diff --git a/lib/content-services/search/components/search-control.component.spec.ts b/lib/content-services/search/components/search-control.component.spec.ts index 560977f54c..79f2bdff37 100644 --- a/lib/content-services/search/components/search-control.component.spec.ts +++ b/lib/content-services/search/components/search-control.component.spec.ts @@ -26,6 +26,9 @@ import { noResult, results } from '../../mock'; import { SearchControlComponent } from './search-control.component'; import { SearchTriggerDirective } from './search-trigger.directive'; import { SearchComponent } from './search.component'; +import { EmptySearchResultComponent } from './empty-search-result.component'; +import { SimpleSearchTestCustomEmptyComponent } from '../../mock'; +import { SearchModule } from '../../index'; describe('SearchControlComponent', () => { @@ -44,7 +47,8 @@ describe('SearchControlComponent', () => { declarations: [ SearchControlComponent, SearchComponent, - SearchTriggerDirective + SearchTriggerDirective, + EmptySearchResultComponent ], providers: [ ThumbnailService, @@ -543,3 +547,55 @@ describe('SearchControlComponent', () => { })); }); }); + +describe('SearchControlComponent - No result custom', () => { + + let fixtureCustom: ComponentFixture; + let elementCustom: HTMLElement; + let componentCustom: SimpleSearchTestCustomEmptyComponent; + let authServiceCustom: AuthenticationService; + let searchServiceCustom: SearchService; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ + SearchModule + ], + declarations: [ + SimpleSearchTestCustomEmptyComponent + ] + }).compileComponents().then(() => { + fixtureCustom = TestBed.createComponent(SimpleSearchTestCustomEmptyComponent); + componentCustom = fixtureCustom.componentInstance; + elementCustom = fixtureCustom.nativeElement; + authServiceCustom = TestBed.get(AuthenticationService); + searchServiceCustom = TestBed.get(SearchService); + }); + })); + + beforeEach(async(() => { + spyOn(authServiceCustom, 'isEcmLoggedIn').and.returnValue(true); + })); + + afterEach(async(() => { + fixtureCustom.destroy(); + TestBed.resetTestingModule(); + })); + + it('should display the custom no results when it is configured', async(() => { + const noResultCustomMessage = 'BANDI IS NOTHING'; + componentCustom.setCustomMessageForNoResult(noResultCustomMessage); + spyOn(searchServiceCustom, 'search').and.returnValue(Observable.of(noResult)); + fixtureCustom.detectChanges(); + + let inputDebugElement = fixtureCustom.debugElement.query(By.css('#adf-control-input')); + inputDebugElement.nativeElement.value = 'BANDY NOTHING'; + inputDebugElement.nativeElement.focus(); + inputDebugElement.nativeElement.dispatchEvent(new Event('input')); + fixtureCustom.whenStable().then(() => { + fixtureCustom.detectChanges(); + expect(elementCustom.querySelector('#custom-no-result').textContent).toBe(noResultCustomMessage); + }); + })); + +}); diff --git a/lib/content-services/search/components/search-control.component.ts b/lib/content-services/search/components/search-control.component.ts index e55e057bc8..f10c653988 100644 --- a/lib/content-services/search/components/search-control.component.ts +++ b/lib/content-services/search/components/search-control.component.ts @@ -18,12 +18,13 @@ import { AuthenticationService, ThumbnailService } from '@alfresco/adf-core'; import { animate, state, style, transition, trigger } from '@angular/animations'; import { Component, EventEmitter, Input, OnDestroy, OnInit, Output, - QueryList, ViewEncapsulation, ViewChild, ViewChildren, ElementRef } from '@angular/core'; + QueryList, ViewEncapsulation, ViewChild, ViewChildren, ElementRef, TemplateRef, ContentChild } from '@angular/core'; import { MinimalNodeEntity, QueryBody } from 'alfresco-js-api'; import { Observable } from 'rxjs/Observable'; import { Subject } from 'rxjs/Subject'; import { SearchComponent } from './search.component'; import { MatListItem } from '@angular/material'; +import { EmptySearchResultComponent } from './empty-search-result.component'; @Component({ selector: 'adf-search-control', @@ -102,8 +103,12 @@ export class SearchControlComponent implements OnInit, OnDestroy { @ViewChildren(MatListItem) private listResultElement: QueryList; + @ContentChild(EmptySearchResultComponent) + emptySearchTemplate: EmptySearchResultComponent; + searchTerm: string = ''; subscriptAnimationState: string; + noSearchResultTemplate: TemplateRef = null; private toggleSearch = new Subject(); private focusSubject = new Subject(); @@ -137,6 +142,10 @@ export class SearchControlComponent implements OnInit, OnDestroy { this.setupFocusEventHandlers(); } + isNoSearchTemplatePresent(): boolean { + return this.emptySearchTemplate ? true : false; + } + ngOnDestroy(): void { if (this.focusSubject) { this.focusSubject.unsubscribe(); diff --git a/lib/content-services/search/public-api.ts b/lib/content-services/search/public-api.ts index c9fc602a33..5c13bfe876 100644 --- a/lib/content-services/search/public-api.ts +++ b/lib/content-services/search/public-api.ts @@ -18,3 +18,4 @@ export * from './components/search.component'; export * from './components/search-control.component'; export * from './components/search-trigger.directive'; +export * from './components/empty-search-result.component'; diff --git a/lib/content-services/search/search.module.ts b/lib/content-services/search/search.module.ts index 5a7e25db8d..5ab17f5b9e 100644 --- a/lib/content-services/search/search.module.ts +++ b/lib/content-services/search/search.module.ts @@ -27,11 +27,13 @@ import { SearchTriggerDirective } from './components/search-trigger.directive'; import { SearchControlComponent } from './components/search-control.component'; import { SearchComponent } from './components/search.component'; +import { EmptySearchResultComponent } from './components/empty-search-result.component'; export const ALFRESCO_SEARCH_DIRECTIVES: [any] = [ SearchComponent, SearchControlComponent, - SearchTriggerDirective + SearchTriggerDirective, + EmptySearchResultComponent ]; export const ALFRESCO_SEARCH_PROVIDERS: [any] = [