src/view/form-view.js
'use strict'
import { eachEntry } from '../core/util.js'
import View from './view.js'
/**
* A FormView is data fields to bind input, select or textarea by theirs names.
*
* @example
* // Create a FormView bound to loginForm
* views.form = new FormView('loginForm');
*
* evts.form_submit = function(sender, e) {
* var body = this.data;
* http.post('/login', { body });
* }
* @example {@lang xml}
* <form id="loginForm">
* <input type="text" name="email">
* <input type="password" name="password">
* <button type="submit">Sign in</button>
* </form>
*/
class FormView extends View {
/**
* @override
*/
get data() {
return this._assignFromFields(this._data);
}
set data(value) {
super.data = value;
}
/**
* Get field value as the type.
*
* @param {string} field - target field
* @return {Any} the value
*/
getValueOf(field) {
const el = this.findEl(field);
if (el) {
return this._valueAsType(el);
}
const vw = this.views[field];
if (vw) {
return vw.data;
}
}
/**
* also returns form element by name.
* @override
*/
findEl(id) {
return this.el[id] || super.findEl(id);
}
_assignFromFields(data = {}) {
const result = { ...data }
// FormData cooks radio buttons and no name inputs
for (let [name, _] of new FormData(this.el)) {
result[name] = this._valueAsType(this.el[name]);
}
eachEntry(this.views, ([name, view]) => {
result[name] = view.data;
});
return result;
}
_valueAsType(el) {
const ds = el.dataset || {};
const type = ds.type || 'text';
let val = el.value;
if (type.startsWith('date') || el.type === 'datetime-local') {
val = new Date(val)
} else if (type === 'number') {
val = Number(val)
} else if (type.startsWith('bool')) {
val = Boolean(val)
}
return val;
}
_setFieldValue(name, val) {
const input = this.el[name];
if (input) {
if (input.type === 'datetime-local') {
val = this.formatLocalDateTime(new Date(val))
}
input.value = val;
return;
}
super._setFieldValue(name, val);
}
formatLocalDateTime(date) {
return [date.getFullYear(), '-',
('0' + (date.getMonth() + 1)).slice(-2), '-',
('0' + date.getDate()).slice(-2), 'T',
('0' + date.getHours()).slice(-2), ':',
('0' + date.getMinutes()).slice(-2)
].join('')
}
}
export default FormView