File
Implements
Metadata
selector |
cd-rbd-configuration-form |
styleUrls |
./rbd-configuration-form.component.scss |
templateUrl |
./rbd-configuration-form.component.html |
Index
Properties
|
|
Methods
|
|
Inputs
|
|
Outputs
|
|
initializeData
|
Type : EventEmitter<literal type>
|
|
Methods
Private
createConfigurationFormGroup
|
createConfigurationFormGroup()
|
|
Dynamically create form controls.
|
isDisabled
|
isDisabled(optionName: string)
|
|
Parameters :
Name |
Type |
Optional |
optionName |
string
|
No
|
|
reset
|
reset(optionName: string)
|
|
Reset the value. The inherited value will be used instead.
Parameters :
Name |
Type |
Optional |
optionName |
string
|
No
|
|
toggleSectionVisibility
|
toggleSectionVisibility(className)
|
|
Parameters :
Name |
Optional |
className |
No
|
|
configurationType
|
Default value : RbdConfigurationType
|
|
ngDataReady
|
Default value : new EventEmitter<any>()
|
|
sectionVisibility
|
Type : literal type
|
Default value : {}
|
|
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { FormControl, Validators } from '@angular/forms';
import { CdFormGroup } from '../../../shared/forms/cd-form-group';
import {
RbdConfigurationEntry,
RbdConfigurationSourceField,
RbdConfigurationType
} from '../../../shared/models/configuration';
import { FormatterService } from '../../../shared/services/formatter.service';
import { RbdConfigurationService } from '../../../shared/services/rbd-configuration.service';
@Component({
selector: 'cd-rbd-configuration-form',
templateUrl: './rbd-configuration-form.component.html',
styleUrls: ['./rbd-configuration-form.component.scss']
})
export class RbdConfigurationFormComponent implements OnInit {
@Input()
form: CdFormGroup;
@Input()
initializeData: EventEmitter<{
initialData: RbdConfigurationEntry[];
sourceType: RbdConfigurationSourceField;
}>;
@Output()
changes = new EventEmitter<any>();
ngDataReady = new EventEmitter<any>();
initialData: RbdConfigurationEntry[];
configurationType = RbdConfigurationType;
sectionVisibility: { [key: string]: boolean } = {};
constructor(
public formatterService: FormatterService,
public rbdConfigurationService: RbdConfigurationService
) {}
ngOnInit() {
const configFormGroup = this.createConfigurationFormGroup();
this.form.addControl('configuration', configFormGroup);
// Listen to changes and emit the values to the parent component
configFormGroup.valueChanges.subscribe(() => {
this.changes.emit(this.getDirtyValues.bind(this));
});
if (this.initializeData) {
this.initializeData.subscribe((data) => {
this.initialData = data.initialData;
const dataType = data.sourceType;
this.rbdConfigurationService.getWritableOptionFields().forEach((option) => {
const optionData = data.initialData.filter((entry) => entry.name === option.name).pop();
if (optionData && optionData['source'] === dataType) {
this.form.get(`configuration.${option.name}`).setValue(optionData['value']);
}
});
this.ngDataReady.emit();
});
}
this.rbdConfigurationService
.getWritableSections()
.forEach((section) => (this.sectionVisibility[section.class] = false));
}
getDirtyValues(includeLocalValues = false, localFieldType?: RbdConfigurationSourceField) {
if (includeLocalValues && !localFieldType) {
const msg =
'ProgrammingError: If local values shall be included, a proper localFieldType argument has to be provided, too';
throw new Error(msg);
}
const result = {};
this.rbdConfigurationService.getWritableOptionFields().forEach((config) => {
const control = this.form.get('configuration').get(config.name);
const dirty = control.dirty;
if (this.initialData && this.initialData[config.name] === control.value) {
return; // Skip controls with initial data loaded
}
if (dirty || (includeLocalValues && control['source'] === localFieldType)) {
if (control.value === null) {
result[config.name] = control.value;
} else if (config.type === RbdConfigurationType.bps) {
result[config.name] = this.formatterService.toBytes(control.value);
} else if (config.type === RbdConfigurationType.milliseconds) {
result[config.name] = this.formatterService.toMilliseconds(control.value);
} else if (config.type === RbdConfigurationType.iops) {
result[config.name] = this.formatterService.toIops(control.value);
} else {
result[config.name] = control.value;
}
}
});
return result;
}
/**
* Dynamically create form controls.
*/
private createConfigurationFormGroup() {
const configFormGroup = new CdFormGroup({});
this.rbdConfigurationService.getWritableOptionFields().forEach((c) => {
let control: FormControl;
if (
c.type === RbdConfigurationType.milliseconds ||
c.type === RbdConfigurationType.iops ||
c.type === RbdConfigurationType.bps
) {
control = new FormControl(0, Validators.min(0));
} else {
throw new Error(
`Type ${c.type} is unknown, you may need to add it to RbdConfiguration class`
);
}
configFormGroup.addControl(c.name, control);
});
return configFormGroup;
}
/**
* Reset the value. The inherited value will be used instead.
*/
reset(optionName: string) {
const formControl = this.form.get('configuration').get(optionName);
if (formControl.disabled) {
formControl.setValue(formControl['previousValue'] || 0);
formControl.enable();
if (!formControl['previousValue']) {
formControl.markAsPristine();
}
} else {
formControl['previousValue'] = formControl.value;
formControl.setValue(null);
formControl.markAsDirty();
formControl.disable();
}
}
isDisabled(optionName: string) {
return this.form.get('configuration').get(optionName).disabled;
}
toggleSectionVisibility(className) {
this.sectionVisibility[className] = !this.sectionVisibility[className];
}
}
<fieldset #cfgFormGroup [formGroup]="form.get('configuration')">
<legend i18n>RBD Configuration</legend>
<div *ngFor="let section of rbdConfigurationService.sections">
<h3 class="page-header">
<span
(click)="toggleSectionVisibility(section.class)"
class="collapsible">{{ section.heading }} <i [ngClass]="{'fa-plus-circle': !sectionVisibility[section.class], 'fa-minus-circle': sectionVisibility[section.class]}" class="fa" aria-hidden="true"></i></span>
</h3>
<div class="{{ section.class }}" [hidden]="!sectionVisibility[section.class]">
<div
class="form-group"
*ngFor="let option of section.options"
[ngClass]="{'has-error': form.showError('configuration.' + option.name, cfgFormGroup)}">
<label
class="control-label col-sm-3"
[for]="option.name">{{ option.displayName }}<cd-helper>{{ option.description }}</cd-helper></label>
<div class="col-sm-9 {{ section.heading }}">
<div class="input-group">
<ng-container [ngSwitch]="option.type">
<ng-container *ngSwitchCase="configurationType.milliseconds">
<input
[id]="option.name"
[name]="option.name"
[formControlName]="option.name"
type="text"
class="form-control"
[ngDataReady]="ngDataReady"
cdMilliseconds>
</ng-container>
<ng-container *ngSwitchCase="configurationType.bps">
<input
[id]="option.name"
[name]="option.name"
[formControlName]="option.name"
type="text"
class="form-control"
defaultUnit="b"
[ngDataReady]="ngDataReady"
cdDimlessBinaryPerSecond>
</ng-container>
<ng-container *ngSwitchCase="configurationType.iops">
<input
[id]="option.name"
[name]="option.name"
[formControlName]="option.name"
type="text"
class="form-control"
[ngDataReady]="ngDataReady"
cdIops>
</ng-container>
</ng-container>
<span class="input-group-btn">
<button
class="btn btn-default"
type="button"
data-toggle="button"
[ngClass]="{'active': isDisabled(option.name)}"
tooltip="Remove the local configuration value. The parent configuration value will be inherited and used instead."
containerClass="tooltip-wide"
[delay]="1000"
i18n-tooltip
(click)="reset(option.name)">
<i class="fa fa-eraser"
aria-hidden="true"></i>
</button>
</span>
</div>
<span
i18n
class="help-block"
*ngIf="form.showError('configuration.' + option.name, cfgFormGroup, 'min')">The mininum value is 0</span>
</div>
</div>
</div>
</div>
</fieldset>
.collapsible {
cursor: pointer;
user-select: none;
}
Legend
Html element with directive