SLDS-Input for SLDS-UI Module
One of the important and big steps in custom UI elements developent is Custom Form Component. We should be able to create our own UI components that must behave as standard component from Angular FormModule. In this case we need to implement ControlValueAccessor interface with few some additional hacks. I want to start with simple input that I will wrap with SLDS input form-element styles.
slds-input.component.html
slds-input.component.ts
Small hack - idPrefix. To make standard label+input tags work together we need to set label[for] and input[id] as unique value across the whole page. To automate it we can generate some random value in contructor. I've added getRandomString to new utils.ts file.
Also interesting moment is input type check in onValueChange method to return value in proper format (string or integer).
And usage example:
If all changes was good you should see this modal
And final updates to finish with Task creation here is few new methods in
task.component.ts
and in the backend
controllers/task.py
If new Task is created successfully you should see Details page for this task
slds-input.component.html
<div class="slds-form-element">
<label class="slds-form-element__label" [for]="idPrefix+'_input-id-1'">
<abbr *ngIf="required" class="slds-required" title="required">* </abbr>{{label}}</label>
<div class="slds-form-element__control">
<input
[type]="type"
[ngModel]="value"
(ngModelChange)="onValueChange($event)"
[id]="idPrefix+'_input-id-1'"
[name]="name"
[required]="required"
[disabled]="disabled"
class="slds-input" />
</div>
</div>
slds-input.component.ts
import { Component, OnInit, Input, Output, EventEmitter, forwardRef } from '@angular/core';
import { getRandomString } from '../../utils';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
@Component({
selector: 'slds-input',
templateUrl: './slds-input.component.html',
styleUrls: ['./slds-input.component.scss'],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => SldsInputComponent),
multi: true
}
]
})
export class SldsInputComponent implements ControlValueAccessor {
@Input() type = 'text';
@Input() label = '<No label>';
@Input() name: string;
@Input() required = false;
@Input() disabled = false;
@Output() valueChange = new EventEmitter();
idPrefix = '';
value: string|number;
oldValue: string|number;
constructor() {
this.idPrefix = getRandomString();
}
writeValue(value: any): void {
this.value = value;
this.oldValue = value;
}
propagateChange = (_: any) => {};
registerOnChange(fn: any): void {
this.propagateChange = fn;
}
registerOnTouched(fn: any): void {
}
onValueChange(newValue: any) {
this.value = newValue;
if (this.type === 'number') {
this.value = parseInt(this.value as string, 10);
}
this.propagateChange(this.value);
}
}
Small hack - idPrefix. To make standard label+input tags work together we need to set label[for] and input[id] as unique value across the whole page. To automate it we can generate some random value in contructor. I've added getRandomString to new utils.ts file.
export function getRandomString() {
return Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);
}
Also interesting moment is input type check in onValueChange method to return value in proper format (string or integer).
And usage example:
...
<slds-modal
*ngIf="showNewTaskModal"
title="New Task">
<modal-content>
<slds-input
[(ngModel)]="newTask.name"
label="Name"
required="true"></slds-input>
</modal-content>
<modal-actions>
<button class="slds-button slds-button_neutral" (click)="cancelCreateEmptyTask()">Cancel</button>
<button class="slds-button slds-button_brand" (click)="createEmptyTask()">Create</button>
</modal-actions>
</slds-modal>
If all changes was good you should see this modal
And final updates to finish with Task creation here is few new methods in
task.component.ts
...
openNewTaskModal() {
this.newTask = {
id: null,
name: '',
status: 'stop',
config: null,
user_id: null
};
this.showNewTaskModal = true;
}
createEmptyTask() {
this.remoteService.createEmptyTask(this.newTask)
.then((data) => {
this.showNewTaskModal = false;
if (data && data.id) {
this.router.navigate(['/tasks', data.id]);
}
});
}
cancelCreateEmptyTask() {
this.showNewTaskModal = false;
}
...
and in the backend
controllers/task.py
...
@task_bp.route('/create', methods=['POST'])
@login_required
def create_task():
task_dto = request.get_json()
task = Task(
name=task_dto['name'],
status='stop',
user_id=current_user.id,
config={}
)
db.session.add(task)
db.session.commit()
return jsonify(task)
...
If new Task is created successfully you should see Details page for this task
Comments
Post a Comment