diff --git a/src/components/searchbar/searchbar.ios.scss b/src/components/searchbar/searchbar.ios.scss index 7111d2dcb0..74a6c719ba 100644 --- a/src/components/searchbar/searchbar.ios.scss +++ b/src/components/searchbar/searchbar.ios.scss @@ -148,7 +148,7 @@ ion-searchbar { // Searchbar Focused // ----------------------------------------- -.searchbar-focused { +.searchbar-has-focus { .searchbar-ios-cancel { flex: 0 0 auto; @@ -177,7 +177,7 @@ ion-searchbar { } } - .searchbar-focused .searchbar-ios-cancel { + .searchbar-has-focus .searchbar-ios-cancel { padding-left: 8px; } diff --git a/src/components/searchbar/searchbar.md.scss b/src/components/searchbar/searchbar.md.scss index b91e807b67..b66d1f48e5 100644 --- a/src/components/searchbar/searchbar.md.scss +++ b/src/components/searchbar/searchbar.md.scss @@ -130,7 +130,7 @@ ion-searchbar { // Searchbar Focused // ----------------------------------------- -.searchbar-focused:not(.searchbar-hide-cancel) { +.searchbar-has-focus:not(.searchbar-hide-cancel) { .searchbar-search-icon { display: none; } diff --git a/src/components/searchbar/searchbar.scss b/src/components/searchbar/searchbar.scss index fa98a10838..f111d2914d 100644 --- a/src/components/searchbar/searchbar.scss +++ b/src/components/searchbar/searchbar.scss @@ -46,6 +46,6 @@ ion-searchbar { min-height: 0; } -.searchbar-has-value.searchbar-focused .searchbar-clear-icon { +.searchbar-has-value.searchbar-has-focus .searchbar-clear-icon { display: block; } diff --git a/src/components/searchbar/searchbar.ts b/src/components/searchbar/searchbar.ts index ef643b75f4..ba16d14768 100644 --- a/src/components/searchbar/searchbar.ts +++ b/src/components/searchbar/searchbar.ts @@ -1,10 +1,7 @@ -import {ElementRef, Component, Directive, Host, HostBinding, HostListener, ViewChild, Input, Output, EventEmitter, Optional, ViewEncapsulation} from '@angular/core'; +import {Component, Directive, ElementRef, EventEmitter, HostBinding, Input, Optional, Output, ViewChild, ViewEncapsulation} from '@angular/core'; import {NgControl} from '@angular/common'; -import {Button} from '../button/button'; import {Config} from '../../config/config'; -import {Icon} from '../icon/icon'; -import {Ion} from '../ion'; import {isPresent} from '../../util/util'; @@ -41,39 +38,40 @@ export class SearchbarInput { @Component({ selector: 'ion-searchbar', host: { - '[class.searchbar-has-value]': 'value', + '[class.searchbar-has-value]': '_value', '[class.searchbar-hide-cancel]': 'hideCancelButton' }, template: '
' + - '' + - '
' + - '' + - '' + + '
' + + '' + + '' + '
' + - '', + '', directives: [SearchbarInput], - encapsulation: ViewEncapsulation.None, + encapsulation: ViewEncapsulation.None }) -export class Searchbar extends Ion { +export class Searchbar { + private _value: string|number = ''; private _tmr: any; + private _shouldBlur: boolean = true; + + private inputEle: any; + private iconEle: any; + private mode: string; /** - * @private + * @input {string} Set the the cancel button text. Default: `"Cancel"`. */ - @ViewChild(SearchbarInput) searchbarInput: SearchbarInput; + @Input() cancelButtonText: string = 'Cancel'; /** - * @input {string} Sets the cancel button text to the value passed in + * @input {boolean} Whether to hide the cancel button or not. Default: `"false"`. */ - @Input() cancelButtonText: string; - - /** - * @input {boolean} Hides the cancel button - */ - @Input() hideCancelButton: any; + @Input() hideCancelButton: any = false; /** * @input {number} How long, in milliseconds, to wait to trigger the `input` event after each keystroke. Default `250`. @@ -81,70 +79,59 @@ export class Searchbar extends Ion { @Input() debounce: number = 250; /** - * @input {string} Sets input placeholder to the value passed in + * @input {string} Set the input's placeholder. Default `"Search"`. */ - @Input() placeholder: string; + @Input() placeholder: string = 'Search'; /** - * @input {any} Expression to evaluate when the Searchbar input has changed including cleared + * @input {string} Set the input's autocomplete property. Values: `"on"`, `"off"`. Default `"off"`. */ - @Input() ngModel: any; + @Input() autocomplete: string; /** - * @output {event} When the Searchbar input has changed including cleared + * @input {string} Set the input's autocorrect property. Values: `"on"`, `"off"`. Default `"off"`. */ - @Output() ionInput: EventEmitter = new EventEmitter(); + @Input() autocorrect: string; /** - * @output {event} When the Searchbar input has blurred + * @input {string|boolean} Set the input's spellcheck property. Values: `true`, `false`. Default `false`. */ - @Output() ionBlur: EventEmitter = new EventEmitter(); + @Input() spellcheck: string|boolean; /** - * @output {event} When the Searchbar input has focused + * @input {string} Set the type of the input. Values: `"text"`, `"password"`, `"email"`, `"number"`, `"search"`, `"tel"`, `"url"`. Default `"search"`. */ - @Output() ionFocus: EventEmitter = new EventEmitter(); + @Input() type: string = 'search'; /** - * @output {event} When the cancel button is clicked + * @output {event} When the Searchbar input has changed including cleared. */ - @Output() ionCancel: EventEmitter = new EventEmitter(); + @Output() ionInput: EventEmitter = new EventEmitter(); /** - * @output {event} When the clear input button is clicked + * @output {event} When the Searchbar input has blurred. */ - @Output() ionClear: EventEmitter = new EventEmitter(); + @Output() ionBlur: EventEmitter = new EventEmitter(); + + /** + * @output {event} When the Searchbar input has focused. + */ + @Output() ionFocus: EventEmitter = new EventEmitter(); + + /** + * @output {event} When the cancel button is clicked. + */ + @Output() ionCancel: EventEmitter = new EventEmitter(); + + /** + * @output {event} When the clear input button is clicked. + */ + @Output() ionClear: EventEmitter = new EventEmitter(); /** * @private */ - value: string = ''; - - /** - * @private - */ - blurInput: boolean = true; - - /** - * @private - */ - inputElement: any; - - /** - * @private - */ - searchIconElement: any; - - /** - * @private - */ - mode: string; - - - /** - * @private - */ - @HostBinding('class.searchbar-focused') isFocused: boolean; + @HostBinding('class.searchbar-has-focus') isFocused: boolean; /** * @private @@ -156,14 +143,49 @@ export class Searchbar extends Ion { private _config: Config, @Optional() ngControl: NgControl ) { - super(_elementRef); - // If the user passed a ngControl we need to set the valueAccessor if (ngControl) { ngControl.valueAccessor = this; } } + /** + * @private + */ + @ViewChild(SearchbarInput) + private set _searchbarInput(searchbarInput: SearchbarInput) { + this.inputEle = searchbarInput.elementRef.nativeElement; + + // By defalt set autocomplete="off" unless specified by the input + let autoComplete = (this.autocomplete === '' || this.autocomplete === 'on') ? 'on' : this._config.get('autocomplete', 'off'); + this.inputEle.setAttribute('autocomplete', autoComplete); + + // by default set autocorrect="off" unless specified by the input + let autoCorrect = (this.autocorrect === '' || this.autocorrect === 'on') ? 'on' : this._config.get('autocorrect', 'off'); + this.inputEle.setAttribute('autocorrect', autoCorrect); + + // by default set spellcheck="false" unless specified by the input + let spellCheck = (this.spellcheck === '' || this.spellcheck === 'true' || this.spellcheck === true) ? true : this._config.getBoolean('spellcheck', false); + this.inputEle.setAttribute('spellcheck', spellCheck); + + // by default set type="search" unless specified by the input + this.inputEle.setAttribute('type', this.type); + } + + @ViewChild('searchbarIcon') _searchbarIcon: ElementRef; + + /** + * @input {string} Set the input value. + */ + @Input() + get value() { + return this._value; + } + + set value(val) { + this._value = val; + } + /** * @private * On Initialization check for attributes @@ -176,18 +198,7 @@ export class Searchbar extends Ion { this.hideCancelButton = (hideCancelButton === '' || hideCancelButton === 'true'); } - this.cancelButtonText = this.cancelButtonText || 'Cancel'; - this.placeholder = this.placeholder || 'Search'; - - if (this.ngModel) this.value = this.ngModel; - this.onChange(this.value); - - this.shouldLeftAlign = this.value && this.value.trim() !== ''; - - // Using querySelector instead of searchbarInput because at this point it doesn't exist - this.inputElement = this._elementRef.nativeElement.querySelector('.searchbar-input'); - this.searchIconElement = this._elementRef.nativeElement.querySelector('.searchbar-search-icon'); - this.setElementLeft(); + this.shouldLeftAlign = this._value && this._value.toString().trim() !== ''; } /** @@ -195,13 +206,8 @@ export class Searchbar extends Ion { * After View Initialization check the value */ ngAfterViewInit() { - // If the user passes an undefined variable to ngModel this will warn - // and set the value to an empty string - if (!isPresent(this.value)) { - console.warn('Searchbar was passed an undefined value in ngModel. Please make sure the variable is defined.'); - this.value = ''; - this.onChange(this.value); - } + this.iconEle = this._searchbarIcon.nativeElement; + this.setElementLeft(); } /** @@ -213,8 +219,8 @@ export class Searchbar extends Ion { if (this.mode !== 'ios') return; if (this.shouldLeftAlign) { - this.inputElement.removeAttribute('style'); - this.searchIconElement.removeAttribute('style'); + this.inputEle.removeAttribute('style'); + this.iconEle.removeAttribute('style'); } else { this.addElementLeft(); } @@ -237,11 +243,11 @@ export class Searchbar extends Ion { // Set the input padding left let inputLeft = 'calc(50% - ' + (textWidth / 2) + 'px)'; - this.inputElement.style.paddingLeft = inputLeft; + this.inputEle.style.paddingLeft = inputLeft; // Set the icon margin left let iconLeft = 'calc(50% - ' + ((textWidth / 2) + 30) + 'px)'; - this.searchIconElement.style.marginLeft = iconLeft; + this.iconEle.style.marginLeft = iconLeft; } /** @@ -253,9 +259,9 @@ export class Searchbar extends Ion { clearTimeout(this._tmr); this._tmr = setTimeout(() => { - this.value = value; - this.onChange(value); - this.ionInput.emit(this); + this._value = value; + this.onChange(this._value); + this.ionInput.emit(ev); }, Math.round(this.debounce)); } @@ -263,8 +269,8 @@ export class Searchbar extends Ion { * @private * Sets the Searchbar to focused and aligned left on input focus. */ - inputFocused() { - this.ionFocus.emit(this); + inputFocused(ev: UIEvent) { + this.ionFocus.emit(ev); this.isFocused = true; this.shouldLeftAlign = true; @@ -276,18 +282,18 @@ export class Searchbar extends Ion { * Sets the Searchbar to not focused and checks if it should align left * based on whether there is a value in the searchbar or not. */ - inputBlurred() { - // blurInput determines if it should blur + inputBlurred(ev: UIEvent) { + // _shouldBlur determines if it should blur // if we are clearing the input we still want to stay focused in the input - if (this.blurInput === false) { - this.searchbarInput.elementRef.nativeElement.focus(); - this.blurInput = true; + if (this._shouldBlur === false) { + this.inputEle.focus(); + this._shouldBlur = true; return; } - this.ionBlur.emit(this); + this.ionBlur.emit(ev); this.isFocused = false; - this.shouldLeftAlign = this.value && this.value.trim() !== ''; + this.shouldLeftAlign = this._value && this._value.toString().trim() !== ''; this.setElementLeft(); } @@ -295,16 +301,16 @@ export class Searchbar extends Ion { * @private * Clears the input field and triggers the control change. */ - clearInput() { - this.ionClear.emit(this); + clearInput(ev: UIEvent) { + this.ionClear.emit(ev); - if (isPresent(this.value) && this.value !== '') { - this.value = ''; - this.onChange(this.value); - this.ionInput.emit(this); + if (isPresent(this._value) && this._value !== '') { + this._value = ''; + this.onChange(this._value); + this.ionInput.emit(ev); } - this.blurInput = false; + this._shouldBlur = false; } /** @@ -313,19 +319,19 @@ export class Searchbar extends Ion { * the clearInput function doesn't want the input to blur * then calls the custom cancel function if the user passed one in. */ - cancelSearchbar() { - this.ionCancel.emit(this); + cancelSearchbar(ev: UIEvent) { + this.ionCancel.emit(ev); - this.clearInput(); - this.blurInput = true; + this.clearInput(ev); + this._shouldBlur = true; } /** * @private * Write a new value to the element. */ - writeValue(value: any) { - this.value = value; + writeValue(val: any) { + this._value = val; } /** diff --git a/src/components/searchbar/searchbar.wp.scss b/src/components/searchbar/searchbar.wp.scss index 7c3baec100..84810d46b2 100644 --- a/src/components/searchbar/searchbar.wp.scss +++ b/src/components/searchbar/searchbar.wp.scss @@ -115,7 +115,7 @@ ion-searchbar { // Searchbar Focused // ----------------------------------------- -.searchbar-focused .searchbar-input-container { +.searchbar-has-focus .searchbar-input-container { border-color: $searchbar-wp-border-color-focused; } @@ -158,7 +158,7 @@ ion-searchbar { @each $color-name, $color-base, $color-contrast in get-colors($colors-wp) { - ion-searchbar[#{$color-name}].searchbar-focused .searchbar-input-container { + ion-searchbar[#{$color-name}].searchbar-has-focus .searchbar-input-container { border-color: $color-base; } diff --git a/src/components/searchbar/test/floating/index.ts b/src/components/searchbar/test/floating/index.ts index a5fb2b5c32..c65a75c8d7 100644 --- a/src/components/searchbar/test/floating/index.ts +++ b/src/components/searchbar/test/floating/index.ts @@ -1,4 +1,4 @@ -import {Component} from '@angular/core'; +import {Component, ChangeDetectorRef} from '@angular/core'; import {FormBuilder, Validators, Control, ControlGroup} from '@angular/common'; import {ionicBootstrap} from '../../../../../src'; @@ -8,27 +8,44 @@ import {ionicBootstrap} from '../../../../../src'; }) class E2EApp { defaultSearch: string = 'test'; - customPlaceholder: string = ''; + customPlaceholder: number = 2; defaultCancel: string = ''; - onClearSearchbar(searchbar) { - console.log("ionClear", searchbar.value); + isAutocorrect: string = 'on'; + isAutocomplete: string = 'on'; + isSpellcheck: boolean = true; + + constructor(private changeDetectorRef: ChangeDetectorRef) { + } - onCancelSearchbar(searchbar) { - console.log("ionCancel", searchbar.value); + onClearSearchbar(ev: any) { + console.log("ionClear", ev.target.value); } - triggerInput(searchbar) { - console.log("ionInput", searchbar.value); + onCancelSearchbar(ev: any) { + console.log("ionCancel", ev.target.value); } - inputBlurred(searchbar) { - console.log("ionBlur", searchbar.value); + triggerInput(ev: any) { + console.log("ionInput", ev.target.value); } - inputFocused(searchbar) { - console.log("ionFocus", searchbar.value); + inputBlurred(ev: any) { + console.log("ionBlur", ev.target.value); + } + + inputFocused(ev: any) { + console.log("ionFocus", ev.target.value); + } + + ngAfterViewInit() { + this.customPlaceholder = 33; + this.changeDetectorRef.detectChanges(); + } + + changeValue() { + this.defaultSearch = "changed"; } } diff --git a/src/components/searchbar/test/floating/main.html b/src/components/searchbar/test/floating/main.html index d9a2817730..5737183093 100644 --- a/src/components/searchbar/test/floating/main.html +++ b/src/components/searchbar/test/floating/main.html @@ -7,14 +7,14 @@

Search - Custom Placeholder
- +

customPlaceholder: {{ customPlaceholder }}

Search - Hide Cancel Button
- +

defaultCancel: {{ defaultCancel }} @@ -22,4 +22,8 @@

Search - Custom Cancel Button Danger
+ +

+ +