I want to capture the event of a user pressing enter on an input of type="text" when they are filling out a form. This is done all over the web, yet the answer eludes me.
This is what I have so far:
In the html file, I have a text input like so:
<input type="text" size=50 class="newlink">
In the Javascript file, I am trying to capture the the user pressing enter to effectively submit the form. I am then grabbing the text from the input and going to stash it in the database:
Template.newLink.events = {
'submit input.newLink': function () {
var url = template.find(".newLink").value;
// add to database
}
};
The submit event is emitted from forms, not single input elements.
The built in event map for meteor is documented here: http://docs.meteor.com/#eventmaps.
You'll have to listen for a keyboard event (keydown, keypress, keyup). Within the event handler, check, if it's the return/enter key (Keycode 13), and proceed on success.
Template.newLink.events = {
'keypress input.newLink': function (evt, template) {
if (evt.which === 13) {
var url = template.find(".newLink").value;
// add to database
}
}
};
You could look into how this is achieved in the todos example (client/todos.js).
It uses a generic event handler for input fields (as seen below). You can browse the rest of the code for usage.
////////// Helpers for in-place editing //////////
// Returns an event map that handles the "escape" and "return" keys and
// "blur" events on a text input (given by selector) and interprets them
// as "ok" or "cancel".
var okCancelEvents = function (selector, callbacks) {
var ok = callbacks.ok || function () {};
var cancel = callbacks.cancel || function () {};
var events = {};
events['keyup '+selector+', keydown '+selector+', focusout '+selector] =
function (evt) {
if (evt.type === "keydown" && evt.which === 27) {
// escape = cancel
cancel.call(this, evt);
} else if (evt.type === "keyup" && evt.which === 13 ||
evt.type === "focusout") {
// blur/return/enter = ok/submit if non-empty
var value = String(evt.target.value || "");
if (value)
ok.call(this, value, evt);
else
cancel.call(this, evt);
}
};
return events;
};
I used this js function once to suppress the user using the return key in the text field to submit the form data. Perhaps you could modify it to suit the capture?
function stopRKey(evt) { // Stop return key functioning in text field.
var evt = (evt) ? evt : ((event) ? event : null);
var node = (evt.target) ? evt.target : ((evt.srcElement) ? evt.srcElement : null);
if ((evt.keyCode == 13) && (node.type=="text")) { return false; }
}
document.onkeypress = stopRKey;
You can also use event.currentTarget.value
Template.newLink.events = {
'keypress input.newLink': function (evt) {
if (evt.which === 13) {
var url = event.currentTarget.value;
// add to database
}
}
};
Related
I have a very simple pug file:
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
As you can see it produces a few trivial forms like this:
(Each form is one 'line' which is a simple table.)
(On the script side, it just reads each 'line' from a MySQL table, there are 10 or so of them.)
So on the www page, the user either
types in new number (say "8")
or clicks the small arrows (say Up, changing it to 7.2 in the example)
then the user must
click submit
and it sends the post.
Quite simply, I would like it to be that when the user
clicks a small arrows (say Up, changing it to 7.2 in the example)
it immediately sends a submit-post.
How do I achieve this?
(It would be fine if the send happens, any time the user types something in the field, and/or, when the user clicks the Small Up And Down Buttons. Either/both is fine.)
May be relevant:
My pug file (and all my pug files) have this sophisticated line of code as line 1:
include TOP.pug
And I have a marvellous file called TOP.pug:
html
head
style.
html {
font-family: sans-serif
}
td {
font-family: monospace
}
body
I have a solution with 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()
});
});
}
Actually it is short but if you want to support Internet Explorer you have to add the polyfill script too. Internet Explorer does not support closest() with this snippet below we teach it.
// 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 form submit to node.js
If you are interested in an ajax solution I put some code below just to blow your mind ;-) It should work instantly, I use it on one of my sites. You could use jQuery and save lines of code but I like it pure. (The ajax function and polyfills are utils so paste it anywhere)
HTML (example)
<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: event listener and prepare ajax call (note the callbacks).
// 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)
}
});
}
As told javascript utils (paste it anywhere like a library)
// 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;
};
}
In node.js (e.g. express route)
// 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 ...',
});
});
Please help with the script function on how to make select2 plugin work in wizard jquery template it is not firing and i'm using the search box, when it clicked it jams.Thank you
$('.class').select2(); AFTER $('#form').steps();
This has helped me thanks but..
$("#form").steps({
bodyTag: "fieldset",
onStepChanging: function (event, currentIndex, newIndex)
{
// Always allow going backward even if the current step contains invalid fields!
if (currentIndex > newIndex)
{
return true;
}
// Forbid suppressing "Warning" step if the user is to young
if (newIndex === 3 && Number($("#age").val()) < 18)
{
return false;
}
var form = $(this);
// Clean up if user went backward before
if (currentIndex < newIndex)
{
// To remove error styles
$(".body:eq(" + newIndex + ") label.error", form).remove();
$(".body:eq(" + newIndex + ") .error", form).removeClass("error");
}
// Disable validation on fields that are disabled or hidden.
form.validate().settings.ignore = ":disabled,:hidden";
// Start validation; Prevent going forward if false
return form.valid();
},
onStepChanged: function (event, currentIndex, priorIndex)
{
// Suppress (skip) "Warning" step if the user is old enough.
if (currentIndex === 2 && Number($("#age").val()) >= 18)
{
$(this).steps("next");
}
// Suppress (skip) "Warning" step if the user is old enough and wants to the previous step.
if (currentIndex === 2 && priorIndex === 3)
{
$(this).steps("previous");
}
},
onFinishing: function (event, currentIndex)
{
var form = $(this);
// Disable validation on fields that are disabled.
// At this point it's recommended to do an overall check (mean ignoring only disabled fields)
form.validate().settings.ignore = ":disabled";
// Start validation; Prevent form submission if false
return form.valid();
},
onFinished: function (event, currentIndex)
{
var form = $(this);
// Submit form input
form.submit();
}
}).validate({
errorPlacement: function (error, element)
{
element.before(error);
},
rules: {
confirm: {
equalTo: "#password"
}
}
});
//IMPORTANT
var form =$("#form");
form.find("#personel_id").select2({
theme: 'bootstrap4',
});
I have come up with a methodology for making editable text in my Meteor app. However, it does not follow the DRY paradigm and I'd like to change that but I am not too good with Javascript yet...
Suppose I have a table cell with some text and I'd like to double click it to edit it. I created a template variable to handle this:
<td class="itemName">
{{#unless editItemName}}
{{name}}
{{else}}
<input class="editItemName" type="text" value="{{name}}" style="width:100px;">
{{/unless}}
</td>
I then create an event to execute this transition on a double-click:
Template.inventoryItemDetail.events = {
'dblclick td.itemName': function (evt) {
Session.set("editItemName",true);
},
'blur input.editItemName': function () {
Session.set("editItemName",null);
},};
I also reused the ok_cancel code from the ToDo's example app (but that's sort of irrelevant):
// Returns an event_map key for attaching "ok/cancel" events to
// a text input (given by selector)
var okcancel_events = function (selector) {
return 'keyup '+selector+', keydown '+selector+', focusout '+selector;
};
// Creates an event handler for interpreting "escape", "return", and "blur"
// on a text field and calling "ok" or "cancel" callbacks.
var make_okcancel_handler = function (options) {
var ok = options.ok || function () {};
var cancel = options.cancel || function () {};
return function (evt) {
if (evt.type === "keydown" && evt.which === 27) {
// escape = cancel
cancel.call(this, evt);
evt.currentTarget.blur();
} else if (evt.type === "keyup" && evt.which === 13) {
// blur/return/enter = ok/submit if non-empty
var value = String(evt.target.value || "");
if (value) {
ok.call(this, value, evt);
evt.currentTarget.blur();
}
else {
cancel.call(this, evt);
evt.currentTarget.blur();
}
}
};
};
Template.inventoryItemDetail.events[ okcancel_events('input.editItemName') ] = make_okcancel_handler({
ok: function (value) {
Items.update(this._id, {$set: {name: value}});
}
});
Finally, I have to tie this Session variable to the template variable:
Template.inventoryItemDetail.editItemName = function () {
return Session.get("editItemName");
};
So right now, I have repeated all of this again and again for each editable text field and it all works, but it seems like terribly programming practice. I have found various editable text utilities on Github but I don't entirely understand them and none of them are for Meteor!
I'd really like to expand my knowledge of Meteor and Javascript by creating a tool that allows me to have editable text without repeating myself this ridiculous amount for each editable text field.
Thanks,
Chet
https://github.com/nate-strauser/meteor-x-editable-bootstrap for the package.
http://vitalets.github.io/x-editable/docs.html for the docs.
I just implemented this in my project and I won't ever go back to contenteditable.
How can I prevent events with conflict time? Is there any variable to set up?
No, there is not a variable to set, but you can use something like clientEvents which retrieves events that fullcalendar has in memory. You can use the function below in the eventDrop. In the case below it uses a function to filter out whether the event will have have an overlap or not.
function checkOverlap(event) {
var start = new Date(event.start);
var end = new Date(event.end);
var overlap = $('#calendar').fullCalendar('clientEvents', function(ev) {
if( ev == event)
return false;
var estart = new Date(ev.start);
var eend = new Date(ev.end);
return (Math.round(estart)/1000 < Math.round(end)/1000 && Math.round(eend) > Math.round(start));
});
if (overlap.length){
//either move this event to available timeslot or remove it
}
}
you can add eventOverlap : false in the celendar config,
http://fullcalendar.io/docs/event_ui/eventOverlap/
Correct overlap checking.
eventDrop: function(event, dayDelta, minuteDelta, allDay, revertFunc, jsEvent, ui, view) {
/// deny overlap of event
var start = new Date(event.start);
var end = new Date(event.end);
var overlap = $('#calendar').fullCalendar('clientEvents', function(ev) {
if( ev == event) {
return false;
}
var estart = new Date(ev.start);
var eend = new Date(ev.end);
return (
( Math.round(start) > Math.round(estart) && Math.round(start) < Math.round(eend) )
||
( Math.round(end) > Math.round(estart) && Math.round(end) < Math.round(eend) )
||
( Math.round(start) < Math.round(estart) && Math.round(end) > Math.round(eend) )
);
});
if (overlap.length){
revertFunc();
return false;
}
}
Add custom property in the event object overlap:false for example your event object will be
`{
title:'Event',
start: '2017-01-04T16:30:00',
end: '2017-01-04T16:40:00',
overlap:false
}`
Now override selectOverlap function,
selectOverlap: function(event) {
if(event.ranges && event.ranges.length >0) {
return (event.ranges.filter(function(range){
return (event.start.isBefore(range.end) &&
event.end.isAfter(range.start));
}).length)>0;
}
else {
return !!event && event.overlap;
}
},
It will not let the another event to override the already placed event.
This does the trick. It also handles resizing overlapping events
var calendar = new Calendar(calendarEl, {
selectOverlap: false,
eventOverlap: false
}
});
I am using Update Panel in my asp page and I am doing JQuery Validation on Asynchronous Postback...
I just want to validate my form on only button clicks or submits...
My problem is..all my buttons are in different formviews and won't load at a time...that's why I am unable to take the button id's and use the click events..here is my code..
Sys.WebForms.PageRequestManager.getInstance().add_initializeRequest(ValidateMyForm);
function ValidateMyForm(sender, args) {
var objPost = args.get_postBackElement();
if (objPost === null || objPost === undefined) return;
if (objPost.id == '<%= ((Button)(formViewinfo.FindControl("btnUpdate"))).ClientID %>') {
$('#pnlerrors').fadeOut('fast');
$('#pnlItemErrors').fadeOut('fast');
var isValid = $('#form1').validate({
errorClass: 'error',
invalidHandler: function (e, validator) {
var errors = validator.numberOfInvalids();
if (errors) {
$('#pnlerrors').html('<p> Please correct the errors </p>').fadeIn('fast');
document.location.href = '#pnlerrors';
}
}, submitHandler: function () {
}
}).form();
if (!isValid) {
CancelPostback(sender, args);
} else {
}
}
//this is for rest of buttons
else {
$('#pnlItemErrors').fadeOut('fast');
$('#pnlerrors').fadeOut('fast');
var isValid = $('#form1').validate({
errorClass: 'error',
invalidHandler: function (e, validator) {
var errors = validator.numberOfInvalids();
if (errors) {
$('#pnlerrors').fadeOut('fast');
document.location.replace('#', '#pnlItemErrors');
$('#pnlItemErrors').html('<p> Please correct the errors </p>').fadeIn('fast');
document.location.href = '#pnlItemErrors';
}
}, submitHandler: function () {
}
}).form();
if (!isValid) {
CancelPostback(sender, args);
} else {
}
}
}
All I want to do is: 2nd time validation on only button submit not for everything...I do get other postbacks on this page and those post backs also gets validated each time (I want to Avoid this)...
I don't know this approach is good or not...I am struggling with this from long time..I really appreciate you help...
On the assumption that you don't want to submit the form when someone presses the enter button, and that you only want to submit the form on pressing a submit button:
$(document).ready(
function(){
$('form').keypress(
function(event){
if (event.keyCode == '13'){
return false;
}
});
$('input:submit').click(
function(){
$(this).closest('form').submit();
});
$('form').submit(
function(){
$('#success').text('form submitted! (Not really...)');
return false;
// Just to stop the error messages
// in this demo.
});
});
There's a JS Fiddle demo, here: http://jsfiddle.net/davidThomas/5PaWz/.
If I'm mistaken in my assumptions, please leave a comment and I'll try to correct myself.
if your problem is just about finding the buttons the need to have validations then
one way of getting around this is to add a class to the buttons that you want to trigger validation, for example :
<asp:button id="btn1" cssclass="Validate"/>
then you can grab all these buttons in JQuery:
var buttons = $('.Validate');
get each button id:
$(buttons).each(function(){
var id = this.id;
});
ohh..god finally found the solution for my problem...First of all my apologizes if my question is not clear....
My validation works on asynchronous post backs...I just want validate my form on button clicks..i do have an asp.net grid view in my page..if i click on paging or something on the grid it fires validation...i want avoid this..
for this what i did is...i am capturing the postback element with the following statement.
var objPost = args.get_postBackElement();
then i am checking for type..
if (objpost.type == 'submit') { do validation }
else { don't }..
this ends my 2days struggle...
thank you very much your support and help...
Try different approach.
Use asp.Net Button with UseSubmitBehavior=true for submission
and use asp.Net Button with UserSubmitBehavior=false for buttons that you don't want them to fire the validation process that. add this following code to your form
function ValidateForm()
{
var errors ="";
if (typeof(Page_ClientValidate) == 'function')
{
if (typeof (Page_ClientValidate) == 'function') { Page_ClientValidate(); }
if (!Page_IsValid)
{
for (i = 0; i < Page_Validators.length; i++) {
var inputControl = document.getElementById(Page_Validators[i].controltovalidate);
if (!Page_Validators[i].isvalid) {
errors = errors + ";" + Page_Validators[i].errormessage;
inputControl.style.border ="solid 2px #FF0000";
}
}
}
return Page_IsValid;
}
return true;
}
$(document).ready(function(){
/*********************************************************************/
///handle form submittion and run validation prior to that
///if a textbox has required field validator, stop form submittion and
/// highlight the text box
/*********************************************************************/
$('#form1').submit(function(){
return ValidateForm();
});