Jquery - check if control is NOT currently being edited - javascript

I have some code that updates controls on my page using Javascript/Ajax/Json calls.
My only problem is that sometimes the control is updated while the user is actively attempting to change the control.
For example - I will be typing in something, and the Ajax call will execute, replacing what I have typed.
Is this a way in javascript/jquery to say:
If $(this).NotBeingCurrentlyEdited ?
I know about the focus option, but how can I say "Not in focus, not being edited currently?"

You can use document.activeElement to check which element has the focus. If the element you want to change has the focus then skip the update. See example snippet below.
var val = 0;
setInterval(() => {
$('input').each((i, el) => {
if (document.activeElement !== el) {
$(el).val(val);
}
});
val++;
}, 2000);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input id="1">
<input id="2">

The way I would approach it is using a timer to determine if the textbox has recently been changed by the user. You could combine this with checking the control's focus as well once an Ajax request is received. You can either disregard updates to that field entirely when TextBoxIsBeingEdited = true or store the updates somewhere to push once the timer ticks.
var TextBoxIsBeingEdited = false;
function TextBoxEdited(){
if(TextBoxIsBeingEdited === false){
document.getElementById("TextBoxStatus").innerText = "Editing";
TextBoxIsBeingEdited = true;
setTimeout(ResetTextBoxEdited, 2000);
}
}
function ResetTextBoxEdited(){
document.getElementById("TextBoxStatus").innerText = "Not Being Edited";
TextBoxIsBeingEdited = false;
}
<input type="text" id="TextBox" oninput="TextBoxEdited()">
<br><br>
<div id="TextBoxStatus">
Not Being Edited
</div>

Related

basic javascript question about disabling buttons

I have a simple piece of javascript embedded into my html form, not a separate file, that is supposed to disable the submit form button until a certain checkbox has been checked but it doesn't seem to be working.
<script>
var disclaimer = document.getElementById("disclaimer");
var submitButton = document.getElementById("submit");
submitButton.disabled = true;
if (disclaimer.checked) {
submitButton.disabled = false;
}
</script>
which I wrote and seems simple and effective but I'm not getting the results I'm looking for. After researching I see results such as
$('#check').click(function(){
if($(this).attr('checked') == false){
$('#btncheck').attr("disabled","disabled");
}
else
$('#btncheck').removeAttr('disabled');
});
Now obviously the variable names and such are named differently but this doesn't even look remotely similar to the javascript code I've provided above and I'm having a hard time getting useful tips from the apparently working code below that does the same thing. Could someone break down the code segment below such that I might be able to fix my code above?
This is the snippet of code with the two HTML id's in question,
<label style='font-size: smaller;'>
<input type='checkbox' name='disclaimer' id='disclaimer' required='required' />
I understand that by submitting this form,
I am transferring any copyright and intellectual property rights to the form's owner,
that I have the right to do so,
and that my submission is not infringing on other people's rights.
</label><br/>
<script>
var disclaimer = document.getElementById("disclaimer");
var submitButton = document.getElementById("submit");
submitButton.disabled = true;
if (disclaimer.checked) {
submitButton.disabled = false;
}
</script>
<div class='vspace'/>
<input type='submit' id='submit' name='came-from-form'/>
Edit: Tons of great answers below that were very informative for letting me know what I'm working with. The issue I'm now facing is implementing these things. In the snippets below this seems very easy to implement but as I try to implement each answer below I'm not seeing any results which clearly means I'm doing something wrong somewhere else in my form. I've attached a larger snippet of the code in question if it helps. Otherwise it might be best to ask a new question.
I believe you trying to find the solution in vanilla JavaScript.
You have to attach the event to the check element like the following way:
var disclaimer = document.getElementById("disclaimer");
document.getElementById("submit").disabled = true;
disclaimer.addEventListener('click', function(){
var submitButton = document.getElementById("submit");
submitButton.disabled = true;
if (this.checked) {
submitButton.disabled = false;
}
});
<form>
<input type="checkbox" id="disclaimer"/>
<button id="submit">Submit</button>
</form>
Update:
In your code, the script is executing before the DOM is fully loaded. Hence you get a error:
Uncaught TypeError: Cannot set property 'disabled' of null
You can either place the script at the end or wrap your code with
DOMContentLoaded
The DOMContentLoaded event is fired when the initial HTML document has been completely loaded and parsed, without waiting for stylesheets, images, and subframes to finish loading. A very different event load should be used only to detect a fully-loaded page. It is an incredibly common mistake to use load where DOMContentLoaded would be much more appropriate, so be cautious.
<label style='font-size: smaller;'>
<input type='checkbox' name='disclaimer' id='disclaimer' required='required' />
I understand that by submitting this form,
I am transferring any copyright and intellectual property rights to the form's owner,
that I have the right to do so,
and that my submission is not infringing on other people's rights.
</label><br/>
<script>
document.addEventListener("DOMContentLoaded", function(event) {
var disclaimer = document.getElementById("disclaimer");
document.getElementById("submit").disabled = true;
disclaimer.addEventListener('click', function(){
var submitButton = document.getElementById("submit");
submitButton.disabled = true;
if (this.checked) {
submitButton.disabled = false;
}
});
});
</script>
<div class='vspace'/>
<input type='submit' id='submit' name='came-from-form'/>
Quick Explantion
Here's a quick explanation of the code, which is heavily reliant on the JavaScript library, jQuery:
// click() is called every time the element `id="check"` is clicked
$('#check').click(function(){
// if element with `id="check"` has an attribute called *checked* set to false or it is null, then perform the if-block, otherwise perform the else-block
if($(this).attr('checked') == false){
// set disabled attribute of element with `id="btncheck"` to value of `disabled`
$('#btncheck').attr("disabled","disabled");
}
else
// remove disabled attribute of element with `id="btncheck"`
$('#btncheck').removeAttr('disabled');
});
anything in $() is selecting the element in the DOM, primarily using CSS-like selectors
.attr() is a method that gets/sets the element HTML attribute
.removeAttr() is a method that removes the HTML attribute
Vanilla JS
What you want to accomplish can be done with vanilla JS.
const disclaimer = document.querySelector("#disclaimer");
const submit = document.querySelector("#submit");
submit.disabled = true; // default setting
const clickHandler = (event) => submit.disabled = !event.target.checked;
disclaimer.addEventListener('click', clickHandler ); // attach event
<form>
<input type="checkbox" id="disclaimer"/>
<button id="submit">Submit</button>
</form>
Hope this will work for you
$('#disclaimer').click(function(){
if($(this).attr('checked') == false){
$('#submit').attr("disabled","disabled");
}
else
$('#submit').removeAttr('disabled');
});
Here if condition indicates the action which should be done if the disclaimer is not chcked. Button will be enable if the disclaimer is checked.
If you want jQuery, use prop (is not wrong to use attr too but I prefer prop instead).
For checkbox, use change event instead of click. I'd do like:
$('#check').on("change", function(){
var isChecked = $(this).is(':checked');
$('#btncheck').prop("disabled", !isChecked);
});
The only significant difference between the 2 code samples you posted is that the second one wraps the button disabling in the click event.
First one says : Straight when page is loaded, if the checkbox is checked, enable the button. (hint: happens only once)
Second one says : For each click on the checkbox, if the checkbox is checked, enable the button.
Something like this should work (haven't tested) :
<script>
var disclaimer = document.getElementById("disclaimer");
var submitButton = document.getElementById("submit");
function disableSubmitIfDisclaimerNotAccepted(){
submitButton.disabled = true;
if (disclaimer.checked) {
submitButton.disabled = false;
}
}
disclaimer.onclick = disableSubmitIfDisclaimerNotAccepted; // everytime the checkbox is clicked
disableSubmitIfDisclaimerNotAccepted(); // on page load
</script>
You must listen to input events in order to make changes when something change, like checking an checkbox.
var disclaimer = document.getElementById("disclaimer");
var submitButton = document.getElementById("submit");
submitButton.disabled = true;
disclaimer.addEventListener('change', function() {
if (this.checked) {
submitButton.disabled = false;
} else {
submitButton.disabled = true;
}
})
More about events: https://developer.mozilla.org/en-US/docs/Web/Events
Submit button disabled by default in HTML :
<input type="checkbox" id="disclaimer">
<label for="disclaimer">Disclaimer</label>
<input type="submit" id="submit" disabled>
Simplest solution using ES6 syntax without JQuery :
let disclaimerCheckbox = document.getElementById('disclaimer'),
submitButton = document.getElementById('submit');
disclaimerCheckbox.onchange = () => submitButton.disabled = !disclaimerCheckbox.checked;
JSFiddle
NOTE : no need to use the DOMContentLoaded event if the script has the defer attribute.

Disabling focused button does not move the focus to the next focusable item

As per title, I have a button that can be hit only 3 times and then it will disable (using jQuery) itself.
test.html
<div class="main">
<input class="one" type="text" />
<button class="two" >If you hit me I will disabling myself...</button>
<button class="three">...and focus should be moved to me!</button>
</div>
test.js
$('.two').on('keyup', function(event) {
$(event.target).attr('disabled', true);
});
Suppose the user is using the keyboard to do so, by hitting the Enter key
Why the focus does not move to the next button when the currently focused one gets disabled?
Here a link to a fiddle showing what I mean: https://jsfiddle.net/8dyk2b2m/
Edit 1
Suppose that:
You don't know what is the next focusable item but you want it to be focused
I have some cases where the next focusable item in not a sibling of the current one (next() does not work)
Edit 2
My DOM is generated on the fly, that's why I cannot manage case by case but I need a more general algorithm. The stranger thing to me still be that the browser does not manage to move the focus when I disable the field currently focused.
Edit 3
In a comment below, the linked solution from this StackOverflow question does not cover all the cases because the disable action prevent the keyup event to be triggered and - on the other side - the keydown event is to earlier, because when the button is hit a new section is created (obviously by another keydown handler somewhere else and no, I cannot modify that handler directly)
Ok, finally I get a good result. I will post here my answer just in case someone would like to do the same or to improve it:
utils.js
function setFocusToClosestTabbableField(target, forward) {
var promise = $timeout(function () {
// Find the focused element in case of the given target is not valid
var $focused = (target instanceof Element || target instanceof jQuery) ? $(target) : $(document.activeElement);
// Check if the element is visible and enabled
var isDisabled = $focused.is(':disabled');
var isHidden = $focused.is(':hidden');
if (isDisabled || isHidden) {
// If the focused element is disabled we have to enable it temporarily in order to find it
// in the list of the tabbable elements
if (isDisabled) {
$focused.attr('disabled', false);
}
// Retrieving now the list of tabbable elements and restore the status of the focused one if needed
var $tabbables = $(':tabbable');
if (isDisabled) {
$focused.attr('disabled', true);
}
// Find the index of the current focused element and retrieve the index of the next on tabbable
// in the list
var focusedIndex = $tabbables.index($focused);
var nextIndex = focusedIndex + ((forward == null || forward == true) ? 1 : -1);
if (nextIndex < 0 || nextIndex > $tabbables.length - 1) {
nextIndex = (forward == null || forward == true) ? 0 : $tabbables.length - 1;
}
// Get the next element focusable and put the focus on it
$focused = $($tabbables.get(nextIndex));
$focused.focus();
// If the field is disable force a keyup event because the browser engine prevents it
if (isDisabled) {
$focused.keyup();
}
}
// Return the focused element
return $focused;
}, 200);
return promise;
}
main.js
// Registering both keydown and keyup since the browser will prevent the second one if the
// focused field becomes disabled in a previously attache handler to the keydown event
$('body').on('keydown keyup', function() {
var key = event.keyCode | -1
var managedKeys = [
-1, // Manually triggered key event
9, // Tab
13, // Enter
32 // Space
];
// I check also Enter and Space since if I hit one of them while the focus is on a button and this
// button will get disabled, then I have to find the next tabbable field and put the focus on it
if (managedKey.indexOf(key) > -1) {
var $target = $(event.target);
setFocusToClosestTabbableField($target, !event.shiftKey);
}
});
NOTES
If someone want to discuss about my solution or want to improve it, please do not hesitate! Cheers!
you have to add focus to next element:
$('.two').on('keyup', function(event) {
$(event.target).attr('disabled', true);
$(event.target).next().focus();
});
.main * {
display: block;
margin: 20px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="main">
<input class="one" type="text" />
<button class="two" >If you hit me I will disabling myself...</button>
<button class="three">...and focus should be moved to me!</button>
</div>
Sorry, I can't comment so answering it.
The fiddle is working for me, may be the browser doesnt know what to execute after the function execution.
If you have the focus injected in the javascript. at the end of the function execution it works.
But why to trigger focus, no answer, why it is not handled by browser.
like
$('.two').on('keyup', function(event) {
$(event.target).attr('disabled', true);
$('.three').focus();
});
You can use click and focus for this.
$('.two').on('click', function(event) {
$(event.target).attr('disabled', true);
$(this).next().focus();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="main">
<input class="one" type="text" />
<button class="two">If you hit me I will disabling myself...</button>
<button class="three">...and focus should be moved to me!</button>
</div>

Jquery on keyup once

How to trigger another alert when I input some text on next time?
For example:
1. put some text
2. alert triggered
3. put some text again
4. alert trigger again
EDIT: I don't want to keep trigger the alert for every time i input, what i trying to do is... lets say I key in "abcd", the function should just trigger once. Then I click everywhere on the screen. Later, I key in "dddd" again in the textbox, the function trigger again for once
EDIT 2: Sry guys, maybe my requirement a bit confusing, i just edit the code and re-explain to illustrate my real case. So, first, i key in "abcd" on textbox, the tooltip should trigger once on first letter of "a". Then i click everywhere of the screen, the tooltip disappear. Next, I key in again "gfffee", the tooltip should appear again on first letter of "g".
<input type="text" id="test">
<input type="button" id="tool">
$('#test').one("keyup", function(){
$('#tool').tooltip("show");
});
$('#tool').tooltip({
placement: "bottom",
trigger: "focus",
title: "Click here",
});
ANSWER:
Thanks everyone for helping me, I managed solve it based on combination of everyone answer.
count = 0;
$('#test').on("change", function(){
count = 0;
});
$('#test').on("keyup", function(){
if(count == 0)
{
$('#tool').tooltip("show");
count = 1;
}
});
$('#tool').tooltip({
placement: "bottom",
trigger: "focus",
title: "Click here",
});
<input type="text" id="test">
<input type="button" id="tool">
Try this
var triggered = 0; // or false
$('#test').on('input', function() {
if(triggered == 0) {
alert('whatever message here');
triggered++;
}
});
$('#test').on('blur', function() {
// reset the triggered value to 0
triggered = 0;
});
I think there is no deterministic way to figure out when you are done with your input, using just the keyup event. But you can try debounce. I've added underscore.js to use debouce, but feel free to use your own implementation or another library. From the debounce docs of underscore
Useful for implementing behavior that should only happen after the input has stopped arriving
You can play around with the wait time to suit your needs. I've made it 500 ms
$('#test').on("keyup", _.debounce(function() {
alert("test");
}, 500));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
<input type="text" id="test">
An excellent explanation of debounce here
Alternate solution
Another possible solution is to attach a blur handler, which will execute if clicked outside your input
$("#test").on("blur", function(e) {
alert("Test")
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<input type="text" id="test">
Can't you just use the onchange function? From your edit it seems like this would be more appropriate for your use case.
So
$('#test').on("change", function(){
alert("test");
});
on input clear the timer with clearTimeout(userTimer); then start new timer with setTimeout(doneType, maxTimer*1000); the maxTimer is in sec of your choose (2s here) if timeout call the function doneType
var userTimer;
var maxTimer = 2;
//on input, clear the timer and start new timer
$('#test').on('input', function () {
clearTimeout(userTimer);
userTimer = setTimeout(doneType, maxTimer*1000);
});
function doneType() {
alert('keep type?');
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="text" id="test">

How to call a function when input is cleared in AngularJS?

I know Angular has simple syntax to display messages or update css, but what I'm trying to do is actually call a function.
<input ng-model="somefield">
<span ng-show="!somefield.length">Please enter something!</span>
<span ng-show="somefield.length">Good boy!</span>
This is my model vm.tagSearching = '' I can detect when I start typing in the input and see the value update. However once I get to the last letter, and I delete that I don't get an update.
I tried using $scope.watch
$scope.$watch('vm.tagSearching', function() {
alert('hey, var has changed!');
});
However this only fires once as the app initializes, but never again, even while typing.
Markup
<input class="tag-search-input"
type="text"
placeholder="Search Tags"
ng-model="tgs.tagSearching"
typeahead="t for t in tgs.fuzzyTagSearch($viewValue)">
Controller
function fuzzyTagSearch(word) {
console.log('fuzzyTagSearch',word);
if (word.length > 2) {
ApiFactory.getSearchResults(word).then(function(data) {
console.log('data',data.data.ticker_tags);
vm.terms = data.data.ticker_tags;
});
}
}
How would you accomplish this? I need to detect when the input is clear when the user backspaces / deletes all the letters so that I can reset the table.
You can simply set up an ng-change directive.
<input ng-model="tgs.tagSearching" ng-change="tgs.detectEmpty()">
vm.detectEmpty = function() {
if (vm.tagSearching.trim().length === 0) {
// it's empty
}
}

Proper handling of input change event

It may be a correct behavior of change event, but the below behavior is bit annoying. When the value is updated from the field history (see explanation below), the event is not triggered.
Please see example code below. the result input field is updated with the change in input field 'input1'. The form and submit button is not fully relevant, but needed to submit a form to make the browser keep the history of field values.
To test:
enter any input in the field (say ABC)
Submit the form
enter first character of input from 1 (A)
use the down arrow to select the previous value + Enter
or use the mouse to select the previous value from the history
No input change is detected.
Which event/ how should this code should modify so that an event is generated whenever the input value is changed.
thanks.
<html>
<head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
</head>
<body>
Result:<input type="text" id="result" readonly></input>
<form method="post" action="">
<input type="text" id="input1" />
<button type=submit>Submit</button>
</form>
<script >
$(document).ready(function() {
$('#input1').change(
function(){
$('#result').val($('#input1').val());
});
});
</script>
</body>
</html>
I think this has nothing to do with jQuery.
A change event should be dispatched when the content of a control has changed and the control loses focus. In practice, the implementation of the change event is inconsistent in browsers, e.g. Firefox dispatches a change event when radio buttons are clicked on rather then when they lose focus. Also in IE, selecting a value from a list of previous values then causing a blur event doesn't fire a change event.
Note that for form controls to be successful, they must have a name attribute with a value. A simple test case is:
<form action="#">
<input type="text" name="input1" onchange="alert('changed');">
<input type="submit">
</form>
One solution is to use the blur event instead and compare the control's current value to its defaultValue - if they're different, perform whatever it is you were going to do for the change event. If the value may be changed a number of times, after the first time you need to compare with the last value onblur rather than the defaultValue.
Anyhow, here's a function that can be called onblur to see if a text input has changed. It needs a bit of work if you want to use it with other types of form control, but I don't think that's necessary.
<form action="#">
<input type="text" name="input1" onblur="
var changed = checkChanged(this);
if (changed[0]) {
alert('changed to: ' + changed[1]);
}
">
<input type="submit">
</form>
<script type="text/javascript">
// For text inputs only
var checkChanged = (function() {
var dataStore = [];
return function (el) {
var value = el.value,
oValue;
for (var i=0, iLen=dataStore.length; i<iLen; i+=2) {
// If element is in dataStore, compare current value to
// previous value
if (dataStore[i] == el) {
oValue = dataStore[++i];
// If value has changed...
if (value !== oValue) {
dataStore[i] = value;
return [true, value];
// Otherwise, return false
} else {
return [false, value];
}
}
}
// Otherwise, compare value to defaultValue and
// add it to dataStore
dataStore.push(el, value);
return [(el.defaultValue != value), value];
}
}());
</script>
Try the keyup event:
$(document).ready(function() {
$('#input1').keyup(
function(){
$('#result').val($('#input1').val());
});
});
http://jsfiddle.net/kaptZ/7/
It seems like it's definitely a browser bug. Not much you can do besides implement your own change handler with focus and blur. This example is not very reusable, but it solved the problem and can be used as inspiration for something reusable.
http://jsfiddle.net/kaptZ/9/
var startValue;
var input1 = $('#input1');
input1.focus(function(){
startValue = this.value;
});
input1.blur(function(){
if (this.value != startValue) {
$('#result').val(this.value);
}
});
A dirty alternative is to use autocomplete="off"
It looks like this bug which was supposed to be fixed in November 2009.
In modern browsers you can use the input event and update as you type. It can be bound either to the text input:
$('#input1').bind('input', function(){
$('#result').val($('#input1').val());
});
Or to the form:
$('#input1').closest('form').bind('input', function(){
$('#result').val($('#input1').val());
});

Categories

Resources