From 508a872251b6d4c97e1af267b0a1e134a7aa2f8e Mon Sep 17 00:00:00 2001 From: Adam Bradley Date: Fri, 18 Dec 2015 23:00:04 -0600 Subject: [PATCH] refactor(segment): query buttons via @ContentChildren --- ionic/components/radio/radio.ts | 2 +- ionic/components/segment/segment.scss | 1 + ionic/components/segment/segment.ts | 241 ++++++++---------- ionic/components/segment/test/basic/main.html | 4 +- 4 files changed, 116 insertions(+), 132 deletions(-) diff --git a/ionic/components/radio/radio.ts b/ionic/components/radio/radio.ts index a7fc3f8c0b..d4816e9cd1 100644 --- a/ionic/components/radio/radio.ts +++ b/ionic/components/radio/radio.ts @@ -178,7 +178,7 @@ export class RadioGroup extends Ion { ], host: { 'role': 'radio', - 'tappable': 'true', + 'tappable': '', '[attr.id]': 'id', '[tabindex]': 'tabIndex', '[attr.aria-checked]': 'checked', diff --git a/ionic/components/segment/segment.scss b/ionic/components/segment/segment.scss index b9e596d6e8..0db5914adf 100644 --- a/ionic/components/segment/segment.scss +++ b/ionic/components/segment/segment.scss @@ -26,4 +26,5 @@ ion-segment { text-align: center; text-overflow: ellipsis; white-space: nowrap; + cursor: pointer; } diff --git a/ionic/components/segment/segment.ts b/ionic/components/segment/segment.ts index e8514e569d..0db83bbabc 100644 --- a/ionic/components/segment/segment.ts +++ b/ionic/components/segment/segment.ts @@ -1,8 +1,87 @@ -import {Directive, Renderer, ElementRef, Host, Optional, EventEmitter, Output} from 'angular2/core'; +import {Directive, Renderer, ElementRef, Host, Optional, EventEmitter, HostBinding, Input, Output, ContentChildren, HostListener} from 'angular2/core'; import {NgControl} from 'angular2/common'; -import {Ion} from '../ion'; import {Config} from '../../config/config'; +import {isDefined} from '../../util/util'; + + +/** + * @name SegmentButton + * @description + * The child buttons of the `ion-segment` component. Each `ion-segment-button` must have a value. + * @property {string} [value] - the value of the segment-button. Required. + * @usage + * ```html + * + * + * Friends + * + * + * Enemies + * + * + *``` + * + * Or with `FormBuilder` + * + *```html + *
+ * + * + * Standard + * + * + * Hybrid + * + * + * Satellite + * + * + *
+ * ``` + * + * @property {Any} [click] - expression to evaluate when a segment button has been clicked + * + * @demo /docs/v2/demos/segment/ + * @see {@link /docs/v2/components#segment Segment Component Docs} + * @see {@link /docs/v2/api/components/segment/Segment/ Segment API Docs} + */ +@Directive({ + selector: 'ion-segment-button', + host: { + 'tappable': '', + 'class': 'segment-button', + 'role': 'button' + } +}) +export class SegmentButton { + @Input() value: string + @Output() select: EventEmitter = new EventEmitter(); + + constructor(private _renderer: Renderer, private _elementRef: ElementRef) {} + + /** + * @private + * On click of a SegmentButton + */ + @HostListener('click', ['$event']) + private onClick(ev) { + console.debug('SegmentButton, select', this.value); + this.select.emit(ev, this.value); + } + + ngOnInit() { + if (!isDefined(this.value)) { + console.warn(' requires a "value" attribute'); + } + } + + public set isActive(isActive) { + this._renderer.setElementClass(this._elementRef, 'segment-activated', isActive); + this._renderer.setElementAttribute(this._elementRef, 'aria-pressed', isActive); + } + +} /** @@ -52,27 +131,22 @@ import {Config} from '../../config/config'; @Directive({ selector: 'ion-segment' }) -export class Segment extends Ion { +export class Segment { @Output() change: EventEmitter = new EventEmitter(); - /** - * @private - * {Array} buttons The children SegmentButton's - */ - buttons: Array = []; + @ContentChildren(SegmentButton) buttons; + value: any; constructor( - @Optional() ngControl: NgControl, - elementRef: ElementRef, - config: Config + @Optional() ngControl: NgControl ) { - super(elementRef, config); - this.onChange = (_) => {}; this.onTouched = (_) => {}; - if (ngControl) ngControl.valueAccessor = this; + if (ngControl) { + ngControl.valueAccessor = this; + } } /** @@ -81,11 +155,33 @@ export class Segment extends Ion { */ writeValue(value) { this.value = !value ? '' : value; - for (let button of this.buttons) { - button.isActive = (button.value === value); + if (this.buttons) { + let buttons = this.buttons.toArray(); + for (let button of buttons) { + button.isActive = (button.value === this.value); + } } } + /** + * @private + */ + ngAfterViewInit() { + let buttons = this.buttons.toArray(); + for (let button of buttons) { + button.select.subscribe(() => { + this.writeValue(button.value); + this.onChange(button.value); + this.change.emit(this.value); + }); + + if (isDefined(this.value)) { + button.isActive = (button.value === this.value); + } + } + } + + /** * @private * Set the function to be called when the control receives a change event. @@ -98,117 +194,4 @@ export class Segment extends Ion { */ registerOnTouched(fn) { this.onTouched = fn; } - /** - * @private - * Called by child SegmentButtons to bind themselves to - * the Segment. - * @param {SegmentButton} segmentButton The child SegmentButton to register. - */ - register(segmentButton) { - this.buttons.push(segmentButton); - - // If this button is registered and matches our value, - // make sure to select it - if (this.value == segmentButton.value) { - this.selected(segmentButton); - } - } - - /** - * @private - * Indicate a button should be selected. - * @param {SegmentButton} segmentButton The button to select. - */ - selected(segmentButton) { - this.buttons.forEach(function(button) { - button.isActive = false; - }); - segmentButton.isActive = true; - - this.value = segmentButton.value; - this.onChange(segmentButton.value); - this.change.emit(this.value); - } -} - - -/** - * @name SegmentButton - * @description - * The child buttons of the `ion-segment` component. Each `ion-segment-button` must have a value. - * @property {string} [value] - the value of the segment-button. - * @usage - * ```html - * - * - * Friends - * - * - * Enemies - * - * - *``` - * - * Or with `FormBuilder` - * - *```html - *
- * - * - * Standard - * - * - * Hybrid - * - * - * Satellite - * - * - *
- * ``` - * - * @property {Any} [click] - expression to evaluate when a segment button has been clicked - * - * @demo /docs/v2/demos/segment/ - * @see {@link /docs/v2/components#segment Segment Component Docs} - * @see {@link /docs/v2/api/components/segment/Segment/ Segment API Docs} - */ -@Directive({ - selector: 'ion-segment-button', - inputs: [ - 'value' - ], - host: { - '(click)': 'click($event)', - '[class.segment-activated]': 'isActive' - } -}) -export class SegmentButton { - constructor( - @Host() segment: Segment, - elementRef: ElementRef, - renderer: Renderer - ) { - this.segment = segment; - - renderer.setElementClass(elementRef, 'segment-button', true); - renderer.setElementAttribute(elementRef, 'tappable', ''); - } - - /** - * @private - * Runs after the first check only - */ - ngOnInit() { - this.segment.register(this); - } - - /** - * @private - * On click of a SegmentButton - * @param {MouseEvent} event The event that happens on click. - */ - click(event) { - this.segment.selected(this, event); - } } diff --git a/ionic/components/segment/test/basic/main.html b/ionic/components/segment/test/basic/main.html index 091d8c2282..5e8442bfbc 100644 --- a/ionic/components/segment/test/basic/main.html +++ b/ionic/components/segment/test/basic/main.html @@ -16,10 +16,10 @@ - + Something - + Else