Skip to content

Commit dfb2eb8

Browse files
committed
Added docs for search component
1 parent cd616c0 commit dfb2eb8

File tree

8 files changed

+171
-3
lines changed

8 files changed

+171
-3
lines changed

components/search/search.component.ts

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
import {Component, Directive, Provider, HostBinding, ElementRef, AfterViewInit, ViewChild, EventEmitter, forwardRef} from 'angular2/core';
1+
import {Component, Directive, Provider, HostListener, HostBinding, ElementRef, AfterViewInit, ViewChild, EventEmitter, forwardRef} from 'angular2/core';
22
import {ControlValueAccessor, NG_VALUE_ACCESSOR} from 'angular2/common';
33
import {Dropdown, DropdownMenu} from '../dropdown';
44

55
@Component({
66
selector: 'sui-search',
77
directives: [DropdownMenu],
8-
inputs: ['placeholder', 'options', 'optionsField', 'searchDelay', 'icon', 'isDisabled'],
9-
outputs: ['selectedOptionChange'],
8+
inputs: ['placeholder', 'options', 'optionsField', 'searchDelay', 'icon'],
9+
outputs: ['selectedOptionChange', 'onItemSelected'],
1010
host: {
1111
'[class.visible]': 'isOpen',
1212
'[class.disabled]': 'isDisabled'
@@ -125,6 +125,7 @@ export class Search extends Dropdown implements AfterViewInit {
125125

126126
//noinspection JSMethodCanBeStatic
127127
protected deepValue(object:any, path:string) {
128+
if (!object) { return; }
128129
if (!path) { return object; }
129130
for (var i = 0, p = path.split('.'), len = p.length; i < len; i++){
130131
object = object[p[i]];
@@ -142,6 +143,7 @@ export class Search extends Dropdown implements AfterViewInit {
142143

143144
public writeValue(value:any) {
144145
this.selectedOption = value;
146+
this._query = this.deepValue(value, this.optionsField);
145147
}
146148

147149
public ngAfterContentInit():void {
@@ -152,6 +154,25 @@ export class Search extends Dropdown implements AfterViewInit {
152154
public ngAfterViewInit():void {
153155
this._menu.service = this._service;
154156
}
157+
158+
@HostListener('click', ['$event'])
159+
public click(event:MouseEvent):boolean {
160+
event.stopPropagation();
161+
162+
if (!this._service.menuElement.nativeElement.contains(event.target)){
163+
if (!this.isOpen && this.query) {
164+
if (this.results.length) {
165+
this.isOpen = true;
166+
}
167+
this._loading = true;
168+
this.search(() => {
169+
this.isOpen = true;
170+
this._loading = false;
171+
});
172+
}
173+
}
174+
return false;
175+
}
155176
}
156177

157178
const CUSTOM_VALUE_ACCESSOR = new Provider(NG_VALUE_ACCESSOR, {useExisting: forwardRef(() => SearchValueAccessor), multi: true});

demo/app/app.component.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
<a class="item" [routerLink]="['MessageComponent']">Message</a>
2626
<a class="item" [routerLink]="['ProgressComponent']">Progress</a>
2727
<a class="item" [routerLink]="['RatingComponent']">Rating</a>
28+
<a class="item" [routerLink]="['SearchComponent']">Search</a>
2829
<a class="item" [routerLink]="['TabComponent']">Tab</a>
2930

3031
<a class="item" [routerLink]="['TestComponent']">Test</a>

demo/app/app.component.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {DropdownComponentPage} from "./components/dropdown.page";
1212
import {ProgressComponentPage} from "./components/progress.page";
1313
import {MessageComponentPage} from "./components/message.page";
1414
import {TabComponentPage} from "./components/tab.page";
15+
import {SearchComponentPage} from "./components/search.page";
1516
import {RatingComponentPage} from "./components/rating.page";
1617

1718
@Component({
@@ -72,6 +73,11 @@ import {RatingComponentPage} from "./components/rating.page";
7273
name: 'RatingComponent',
7374
component: RatingComponentPage
7475
},
76+
{
77+
path: '/components/search',
78+
name: 'SearchComponent',
79+
component: SearchComponentPage
80+
},
7581
{
7682
path: '/components/tab',
7783
name: 'TabComponent',
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<page-title>
2+
<div header>Search</div>
3+
<div sub-header>
4+
<p>A search module allows a user to query for results from a selection of data</p>
5+
</div>
6+
</page-title>
7+
<div class="ui main container">
8+
<div class="ui dividing right rail"></div>
9+
<h2 id="examples" class="ui dividing header">Examples</h2>
10+
<example code="app/components/search/standard.example.html">
11+
<div info>
12+
<h4 class="ui header">Local</h4>
13+
<p>A search can display a set of local results</p>
14+
</div>
15+
<search-example-standard result></search-example-standard>
16+
</example>
17+
<example code="app/components/search/remote.example.html">
18+
<div info>
19+
<h4 class="ui header">Remote</h4>
20+
<p>A search can display a set of remote results</p>
21+
</div>
22+
<search-example-remote result></search-example-remote>
23+
</example>
24+
<h2 id="api" class="ui dividing header">API</h2>
25+
<api [api]="api"></api>
26+
</div>

demo/app/components/search.page.ts

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import {Component} from 'angular2/core';
2+
3+
import {PageTitle} from "../internal/page-title.component";
4+
import {Example} from './../internal/example.component'
5+
import {Api} from "../internal/api.component";
6+
7+
import {SEARCH_EXAMPLES} from "./search/search.examples";
8+
9+
@Component({
10+
selector: 'search-component-page',
11+
directives: [PageTitle, Example, Api, SEARCH_EXAMPLES],
12+
templateUrl: "app/components/search.page.html"
13+
})
14+
export class SearchComponentPage {
15+
public api = [
16+
{
17+
selector: "<sui-search>",
18+
properties: [
19+
{
20+
name: "placeholder",
21+
description: "Sets the placeholder string on the search box.",
22+
defaultValue: "Search..."
23+
},
24+
{
25+
name: "options",
26+
description: "Sets the options available to the search component. Can either be an array or a function that takes a query and returns a Promise for remote lookup."
27+
},
28+
{
29+
name: "optionsField",
30+
description: "Sets the property name that the search element uses to display each option. Supports dot notation for nested properties."
31+
},
32+
{
33+
name: "searchDelay",
34+
description: "Sets the amount of time in milliseconds to wait after the last keypress before running a search.",
35+
defaultValue: "200"
36+
},
37+
{
38+
name: "icon",
39+
description: "Sets whether or not the search displays an icon. Loading state is automatically applied when searching.",
40+
defaultValue: "true"
41+
},
42+
{
43+
name: "ngModel",
44+
description: "Bind the search selected item to the value of the provided variable."
45+
}
46+
],
47+
events: [
48+
{
49+
name: "ngModelChange",
50+
description: "Fires whenever the search's selected item is changed. <code>[(ngModel)]</code> syntax is supported."
51+
},
52+
{
53+
name: "onItemSelected",
54+
description: "Fires whenever the search's selected item is changed. The selected value is passed as <code>$event</code>."
55+
}
56+
]
57+
}
58+
]
59+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<sui-search placeholder="Example Search..." [options]="optionsSearch" optionsField="title" [(ngModel)]="selectedItem"></sui-search>
2+
<div class="ui segment">
3+
<p>Setting the <code>[options]</code> property to a function that takes a query and returns a Promise allows remote lookups.</p>
4+
<p>Currently selected: {{ selectedItem | json }}</p>
5+
</div>
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import {Component} from 'angular2/core';
2+
3+
import {CHECKBOX_DIRECTIVES} from '../../../../components/checkbox';
4+
import {SEARCH_DIRECTIVES} from '../../../../components/search';
5+
// import {CHECKBOX_DIRECTIVES, SEARCH_DIRECTIVES} from 'ng2-semantic-ui/ng2-semantic-ui';
6+
7+
@Component({
8+
selector: 'search-example-standard',
9+
directives: [CHECKBOX_DIRECTIVES, SEARCH_DIRECTIVES],
10+
templateUrl: "app/components/search/standard.example.html"
11+
})
12+
export class SearchExampleStandard {
13+
public icon:boolean = true;
14+
public static standardOptions:Array<string> = ["Apple", "Bird", "Car", "Dog", "Elephant", "Finch", "Gate",
15+
"Horrify", "Indigo", "Jelly", "Keep", "Lemur", "Manifest", "None", "Orange", "Peel", "Quest",
16+
"Resist", "Suspend", "Terrify", "Underneath", "Violet", "Water", "Xylophone", "Yellow", "Zebra"];
17+
//noinspection JSMethodCanBeStatic
18+
public get options():Array<string> {
19+
return SearchExampleStandard.standardOptions;
20+
}
21+
//noinspection JSMethodCanBeStatic
22+
public alertSelected(selectedItem:string):void {
23+
alert(`You chose '${selectedItem}'!`);
24+
}
25+
}
26+
27+
@Component({
28+
selector: 'search-example-remote',
29+
directives: [SEARCH_DIRECTIVES],
30+
templateUrl: "app/components/search/remote.example.html"
31+
})
32+
export class SearchExampleRemote extends SearchExampleStandard {
33+
public optionsSearch(query:string):Promise<Array<any>> {
34+
var options = SearchExampleStandard.standardOptions.map((o:string) => ({ title: o }));
35+
return new Promise((resolve, reject) => {
36+
var results = options.filter((o:any) => {
37+
return o.title.slice(0, query.length).toLowerCase() == query.toLowerCase();
38+
});
39+
setTimeout(() => {
40+
resolve(results);
41+
}, 300);
42+
});
43+
}
44+
}
45+
46+
export const SEARCH_EXAMPLES:Array<any> = [SearchExampleStandard, SearchExampleRemote];
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<sui-search placeholder="Example Search..." [icon]="icon" [options]="options" [searchDelay]="0" (onItemSelected)="alertSelected($event)"></sui-search>
2+
<div class="ui segment">
3+
<sui-checkbox [(ngModel)]="icon">Has icon?</sui-checkbox>
4+
</div>

0 commit comments

Comments
 (0)