简单的 pug html 表单,让它在值更改时立即发送,而不是等待提交按钮
Simple pug html form, make it send immediately on change of value rather than wait for submit button
我有一个非常简单的 pug 文件:
for item in itemList
form(method='post', action='/change')
table
tr
td(width=100)
td(width=200)
| #{item.name}
input(type='hidden', name='field' value=item.name)
input(type='hidden', name='style' value='doublevalue')
td(width=100)
input(type='number', name='value' min=-20.0 max=80.00 step=0.01 value=+item.value)
td(width=100)
input(type='submit', value='Update')
p end
如您所见,它会生成一些像这样的微不足道的 form
s:
(每个表格是一个'line',这是一个简单的table。)
(在脚本方面,它只是从 MySQL table 中读取每个 'line',其中有 10 个左右。)
因此在 www 页面上,用户要么
输入新数字(比如“8”)
或单击小箭头(例如向上,在示例中将其更改为 7.2)
那么用户必须
- 点击提交
并发送 post
.
很简单,我希望当用户
- 单击一个小箭头(例如向上,在示例中将其更改为 7.2)
它立即发送一个提交-post。
如何实现?
(如果发送发生,任何时候用户在字段中键入内容,and/or,当用户单击小的向上和向下按钮时,就可以了。Either/both 很好。 )
可能相关:
我的哈巴狗文件(以及我所有的哈巴狗文件)在第 1 行有这样 复杂 行代码:
include TOP.pug
我有一个很棒的文件,叫做 TOP.pug:
html
head
style.
html {
font-family: sans-serif
}
td {
font-family: monospace
}
body
我有 javascript 的解决方案。
// check if there are input[type="number"] to prevent errors
if (document.querySelector('input[type="number"]')) {
// add event for each of them
document.querySelectorAll('input[type="number"]').forEach(function(el) {
el.addEventListener('change', function (e) {
// on change submit the parent (closest) form
e.currentTarget.closest('form').submit()
});
});
}
实际上它很短,但如果你想支持 Internet Explorer,你还必须添加 polyfill 脚本。 Internet Explorer 不支持 closest()
下面我们教它的这段代码。
// polyfills for matches() and closest()
if (!Element.prototype.matches)
Element.prototype.matches = Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector;
if (!Element.prototype.closest) {
Element.prototype.closest = function(s) {
var el = this;
do {
if (el.matches(s)) return el;
el = el.parentElement || el.parentNode;
} while (el !== null && el.nodeType === 1);
return null;
};
}
Ajax 表单提交到 node.js
如果您对 ajax 解决方案感兴趣,我在下面放了一些代码只是为了让您大开眼界;-) 它应该可以立即运行,我在我的一个网站上使用了它。您可以使用 jQuery 并保存代码行,但我喜欢它纯粹。 (ajax 函数和 polyfills 是实用程序,所以将其粘贴到任何地方)
HTML(示例)
<form>
<input type="hidden" name="field" value="field1">
<input type="hidden" name="style" value="style1">
<input type="number" name="value">
<input type="submit" value="update">
</form>
<form>
<input type="hidden" name="field" value="field2">
<input type="hidden" name="style" value="style2">
<input type="number" name="value">
<input type="submit" value="update">
</form>
Javascript: 事件侦听器并准备 ajax 调用(注意回调)。
// check if there are forms to prevent errors
if (document.querySelector('form')) {
// add submit event for each form
document.querySelectorAll('form').forEach(function (el) {
el.addEventListener('submit', function (e) {
e.currentTarget.preventDefault();
submitData(e.currentTarget);
});
});
}
// check if there are input[type="number"] to prevent errors
if (document.querySelector('input[type="number"]')) {
// add change event for each of them
document.querySelectorAll('input[type="number"]').forEach(function (el) {
el.addEventListener('change', function (e) {
submitData(e.currentTarget.closest('form'));
});
});
}
// collect form data and send it
function submitData(form) {
// send data through (global) ajax function
ajax({
url: '/change',
method: 'POST',
data: {
field: form.querySelector('input[name="field"]').value,
style: form.querySelector('input[name="style"]').value,
value: form.querySelector('input[name="value"]').value,
},
// callback on success
success: function (response) {
// HERE COMES THE RESPONSE
console.log(response);
// error is defined in (node.js res.json({error: ...}))
if (response.error) {
// make something red
form.style.border = '1px solid red';
}
if (!response.error) {
// everything ok, make it green
form.style.border = '1px solid green';
}
// remove above styling
setTimeout(function () {
form.style.border = 'none';
}, 1000);
},
// callback on error
error: function (error) {
console.log('server error occurred: ' + error)
}
});
}
如前所述javascript utils(像库一样粘贴到任何地方)
// reusable ajax function
function ajax(obj) {
let a = {};
a.url = '';
a.method = 'GET';
a.data = null;
a.dataString = '';
a.async = true;
a.postHeaders = [
['Content-type', 'application/x-www-form-urlencoded'],
['X-Requested-With', 'XMLHttpRequest']
];
a.getHeaders = [
['X-Requested-With', 'XMLHttpRequest']
];
a = Object.assign(a, obj);
a.method = a.method.toUpperCase();
if (typeof a.data === 'string')
a.dataString = encodeURIComponent(a.data);
else
for (let item in a.data) a.dataString += item + '=' + encodeURIComponent(a.data[item]) + '&';
let xhReq = new XMLHttpRequest();
if (window.ActiveXObject) xhReq = new ActiveXObject('Microsoft.XMLHTTP');
if (a.method == 'GET') {
if (typeof a.data !== 'undefined' && a.data !== null) a.url = a.url + '?' + a.dataString;
xhReq.open(a.method, a.url, a.async);
for (let x = 0; x < a.getHeaders.length; x++) xhReq.setRequestHeader(a.getHeaders[x][0], a.getHeaders[x][1]);
xhReq.send(null);
}
else {
xhReq.open(a.method, a.url, a.async);
for (let x = 0; x < a.postHeaders.length; x++) xhReq.setRequestHeader(a.postHeaders[x][0], a.postHeaders[x][1]);
xhReq.send(a.dataString);
}
xhReq.onreadystatechange = function () {
if (xhReq.readyState == 4) {
let response;
try {
response = JSON.parse(xhReq.responseText)
} catch (e) {
response = xhReq.responseText;
}
//console.log(response);
if (xhReq.status == 200) {
obj.success(response);
}
else {
obj.error(response);
}
}
}
}
// (one more) polyfill for Object.assign
if (typeof Object.assign !== 'function') {
// Must be writable: true, enumerable: false, configurable: true
Object.defineProperty(Object, 'assign', {
value: function assign(target, varArgs) {
// .length of function is 2
if (target === null || target === undefined) {
throw new TypeError('Cannot convert undefined or null to object');
}
var to = Object(target);
for (var index = 1; index < arguments.length; index++) {
var nextSource = arguments[index];
if (nextSource !== null && nextSource !== undefined) {
for (var nextKey in nextSource) {
// Avoid bugs when hasOwnProperty is shadowed
if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
to[nextKey] = nextSource[nextKey];
}
}
}
}
return to;
},
writable: true,
configurable: true
});
}
// polyfills for matches() and closest()
if (!Element.prototype.matches)
Element.prototype.matches = Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector;
if (!Element.prototype.closest) {
Element.prototype.closest = function (s) {
var el = this;
do {
if (el.matches(s)) return el;
el = el.parentElement || el.parentNode;
} while (el !== null && el.nodeType === 1);
return null;
};
}
在node.js(例如快速路线)
// the route in node.js
app.post('/change', (req, res) => {
// your logic here
let field = req.body.field;
let style = req.body.style;
let value = req.body.value;
// ...
// response result
res.json({
databaseError: false, // or true
additionalStuff: 'message, markup and other things ...',
});
});
我有一个非常简单的 pug 文件:
for item in itemList
form(method='post', action='/change')
table
tr
td(width=100)
td(width=200)
| #{item.name}
input(type='hidden', name='field' value=item.name)
input(type='hidden', name='style' value='doublevalue')
td(width=100)
input(type='number', name='value' min=-20.0 max=80.00 step=0.01 value=+item.value)
td(width=100)
input(type='submit', value='Update')
p end
如您所见,它会生成一些像这样的微不足道的 form
s:
(每个表格是一个'line',这是一个简单的table。)
(在脚本方面,它只是从 MySQL table 中读取每个 'line',其中有 10 个左右。)
因此在 www 页面上,用户要么
输入新数字(比如“8”)
或单击小箭头(例如向上,在示例中将其更改为 7.2)
那么用户必须
- 点击提交
并发送 post
.
很简单,我希望当用户
- 单击一个小箭头(例如向上,在示例中将其更改为 7.2)
它立即发送一个提交-post。
如何实现?
(如果发送发生,任何时候用户在字段中键入内容,and/or,当用户单击小的向上和向下按钮时,就可以了。Either/both 很好。 )
可能相关:
我的哈巴狗文件(以及我所有的哈巴狗文件)在第 1 行有这样 复杂 行代码:
include TOP.pug
我有一个很棒的文件,叫做 TOP.pug:
html
head
style.
html {
font-family: sans-serif
}
td {
font-family: monospace
}
body
我有 javascript 的解决方案。
// check if there are input[type="number"] to prevent errors
if (document.querySelector('input[type="number"]')) {
// add event for each of them
document.querySelectorAll('input[type="number"]').forEach(function(el) {
el.addEventListener('change', function (e) {
// on change submit the parent (closest) form
e.currentTarget.closest('form').submit()
});
});
}
实际上它很短,但如果你想支持 Internet Explorer,你还必须添加 polyfill 脚本。 Internet Explorer 不支持 closest()
下面我们教它的这段代码。
// polyfills for matches() and closest()
if (!Element.prototype.matches)
Element.prototype.matches = Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector;
if (!Element.prototype.closest) {
Element.prototype.closest = function(s) {
var el = this;
do {
if (el.matches(s)) return el;
el = el.parentElement || el.parentNode;
} while (el !== null && el.nodeType === 1);
return null;
};
}
Ajax 表单提交到 node.js
如果您对 ajax 解决方案感兴趣,我在下面放了一些代码只是为了让您大开眼界;-) 它应该可以立即运行,我在我的一个网站上使用了它。您可以使用 jQuery 并保存代码行,但我喜欢它纯粹。 (ajax 函数和 polyfills 是实用程序,所以将其粘贴到任何地方)
HTML(示例)
<form>
<input type="hidden" name="field" value="field1">
<input type="hidden" name="style" value="style1">
<input type="number" name="value">
<input type="submit" value="update">
</form>
<form>
<input type="hidden" name="field" value="field2">
<input type="hidden" name="style" value="style2">
<input type="number" name="value">
<input type="submit" value="update">
</form>
Javascript: 事件侦听器并准备 ajax 调用(注意回调)。
// check if there are forms to prevent errors
if (document.querySelector('form')) {
// add submit event for each form
document.querySelectorAll('form').forEach(function (el) {
el.addEventListener('submit', function (e) {
e.currentTarget.preventDefault();
submitData(e.currentTarget);
});
});
}
// check if there are input[type="number"] to prevent errors
if (document.querySelector('input[type="number"]')) {
// add change event for each of them
document.querySelectorAll('input[type="number"]').forEach(function (el) {
el.addEventListener('change', function (e) {
submitData(e.currentTarget.closest('form'));
});
});
}
// collect form data and send it
function submitData(form) {
// send data through (global) ajax function
ajax({
url: '/change',
method: 'POST',
data: {
field: form.querySelector('input[name="field"]').value,
style: form.querySelector('input[name="style"]').value,
value: form.querySelector('input[name="value"]').value,
},
// callback on success
success: function (response) {
// HERE COMES THE RESPONSE
console.log(response);
// error is defined in (node.js res.json({error: ...}))
if (response.error) {
// make something red
form.style.border = '1px solid red';
}
if (!response.error) {
// everything ok, make it green
form.style.border = '1px solid green';
}
// remove above styling
setTimeout(function () {
form.style.border = 'none';
}, 1000);
},
// callback on error
error: function (error) {
console.log('server error occurred: ' + error)
}
});
}
如前所述javascript utils(像库一样粘贴到任何地方)
// reusable ajax function
function ajax(obj) {
let a = {};
a.url = '';
a.method = 'GET';
a.data = null;
a.dataString = '';
a.async = true;
a.postHeaders = [
['Content-type', 'application/x-www-form-urlencoded'],
['X-Requested-With', 'XMLHttpRequest']
];
a.getHeaders = [
['X-Requested-With', 'XMLHttpRequest']
];
a = Object.assign(a, obj);
a.method = a.method.toUpperCase();
if (typeof a.data === 'string')
a.dataString = encodeURIComponent(a.data);
else
for (let item in a.data) a.dataString += item + '=' + encodeURIComponent(a.data[item]) + '&';
let xhReq = new XMLHttpRequest();
if (window.ActiveXObject) xhReq = new ActiveXObject('Microsoft.XMLHTTP');
if (a.method == 'GET') {
if (typeof a.data !== 'undefined' && a.data !== null) a.url = a.url + '?' + a.dataString;
xhReq.open(a.method, a.url, a.async);
for (let x = 0; x < a.getHeaders.length; x++) xhReq.setRequestHeader(a.getHeaders[x][0], a.getHeaders[x][1]);
xhReq.send(null);
}
else {
xhReq.open(a.method, a.url, a.async);
for (let x = 0; x < a.postHeaders.length; x++) xhReq.setRequestHeader(a.postHeaders[x][0], a.postHeaders[x][1]);
xhReq.send(a.dataString);
}
xhReq.onreadystatechange = function () {
if (xhReq.readyState == 4) {
let response;
try {
response = JSON.parse(xhReq.responseText)
} catch (e) {
response = xhReq.responseText;
}
//console.log(response);
if (xhReq.status == 200) {
obj.success(response);
}
else {
obj.error(response);
}
}
}
}
// (one more) polyfill for Object.assign
if (typeof Object.assign !== 'function') {
// Must be writable: true, enumerable: false, configurable: true
Object.defineProperty(Object, 'assign', {
value: function assign(target, varArgs) {
// .length of function is 2
if (target === null || target === undefined) {
throw new TypeError('Cannot convert undefined or null to object');
}
var to = Object(target);
for (var index = 1; index < arguments.length; index++) {
var nextSource = arguments[index];
if (nextSource !== null && nextSource !== undefined) {
for (var nextKey in nextSource) {
// Avoid bugs when hasOwnProperty is shadowed
if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
to[nextKey] = nextSource[nextKey];
}
}
}
}
return to;
},
writable: true,
configurable: true
});
}
// polyfills for matches() and closest()
if (!Element.prototype.matches)
Element.prototype.matches = Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector;
if (!Element.prototype.closest) {
Element.prototype.closest = function (s) {
var el = this;
do {
if (el.matches(s)) return el;
el = el.parentElement || el.parentNode;
} while (el !== null && el.nodeType === 1);
return null;
};
}
在node.js(例如快速路线)
// the route in node.js
app.post('/change', (req, res) => {
// your logic here
let field = req.body.field;
let style = req.body.style;
let value = req.body.value;
// ...
// response result
res.json({
databaseError: false, // or true
additionalStuff: 'message, markup and other things ...',
});
});