ラジオボタン(radios)の CSSをカスタムして、それをカスタムコンポーネントにしました。
意外と ([ngModel])
をカスタムコンポーネントでやっているリファレンスって少ないので、 ngModel
の例としても役に立つかもしれない。
利用する側のコンポーネントのコード
parent.ts
@Component({
selector: 'app-parent',
templateUrl: './parent.component.html'
})
export class ParentComponent {
@Input() gender: string;
}
parent.component.html
<app-radio selectValue="male" label="男" name="gender" [(ngModel)]="gender">
<app-radio selectValue="female" label="女" name="gender" [(ngModel)]="gender">
<app-radio selectValue="unknown" label="どちらでもない" name="gender" [(ngModel)]="gender">
コンポーネントのコード
radio.component.ts
import { Component, forwardRef, Input } from '@angular/core';
import { NG_VALUE_ACCESSOR } from '@angular/forms';
@Component({
selector: 'app-radio',
templateUrl: './radio.component.html',
styleUrls: ['./radio.component.scss'],
providers: [
{
provide: NG_VALUE_ACCESSOR,
multi: true,
useExisting: forwardRef(() => RadioComponent),
},
],
})
export class RadioComponent {
_value: string;
@Input() selectValue: any;
@Input() label: string;
private onTouchedCallback: () => void = () => {};
private onChangeCallback: (_: any) => void = () => {};
get value(): string {
return this._value;
}
@Input('value')
set value(text: string) {
if (this._value !== text) {
this._value = text;
this.onChangeCallback(text);
}
}
writeValue(text: string): void {
if (text !== this.value) {
this.value = text;
}
}
registerOnChange(fn: any): void {
this.onChangeCallback = fn;
}
registerOnTouched(fn: any): void {
this.onTouchedCallback = fn;
}
setDisabledState(isDisabled: boolean): void {
}
}
radio.component.html
<label class="radio-wrapper">
<input type="radio" [value]="selectValue" [(ngModel)]="value" >
<span class="checkmark"></span><span class="label">{{ label }}</span>
</label>
radio.component.scss
.radio-wrapper {
display: inline-flex;
align-items: center;
position: relative;
margin-top: 8px;
cursor: pointer;
font-size: 16px;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
&.margin-left {
margin-left: 34px;
}
.label {
margin-left: 4px;
}
}
/* Hide the browser's default radio button */
.radio-wrapper input {
position: absolute;
opacity: 0;
}
/* Create a custom radio button */
.checkmark {
display: inline-block;
//position: absolute;
//top: 0;
//left: 0;
height: 21px;
width: 21px;
background-color: #eee;
border-radius: 50%;
}
/* On mouse-over, add a grey background color */
.radio-wrapper:hover input ~ .checkmark {
background-color: #ccc;
}
/* When the radio button is checked, add a blue background */
.radio-wrapper input:checked ~ .checkmark {
background-color: white;
border: 1px solid #2196F3;
}
/* Create the indicator (the dot/circle - hidden when not checked) */
.checkmark:after {
content: "";
position: absolute;
display: none;
}
/* Show the indicator (dot/circle) when checked */
.radio-wrapper input:checked ~ .checkmark:after {
display: block;
}
/* Style the indicator (dot/circle) */
.radio-wrapper .checkmark:after {
top: 7px;
left: 7px;
width: 9px;
height: 9px;
border-radius: 50%;
background: #2196F3;
}