I have some simple javascript which uses knockout that is intended to work as follows:
user can add comment, bringing up a textarea. Upon pressing enter, their comment is posted. They have a button to allow them to cancel the post and bring them back to add comment screen.
The problem is, when the user selects cancel (the <a> element below) while there is text in the textarea, my click event handler for the cancel is not called... until the second time it's clicked. However it will effectively cancel the post if the user has not typed anything yet in the textarea.
HTML:
<a data-bind="attr:{id: $context.cellContext.status.rowIndex}, click: $parent.toggleCommentSelection" class="fa fa-plus" style="float: right"/>
<textarea data-bind="attr:{id: 'commentField' + $context.cellContext.status.rowIndex}, event: { keyup: $parent.checkEntered, }" class="comment-text-area" />
Javascript:
self.toggleCommentSelection = function (data, event) {
var targetId = event.currentTarget.id;
self.currentRow(targetId);
//stuff that gets called on cancel button click
//if there is text in the text area this will not get called until
//clicked twice
};
self.checkEntered = function (data, event) {
//stuff that gets called on keyup
//enter key was pressed
if (event.keyCode === 13) {
var comment = $.trim($('#commentField' +
self.currentRow()).val());
if (comment.length > 0) {
postComment(comment);
}
}
};
Any ideas on why my click binded function toggleCommentSelectionis only called the second time it is clicked if there is text in the textarea?
Related
I'm having trouble with my "showPassword" function. I have my code setup so that when a user hits the enter key (releases the enter key technically), it'll trigger the login submit button function. However, I also notice it triggers the showPassword function too, and I can't figure out why. I'm fairly new to javascript, so any help is appreciated!
Is this because in the HTML portion, the password button comes before the submit button?
Here is my code so far:
//Javascript event listeners:
document.addEventListener("DOMContentLoaded", function() {
loginButton.addEventListener("click", loginButtonClick);
newTransactionButton.addEventListener("click", newTransactionButtonClick);
displayPassword.addEventListener("click", displayPasswordClick);
newTransaction.addEventListener("click", newTransactionSubmitButtonClick);
next.addEventListener("click", nextPage);
prev.addEventListener("click", prevPage);
//if user wants to hit the enter key while on the username input field to submit:
var loginButtonEnter = document.getElementById("loginEmail");
loginButtonEnter.addEventListener("keyup", function(event) {
if (event.keyCode === 13) // Number 13 is the "Enter" key on the keyboard
{
document.getElementById("loginButton").click();
}
});
//if user wants to hit the enter key while on the password input field to submit:
var loginButtonEnter = document.getElementById("loginPassword");
loginButtonEnter.addEventListener("keyup", function(event) {
if (event.keyCode === 13) // Number 13 is the "Enter" key on the keyboard
{
document.getElementById("loginButton").click();
}
});
});
// Show password function:
//dispalys the password as text or hidden password (switches between)
function displayPasswordClick() {
var userPassword = document.getElementById("loginPassword");
const type = userPassword.getAttribute('type') === 'password' ? 'text' : 'password';
userPassword.setAttribute('type', type);
event.preventDefault();
}
<br>
<span class="loginBodyText">Password:</span>
<input type="password" id="loginPassword" placeholder="password"></input>
<div><b class="errorText" id="addErrorPartnerUserSecret"></b></div>
<br>
<!-- button to toggle password visibility -->
<button id="loginPasswordDisplay">Show Password</button>
<button id="loginButton">Submit</button>
Change
<button id="loginPasswordDisplay">Show Password</button>
to
<button type="button" id="loginPasswordDisplay">Show Password</button>
The default type for button elements is submit. Enter inside a form triggers the first submit button in that form, and you don't need any keyboard listeners for this behaviour.
Currently that is your Show Password button, thus Enter additionally activates any click listeners on that as well.
type
The default behavior of the button. Possible values are:
submit: The button submits the form data to the server. This is the default if the attribute is not specified for buttons associated with a <form>, or if the attribute is an empty or invalid value.
reset: The button resets all the controls to their initial values, like <input type="reset">. (This behavior tends to annoy users.)
button: The button has no default behavior, and does nothing when pressed by default. It can have client-side scripts listen to the element's events, which are triggered when the events occur.
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#attr-type
Is there any way to detect if user has changed from the content of one section to another in the same page?
I have a page with multiple buttons (1 form/section is opened once you click on each button), when they all are closed i can detect user is changing to another form using a click event on the button element.
My sections in this case are forms loaded when you click on every button in the page. pure jquery to load the content via ajax inside them.
The problem is when all sections are open. I need to detect when user has changed between the content of one section to another.
I have to warn the user about saving your changes in a previous form because system has a timeout for inactivity, if user didnt save his data, it is lost once user gets logout from application.
the event prompt the user to save the data of the previous form.
The only way I can think of doing this is using a mouse event, but this can sometimes be a frustrating experience.
Solved
Thanks DelightedD0D, I ended up doing this
This var saves the previous form number
var pendingForm = [];
Events which fire a possible warning
//Pressing tab is reviewed if there are unsaved changes in the previous section.
$(document).keyup(function(eventTab) {
var code = eventTab.keyCode || eventTab.which;
if (code === 9) {
checkPrevious(eventTab);
}
});
//Clicking is reviewed if there are unsaved changes in the previous section
$(document).mouseup(function(eventMouse) {
checkPrevious(eventMouse);
});
Here we establish when a form is pending or has changed
$('.formSection').on('keyup change', 'input, select, textarea', function() {
$(this).closest('.formSection').addClass('pending');
//We get the number of the form by the id
var numForm = $(this).closest('.formSection').attr('id').substr(11, 2);
if ( $.inArray(numForm , pendingForm) == -1 ) {
pendingForm.push(numForm);
}
});
//I have my own functions to save and cancel, but the idea is Save the data
//then find the formSection from previous form, remove pending class and
//remove number form from array of pending sections
$('.save').click(function() {
//save data...
var numForm = pendingForm.pop();
$('#formSection'+numForm).removeClass('pending');
});
And this function checks when user move to another form
function checkPrevious(e) {
var $target = $(e.target);
//If it is clicked somewhere within a form or a button that opens a section
if ($target.closest('.formSection').length || $target.hasClass('btnSection')) {
var isDisabled = false;
if (pendingForm.length > 0) {
prevForm = pendingForm.slice(-1).pop();
//Every submit form button has an id with a consecutive number in my case
//If disabled, that means it has errors in validation (Bootstrap)
//**I have to improve this verification yet**
isDisabled = $('#submitForm' + prevForm).is(':disabled');
}
// get any forms with changes that are not the current form or do not contain the clicked element
var $otherFormsWithChanges = $('.pending').filter(function() {
var $this = $(this);
return $this.hasClass('pending') && (!$this.is($target) || $this.has($target).length != 0);
});
// if another form has a change, thow up a message
// allow the user to go back to the form or ignore the changes
if ($otherFormsWithChanges.length > 0 && $otherFormsWithChanges.has($target).length === 0 ) {
var modalPrev = $('#modalPrev');
if ( isDisabled == false ) {
//If everything is ok, we can save
modalPrev.find('.modal-content .modal-body').html("<p>You have unsaved changes. Do you want to save previous form?</p>");
modalPrev.find(".btnSave").removeClass('hide');
} else {
modalPrev.find('.modal-content .modal-body').html("<p>You have some errors in your previous form.</p>");
modalPrev.find(".btnSave").addClass('hide');
}
$('#modalPrev').modal('show');
}
}
}
I show a modal instead of an alert with two buttons [Save] and [Cancel], every one has a function which do a save or close but both remove the previous section from the array to not be considered anymore.
You could do this by setting a class on the form when input values change then listening for clicks on the document and checking if a form other than the one being interacted with has changes. If one does, present a message to the user.
This should work:
Note that you dont have to use forms, just add the track-changes class to some parent of the inputs you have grouped together
jsFiddle example
$(document).mouseup(function(e) {
var $target = $(e.target);
// get any forms with changes that are not the current form or do not contain the clicked element
var $otherFormsWithChanges = $('.pending').filter(function() {
var $this=$(this);
return $this.hasClass('pending') && (!$this.is($target) || $this.has($target).length !=0);
});
// if another form has a change, thow up a message
// allow the user to go back to the form or ignore the changes
if ($otherFormsWithChanges.length > 0 && $otherFormsWithChanges.has($target).length===0 ) {
var c = confirm("You have unsaved changes.\n\n Click cancel to go back to the unsaved form or OK to ignore");
c ? $otherFormsWithChanges.removeClass('pending') : $otherFormsWithChanges.find('input, select, textarea').focus();
}
});
$('.track-changes').on('keyup change', 'input, select, textarea', function() {
$(this).closest('.track-changes').addClass('pending');
});
$('.save').click(function() {
// save data...
$(this).closest('.track-changes').removeClass('pending');
});
form{
padding:10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h4>form 1</h4>
<form class="track-changes" has-changes="false" action="">
<input type="text">
some text
<br>
<button type="button" class="save">Save</button>
</form>
<h4>form 2</h4>
<form class="track-changes" has-changes="false" action="">
<input type="text">
some text
<br>
<button type="button" class="save">Save</button>
</form>
<h4>form 3</h4>
<form class="track-changes" has-changes="false" action="">
<input type="text">
some text
<br>
<button type="button" class="save">Save</button>
</form>
I am trying to prioritize click event in case two events click and change are fired.
I have a global function similar to "ValidateOnChange" and "ValidateOnClick" to validate input of text box on change and on click event.
Enter some text, it shows up error message. Then try to input correct value and click the Submit button, the error vanishes and this makes user to click the button twice. Here I am trying to fix this double click.
Here is mock up code:
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
</head>
<body>
<div>Enter any string:</div>
<div><input type="text" id="txtInput" ></input></div>
<div id="divError" style="color: red; display: none;">Please enter 0</div>
<input type="button" value="Submit" id="btnSubmit" ></input>
<script type="text/javascript">
var mouseevent_var = null;
function ValidateOnChange(e) {
var input = $('#txtInput').val();
if (input == '0') {
$('#divError').hide();
} else {
$('#divError').show();
}
}
function ValidateOnClick(e){
alert("Hurray!!! You got it right!");
}
$('#txtInput').mousedown(function (e) {
mouseevent_var = e;
});
jQuery(document).ready(function(){
$('#btnSubmit').click(function(e){
ValidateOnClick(e);
});
$('#txtInput').change(function(e){
ValidateOnChange(e);
});
//User don't want error when they are typing in.
//$('#txtInput').keyup(function() {
//$('#txtInput').trigger("change");
//});
});
</script>
</body>
</html>
The keyup event seemed to be solution but users don't want the error to popup when they are typing in.
Is there any way to list all the triggered events so that I could filter "mousedown" and "mouseup" events for submit button? Or is there any alternative way to prioritize click event ?
There can be many alternatives depending on the situations. I have made few minor changes to avoid the double click issue (comments amended). Basically we need to bind the mousedown event on the button object. There we will set a temporary flag variable to true. In the same time if input's change event gets fired then you can skip the checking if the temporary flag variable is true. Reason behind the double click for triggering the button's click event is better explained here: How to get jQuery click event after append in change event handler
Your updated js code below:
var mouseevent_var = false;
function ValidateOnChange(e) {
// Skip validation if the change event is fired due to user's click on submit button
if(mouseevent_var){ return false; }
var input = $('#txtInput').val();
if (input == 0) {
$('#divError').hide();
} else {
$('#divError').show();
}
}
function ValidateOnClick(e){
mouseevent_var = false; // Reset mouseevent_var to false
alert("Hurray!!! You got it right!");
}
$('#btnSubmit').mousedown(function (e) {
mouseevent_var = true;
});
jQuery(document).ready(function(){
$('#btnSubmit').click(function(e){
ValidateOnClick(e);
});
$('#txtInput').change(function(e){
ValidateOnChange(e);
});
//User don't want error when they are typing in.
//$('#txtInput').keyup(function() {
//$('#txtInput').trigger("change");
//});
});
The above code is just a fix as per your need. But there are other better alternatives too. Ideally you should not have two different validation functions for validating same fields on different events. You must think of managing it with a single function.
I have code similar to this:
<div id="div1" onclick="myfunc()">
<span class="myspan"></span>
</div>
Now, if a user clicks on a button elsewhere on the page, an input box is dynamically added to the span. The button also gives the input box focus.
The input box has code like this:
<input type=text onkeypress="runthis()" onblur="runthis()">
The problem is, if I try to select text in the input box, the parent onclick and onblur fire. I want to edit the input box until I click away (or hit enter).
This is basically a quick edit box. A user clicks an edit button, the input box appears. They click out or hit enter and it saves.
Edit (actual code):
<div class="plBoxContainer">
<a href="playlists" onClick="playlists(id); return false;" onMouseOver="if(RUNPLAYLIST){this.getElementsByTagName('span')[0].style.textDecoration='underline'}" onMouseOut="this.getElementsByTagName('span')[0].style.textDecoration='none'">
<br><span class="folderName">Some Name</span>
<span class="plEdit" onClick="PlEditBox(this.previousSibling); document.getElementById('dummydiv').innerHTML=id;"> </span>
Some text</a>
</div>
JS:
function PlEditBox(folderName){
RUNPLAYLIST = 0;
name = folderName.innerHTML;
folderName.innerHTML = '<input type=text id="folderNameChange" value="'+name+'" onkeypress="return PlDoEdit(this.value, document.getElementById(\'dummydiv\').innerHTML, event);" onBlur="PlDoEdit(this.value, document.getElementById(\'dummydiv\').innerHTML, \'blur\')">';
document.getElementById('folderNameChange').focus();
document.getElementById('folderNameChange').select();
}
function PlDoEdit(value, id, e)
{
var keycode;
if (window.event) keycode = window.event.keyCode;
else if (e && e != blur) keycode = e.which;
else keycode = '';
if (keycode == 13 || e == 'blur')
{
RUNPLAYLIST = 1;
//do some unrelated stuff here
return false;
}
else return true;
}
function playlists(plID)
{
if(RUNPLAYLIST==0)
{
RUNPLAYLIST = 1;
return false;
}
//do a bunch of unrelated stuff here
}
I think you should use event.returnValue = false/event.preventDefault in your function to prevent event bubling. Like
event.preventDefault ? event.preventDefault() : event.returnValue = false;
For more see http://mootools.net/docs/core/Types/DOMEvent#Event:stop
JS Fiddle isn't allowing saving/sharing at the moment as they are migrating their servers. In the mean time, there's a screenshot at the bottom of this post that might help.
It looks like you're using pure Javascript, but I used YUI to abstract away the even normalization; nobody should be bothered with that! :)
Basically the event handler for the DIV element won't actually do anything unless the DIV is the true even target (i.e. the DIV was clicked directly rather than the INPUT within).
(Right-click > View Image in Firefox to see full size.)
Update
I made another JS Fiddle that displays a name, turns it into an edit box if you click on it, and saves the value (returning to simple display) when the INPUT loses focus or when ENTER key is pressed.
(Right-click > View Image in Firefox to see full size.)
I am trying to update a div on click similar to orkut .. The div is updating fine. But when the user clicks on the textbox its value becomes null initially. So the user has to again type the whole thing. So what I need is a facililty for the user to add the text with the existing one. So when he clicks on the textbox, the existing value of textbox would remain there and allows user to append new text. Please find the code below for that..
$(document).ready(function () {
$('.photo_title').click(
function(e){
var text = $(this).text();
$(this).val('');
$('<input type="text" value="sdfsdfsdfsdf" />').appendTo($(this)).val(text).select().blur(
function(){
var newText = $(this).val();
if(newText==""){newText="enter text "}
$(this).parent().text(newText),find("form input:text" ).remove();
});
});
});
HTML
<div class="photo_title">My text goes here and type here to add more</div>
You should place something like the following at the top of your click handler
if (e.target != this) return;
Otherwise, the handler will be triggered when the user clicks in the text box as well since the event will bubble up. So your code will end up looking like:
$(document).ready(function () {
$('.photo_title').click(
function(e){
if (e.target != this) return;
...
}
);
});