mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-20 12:29:55 +08:00
fix(radio): prevent multiple radio buttons from being checked
This commit is contained in:
@ -1,7 +1,7 @@
|
||||
import {Component, Optional, Input, Output, HostListener, EventEmitter} from 'angular2/core';
|
||||
|
||||
import {Form} from '../../util/form';
|
||||
import {isTrueProperty, isDefined} from '../../util/util';
|
||||
import {isTrueProperty, isDefined, isBlank} from '../../util/util';
|
||||
import {Item} from '../item/item';
|
||||
import {ListHeader} from '../list/list';
|
||||
import {RadioGroup} from './radio-group';
|
||||
@ -50,10 +50,10 @@ export class RadioButton {
|
||||
private _checked: any = false;
|
||||
private _disabled: any = false;
|
||||
private _labelId: string;
|
||||
private _value = null;
|
||||
|
||||
id: string;
|
||||
|
||||
@Input() value: string = '';
|
||||
@Output() select: EventEmitter<RadioButton> = new EventEmitter();
|
||||
|
||||
constructor(
|
||||
@ -63,21 +63,28 @@ export class RadioButton {
|
||||
) {
|
||||
_form.register(this);
|
||||
|
||||
if (_group) {
|
||||
// register with the radiogroup
|
||||
this.id = 'rb-' + _group.register(this);
|
||||
}
|
||||
|
||||
if (_item) {
|
||||
// register the input inside of the item
|
||||
// reset to the item's id instead of the radiogroup id
|
||||
this.id = 'rb-' + _item.registerInput('radio');
|
||||
this._labelId = 'lbl-' + _item.id;
|
||||
this._item.setCssClass('item-radio', true);
|
||||
}
|
||||
|
||||
console.log(this.value);
|
||||
|
||||
if (_group) {
|
||||
_group.register(this);
|
||||
}
|
||||
}
|
||||
|
||||
check() {
|
||||
this.checked = true;
|
||||
@Input()
|
||||
get value() {
|
||||
// if the value is not defined then use it's unique id
|
||||
return isBlank(this._value) ? this.id : this._value;
|
||||
}
|
||||
|
||||
set value(val) {
|
||||
this._value = val;
|
||||
}
|
||||
|
||||
@Input()
|
||||
@ -85,11 +92,28 @@ export class RadioButton {
|
||||
return this._checked;
|
||||
}
|
||||
|
||||
set checked(val) {
|
||||
set checked(isChecked) {
|
||||
if (!this._disabled) {
|
||||
this._checked = isTrueProperty(val);
|
||||
this.select.emit(this);
|
||||
this._item && this._item.setCssClass('item-radio-checked', this._checked);
|
||||
// only check/uncheck if it's not disabled
|
||||
|
||||
// emit the select event for the radiogroup to catch
|
||||
this._checked = isTrueProperty(isChecked);
|
||||
this.select.emit(this.value);
|
||||
|
||||
// if it's a stand-alone radiobutton nothing else happens
|
||||
// if it was within a radiogroup then updateAsChecked will
|
||||
// get called again
|
||||
this.updateAsChecked(this._checked);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
updateAsChecked(val: boolean) {
|
||||
this._checked = val;
|
||||
if (this._item) {
|
||||
this._item.setCssClass('item-radio-checked', val);
|
||||
}
|
||||
}
|
||||
|
||||
@ -103,14 +127,6 @@ export class RadioButton {
|
||||
this._item && this._item.setCssClass('item-radio-disabled', this._disabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
setChecked(val: boolean) {
|
||||
this._checked = isTrueProperty(val);
|
||||
this._item && this._item.setCssClass('item-radio-checked', val);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
@ -119,7 +135,7 @@ export class RadioButton {
|
||||
console.debug('radio, select', this.id);
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
this.check();
|
||||
this.checked = true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,4 +1,4 @@
|
||||
import {Directive, ElementRef, Renderer, Optional, Input, Output, ContentChild, EventEmitter} from 'angular2/core';
|
||||
import {Directive, ElementRef, Renderer, Optional, Input, Output, HostListener, ContentChild, EventEmitter} from 'angular2/core';
|
||||
import {NgControl} from 'angular2/common';
|
||||
|
||||
import {RadioButton} from './radio-button';
|
||||
@ -60,6 +60,8 @@ import {isDefined} from '../../util/util';
|
||||
})
|
||||
export class RadioGroup {
|
||||
private _buttons: Array<RadioButton> = [];
|
||||
private _ids: number = -1;
|
||||
private _init: boolean = false;
|
||||
|
||||
id;
|
||||
value;
|
||||
@ -84,43 +86,67 @@ export class RadioGroup {
|
||||
* the checked value.
|
||||
* https://github.com/angular/angular/blob/master/modules/angular2/src/forms/directives/shared.ts#L34
|
||||
*/
|
||||
writeValue(value) {
|
||||
this.value = isDefined(value) ? value : '';
|
||||
this._buttons.forEach(button => {
|
||||
let isChecked = button.checked;
|
||||
button.setChecked(isChecked);
|
||||
if (isChecked) {
|
||||
this._renderer.setElementAttribute(this._elementRef.nativeElement, 'aria-activedescendant', button.id);
|
||||
writeValue(val) {
|
||||
if (val !== null) {
|
||||
let oldVal = this.value;
|
||||
|
||||
// set the radiogroup's value
|
||||
this.value = val || '';
|
||||
|
||||
this.updateValue();
|
||||
|
||||
// only emit change when it...changed
|
||||
if (this.value !== oldVal && this._init) {
|
||||
this.change.emit(this.value);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
register(button: RadioButton) {
|
||||
this._buttons.push(button);
|
||||
|
||||
button.select.subscribe(() => {
|
||||
this.writeValue(button.value);
|
||||
this.onChange(button.value);
|
||||
this.change.emit(this);
|
||||
});
|
||||
this._init = true;
|
||||
}
|
||||
}
|
||||
|
||||
ngAfterContentInit() {
|
||||
this._buttons.forEach(button => {
|
||||
|
||||
if (isDefined(this.value)) {
|
||||
let isChecked = (button.value === this.value) || button.checked;
|
||||
button.setChecked(isChecked);
|
||||
if (isChecked) {
|
||||
this.writeValue(button.value);
|
||||
//this.onChange(button.value);
|
||||
this._renderer.setElementAttribute(this._elementRef.nativeElement, 'aria-activedescendant', button.id);
|
||||
}
|
||||
}
|
||||
|
||||
// in a setTimeout to prevent
|
||||
// Expression '_checked in RadioButton@0:24' has changed after
|
||||
// it was checked. Previous value: 'true'. Current value: 'false'
|
||||
// should be available in future versions of ng2
|
||||
setTimeout(() => {
|
||||
this.updateValue();
|
||||
});
|
||||
}
|
||||
|
||||
private updateValue() {
|
||||
if (isDefined(this.value)) {
|
||||
// loop through each of the radiobuttons
|
||||
this._buttons.forEach(radioButton => {
|
||||
|
||||
// check this radiobutton if its value is
|
||||
// the same as the radiogroups value
|
||||
let isChecked = (radioButton.value === this.value);
|
||||
|
||||
radioButton.updateAsChecked(isChecked);
|
||||
|
||||
if (isChecked) {
|
||||
// if this button is checked, then set it as
|
||||
// the radiogroup's active descendant
|
||||
this._renderer.setElementAttribute(this._elementRef.nativeElement, 'aria-activedescendant', radioButton.id);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
register(button: RadioButton): string {
|
||||
this._buttons.push(button);
|
||||
|
||||
// listen for radiobutton select events
|
||||
button.select.subscribe(() => {
|
||||
// this radiobutton has been selected
|
||||
this.writeValue(button.value);
|
||||
this.onChange(button.value);
|
||||
});
|
||||
|
||||
return this.id + '-' + (++this._ids);
|
||||
}
|
||||
|
||||
@ContentChild(ListHeader)
|
||||
private set _header(header) {
|
||||
if (header) {
|
||||
@ -134,16 +160,12 @@ export class RadioGroup {
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
onChange(val) {
|
||||
// TODO: figure the whys and the becauses
|
||||
}
|
||||
onChange(val) {}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
onTouched(val) {
|
||||
// TODO: figure the whys and the becauses
|
||||
}
|
||||
onTouched(val) {}
|
||||
|
||||
/**
|
||||
* @private
|
||||
|
@ -13,6 +13,12 @@ $radio-ios-icon-border-style: solid !default;
|
||||
$radio-ios-disabled-opacity: 0.4 !default;
|
||||
|
||||
|
||||
ion-radio {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
|
||||
// iOS Radio Circle: Unchecked
|
||||
// -----------------------------------------
|
||||
|
||||
@ -56,6 +62,7 @@ $radio-ios-disabled-opacity: 0.4 !default;
|
||||
// -----------------------------------------
|
||||
|
||||
.item ion-radio {
|
||||
position: static;
|
||||
display: block;
|
||||
margin: $item-ios-padding-media-top ($item-ios-padding-right / 2) $item-ios-padding-media-bottom ($item-ios-padding-left / 2);
|
||||
}
|
||||
|
@ -18,6 +18,12 @@ $radio-md-transition-easing: cubic-bezier(.4, 0, .2, 1) !default;
|
||||
$radio-md-disabled-opacity: 0.4 !default;
|
||||
|
||||
|
||||
ion-radio {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
|
||||
// Material Design Radio Outer Circle: Unchecked
|
||||
// -----------------------------------------
|
||||
|
||||
@ -82,6 +88,7 @@ $radio-md-disabled-opacity: 0.4 !default;
|
||||
// -----------------------------------------
|
||||
|
||||
.item ion-radio {
|
||||
position: static;
|
||||
display: block;
|
||||
margin: $item-md-padding-media-top ($item-md-padding-right / 2) $item-md-padding-media-bottom 0;
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ class E2EApp {
|
||||
this.currencies = ['USD', 'EUR'];
|
||||
this.selectedCurrency = 'EUR';
|
||||
|
||||
this.relationship = 'friends';
|
||||
this.relationship = 'enemies';
|
||||
|
||||
}
|
||||
|
||||
@ -52,4 +52,20 @@ class E2EApp {
|
||||
console.log('Submitting form', this.fruitsForm.value);
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
petChange(ev) {
|
||||
console.log('petChange', ev);
|
||||
}
|
||||
|
||||
dogSelect(ev) {
|
||||
console.log('dogSelect', ev);
|
||||
}
|
||||
|
||||
catSelect(ev) {
|
||||
console.log('catSelect', ev);
|
||||
}
|
||||
|
||||
turtleSelect(ev) {
|
||||
console.log('turtleSelect', ev);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
|
||||
<ion-toolbar><ion-title>Radio Group</ion-title></ion-toolbar>
|
||||
<ion-toolbar>
|
||||
<ion-title>Radio Group</ion-title>
|
||||
</ion-toolbar>
|
||||
|
||||
|
||||
<ion-content>
|
||||
@ -78,20 +80,20 @@
|
||||
<code><b>relationship:</b> {{relationship}}</code>
|
||||
</div>
|
||||
|
||||
<ion-list radio-group>
|
||||
<ion-item>
|
||||
<ion-label>Dogs</ion-label>
|
||||
<ion-radio checked></ion-radio>
|
||||
</ion-item>
|
||||
<ion-item>
|
||||
<ion-label>Cats</ion-label>
|
||||
<ion-radio></ion-radio>
|
||||
</ion-item>
|
||||
<ion-item>
|
||||
<ion-label>Turtles</ion-label>
|
||||
<ion-radio></ion-radio>
|
||||
</ion-item>
|
||||
</ion-list>
|
||||
<div radio-group [(ngModel)]="pet" (change)="petChange($event)">
|
||||
<p>
|
||||
<ion-radio checked (select)="dogSelect($event)"></ion-radio>
|
||||
Dogs
|
||||
</p>
|
||||
<p>
|
||||
<ion-radio (select)="catSelect($event)"></ion-radio>
|
||||
Cats
|
||||
</p>
|
||||
<p>
|
||||
<ion-radio (select)="turtleSelect($event)"></ion-radio>
|
||||
Turtles
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div padding>
|
||||
<code><b>pet:</b> {{pet}}</code>
|
||||
|
Reference in New Issue
Block a user