jQuery and textarea change events - javascript

i just met a strange behavior jQuery and can't figure out any more or less slight solution.
Say, i have textarea and button. I want to disable button if textarea is empty.
For this i have a handler which does this job.
Here is the code:
// textarea control
var $textarea = $('#myTextarea');
var $button = $('#myButton');
$textarea.on('input propertychange', function() {
if($textarea.val().length > 0) {
$button.removeClass('disabled').removeAttr('disabled');
} else {
$button.addClass('disabled').attr('disabled', 'disabled');
}
});
$button.on('click', function() {
if ($button.attr("disabled") != null) {
console.log('Disabled!');
return false;
} else {
// do some stuff and eventually erase textarea
$textarea.val('');
}
});
My trouble is when i erase textarea (the end of the code) it doesn't disable the button. Any ideas would be appreciated (actually it's slight adaptation of my code but the situation reflected pretty good, hope it would be clear for you, thanks!)
UPD
Nothing found on stackoverflow doesn't help.
UPD2
As i said in the begin, i was looking not for workaround like force trigger event, i thought it's possible to catch any event fired by $textarea.val(); Sure #Madbreaks and #epascarello 's solutions work pretty good, thanks guys.

Maybe just add this:
else {
// do some stuff and eventually erase textarea
$textarea.val('');
// notify
$textarea.trigger('propertychange');
}

problem is setting values with JavaScript does not normally trigger the events, but you can do it yourself.
$textarea.val('').trigger("input");

Make sure you trim the value of your textarea and you dont have an white spaces when you get the length of the .val(). Also in case you use a text editor like ckEditor make sure you read their documentation on how to retrieve the text being written.

Recommend using this jQueryTextChange lib. Its a cross browser consistent one. The usages are clearly elaborated on the home page. http://zurb.com/playground/jquery-text-change-custom-event

Related

Why isn't my Javascript working?

I am new to coding and I need to use Javascript in my code. I have a checkbox within an HTML table (below).
<td><input type="checkbox" id="check1"/>
<label th:text="${item.contents}"> </label>
</td>
I am trying to use Javascript to alert me when I have checked the box with the code below.
<script>
$('#check1').click(function() {
if($(this).not(':checked'))
alert('unchecked');
else
alert('checked');
});
</script>
Why isn't it working? I don't get an error, but nothing happens either.
Thank you.
Ok, first, you have some syntax that is not HTML here:
<label **th:text="${item.contents}"**>
And, if that non-HTML code is incorrect, that could be enough for the page to stop processing. You say you don't get an error, but do you mean that you've checked your developer tools console window and don't see an error there?
As for the checkbox, neither the table cell, nor the label are related to your goal.
Next, JQuery is a great thing, but it sometimes makes things that are already easy, harder. Your code is actually EXCLUDING any checked elements from the wrapped set that will be examined because you are using not().
Here is a solution that doesn't rely on JQuery:
var chk = document.getElementById("check1");
chk.addEventListener("click", function(){
// The following is not part of your question, but is
// added just for completeness:
// Because the alert() is modal, it will block the UI
// from updating and it will most likely appear before
// the UI updates the checkbox to the latest appearance.
// To solve this, we add a short delay before making the
// alert using a timer and we need to store the checked
// status of the checkbox outside of the timer's callback
// function.
var on = this.checked;
setTimeout(function(){
var message = "checked";
if(!on){
message = "un" + message;
}
alert(message);
}, 50);
});
<input type="checkbox" id="check1">
I don't think it's normally very wise to listen to click events on things like checkboxes and radio buttons. From what I understand they may be triggered before the value of the input is updated, depending on where you catch the event in the dom.
I'm not sure what the html syntax is on your label, the th:text part, but it seems to be some sort of templating syntax and also may be unrelated. To help simplify the problem also I will give you an example without using jQuery, jQuery often adds unnecessary complexity to simple problems.
A properly working example of your code using vanilla javascript (without jquery) would be,
document.getElementById("check1").addEventListener('change', function(e) {
var checked = this.checked;
if(checked) { alert("Checked"); }
else { alert("Unchecked"); }
});
And with jquery, a working example is:
$("#check1").on("change", function(e) {
var checked = this.checked;
if(checked) { alert("Checked"); }
else { alert("Unchecked"); }
});

How can I test this JavaScript effectively?

I've written a piece of code which acts on the event that a user highlights some text on a page. The code works fine (below) but my issue is how to test it effectively? Is there a way of mocking a user selecting text (specifically involving a mouseup event).
Maybe the issue is that checking if text is selected when a mouseup event occurs is not the best way to do this? Any insight is appreciated.
var note = {
mouseHandler : function(e){
selection = window.getSelection();
if (selection.toString() !== '') {
note.selection = selection;
note.setAttributes();
note.hideOverlay();
note.placeOverlay();
}
}
}
Ideally I'd like to be able to trigger this with test code so I can ensure note.placeOverlay() happens
So in Jasmine you would spy on window.getSelection and return a string in one case and none in the other. Then you would check that this what should happen in note.placeOver happens.
spyOn(window, 'getSelection').andReturn('someString')
note.mouseHandler();
//test what you expect here
spyOn(window, 'getSelection').andReturn('')
note.mouseHandler();
//test that nothings happens here
Maybe you can show what note.placeOver does, so I can complete the answer.

How to deslect highlighted text in textbox if already highlighted?

So I have this very simple JS function that selects all the text in the ASP.NET texbox (input):
function selectAllText(textbox) {
textbox.focus();
textbox.select();
}
..and it gets called like this on the click event:
$("#<%=Textbox1.ClientID %>").click(function () { selectAllText(jQuery(this)) });
The problem is no matter how many times a user clicks in the text box all of the text is always selected. I understand why this is occuring (based on the way my code above is), but it doesn't work well when the user tries to click in the middle of a word to get the cursor back to make a modification to the text.
How do I modify this JS to tell if the text is already highlighted and then deselect the text? This was on subsiquient click, the user can get the single cursor on a precise clicked location to make a modification.
I am trying to get the documentation on the .select() method to see if I could do if(!textbox.select()), but I am having a hard time finding it, so post any doc links as well if you have them.
EDIT: This problem and need for a workaround seems to be for IE (I am using IE9). In Chrome the behavior by default is what I need, but this is for an intranet application that runs on IE, so it appears I need an explicit workaround.
Thanks!
Is it necessary to do the .focus() in this function? You could instead attach a simple .select(); to the onfocus event (.bind('focus', function(){..})): http://jsfiddle.net/EGHzj/
Try this
$(document).ready(function(){
$('input').bind('click',function(){
if($(this).hasClass('selected')){
$(this).toggleClass('selected');
}else{
this.focus();
this.select();
$(this).toggleClass('selected');
}
});
});
This should work in IE also,
http://jsfiddle.net/rAqgw/7/
function selectAllText(textbox) {
// if there isn't selected text.
if (textbox[0].selectionEnd) {
textbox.focus();
textbox.select();
}
}
$('#txt').click(function() {
selectAllText($(this));
});
Live DEMO
​

Any event triggered on autocomplete?

I have a pretty simple form. When the user types in an input field, I want to update what they've typed somewhere else on the page. This all works fine. I've bound the update to the keyup, change and click events.
The only problem is if you select an input from the browser's autocomplete box, it does not update. Is there any event that triggers when you select from autocomplete (it's apparently neither change nor click). Note that if you select from the autocomplete box and the blur the input field, the update will be triggered. I would like for it to be triggered as soon as the autocomplete .
See: http://jsfiddle.net/pYKKp/ (hopefully you have filled out a lot of forms in the past with an input named "email").
HTML:
<input name="email" />
<div id="whatever"><whatever></div>
CSS:
div {
float: right;
}
Script:
$("input").on('keyup change click', function () {
var v = $(this).val();
if (v) {
$("#whatever").text(v);
}
else {
$("#whatever").text('<whatever>');
}
});
I recommending using monitorEvents. It's a function provide by the javascript console in both web inspector and firebug that prints out all events that are generated by an element. Here's an example of how you'd use it:
monitorEvents($("input")[0]);
In your case, both Firefox and Opera generate an input event when the user selects an item from the autocomplete drop down. In IE7-8 a change event is produced after the user changes focus. The latest Chrome does generate a similar event.
A detailed browser compatibility chart can be found here:
https://developer.mozilla.org/en-US/docs/Web/Events/input
Here is an awesome solution.
$('html').bind('input', function() {
alert('test');
});
I tested with Chrome and Firefox and it will also work for other browsers.
I have tried a lot of events with many elements but only this is triggered when you select from autocomplete.
Hope it will save some one's time.
Add "blur". works in all browsers!
$("input").on('blur keyup change click', function () {
As Xavi explained, there's no a solution 100% cross-browser for that, so I created a trick on my own for that (5 steps to go on):
1. I need a couple of new arrays:
window.timeouts = new Array();
window.memo_values = new Array();
2. on focus on the input text I want to trigger (in your case "email", in my example "name") I set an Interval, for example using jQuery (not needed thought):
jQuery('#name').focus(function ()
{
var id = jQuery(this).attr('id');
window.timeouts[id] = setInterval('onChangeValue.call(document.getElementById("'+ id +'"), doSomething)', 500);
});
3. on blur I remove the interval: (always using jQuery not needed thought), and I verify if the value changed
jQuery('#name').blur(function ()
{
var id = jQuery(this).attr('id');
onChangeValue.call(document.getElementById(id), doSomething);
clearInterval(window.timeouts[id]);
delete window.timeouts[id];
});
4. Now, the main function which check changes is the following
function onChangeValue(callback)
{
if (window.memo_values[this.id] != this.value)
{
window.memo_values[this.id] = this.value;
if (callback instanceof Function)
{
callback.call(this);
}
else
{
eval( callback );
}
}
}
Important note: you can use "this" inside the above function, referring to your triggered input HTML element. An id must be specified in order to that function to work, and you can pass a function, or a function name or a string of command as a callback.
5. Finally you can do something when the input value is changed, even when a value is selected from a autocomplete dropdown list
function doSomething()
{
alert('got you! '+this.value);
}
Important note: again you use "this" inside the above function referring to the your triggered input HTML element.
WORKING FIDDLE!!!
I know it sounds complicated, but it isn't.
I prepared a working fiddle for you, the input to change is named "name" so if you ever entered your name in an online form you might have an autocomplete dropdown list of your browser to test.
Detecting autocomplete on form input with jQuery OR JAVASCRIPT
Using: Event input. To select (input or textarea) value suggestions
FOR EXAMPLE FOR JQUERY:
$(input).on('input', function() {
alert("Number selected ");
});
FOR EXAMPLE FOR JAVASCRIPT:
<input type="text" onInput="affiche(document.getElementById('something').text)" name="Somthing" />
This start ajax query ...
The only sure way is to use an interval.
Luca's answer is too complicated for me, so I created my own short version which hopefully will help someone (maybe even me from the future):
$input.on( 'focus', function(){
var intervalDuration = 1000, // ms
interval = setInterval( function(){
// do your tests here
// ..................
// when element loses focus, we stop checking:
if( ! $input.is( ':focus' ) ) clearInterval( interval );
}, intervalDuration );
} );
Tested on Chrome, Mozilla and even IE.
I've realised via monitorEvents that at least in Chrome the keyup event is fired before the autocomplete input event. On a normal keyboard input the sequence is keydown input keyup, so after the input.
What i did is then:
let myFun = ()=>{ ..do Something };
input.addEventListener('change', myFun );
//fallback in case change is not fired on autocomplete
let _k = null;
input.addEventListener( 'keydown', (e)=>_k=e.type );
input.addEventListener( 'keyup', (e)=>_k=e.type );
input.addEventListener( 'input', (e)=>{ if(_k === 'keyup') myFun();})
Needs to be checked with other browser, but that might be a way without intervals.
I don't think you need an event for this: this happens only once, and there is no good browser-wide support for this, as shown by #xavi 's answer.
Just add a function after loading the body that checks the fields once for any changes in the default value, or if it's just a matter of copying a certain value to another place, just copy it to make sure it is initialized properly.

Detect all changes to a <input type="text"> (immediately) using JQuery

There are many ways the value of a <input type="text"> can change, including:
keypresses
copy/paste
modified with JavaScript
auto-completed by browser or a toolbar
I want my JavaScript function to be called (with the current input value) any time it changes. And I want it to be called right away, not just when the input loses focus.
I'm looking for the cleanest and most robust way to do this across all browsers (using jQuery preferably).
This jQuery code uses .bind() to catch immediate changes to any element, and should work across all browsers:
$('.myElements').each(function() {
var elem = $(this);
// Save current value of element
elem.data('oldVal', elem.val());
// Look for changes in the value
elem.bind("propertychange change click keyup input paste", function(event){
// If value has changed...
if (elem.data('oldVal') != elem.val()) {
// Updated stored value
elem.data('oldVal', elem.val());
// Do action
....
}
});
});
However, note that .bind() was deprecated in jQuery version 3.0. Anyone using jQuery version 1.7 or newer should use .on() instead.
A real-time solution for jQuery >= 1.7 is on
$("#input-id").on("change keyup paste", function(){
dosomething();
})
if you also want to detect "click" event, just:
$("#input-id").on("change keyup paste click", function(){
dosomething();
})
if you're using jQuery <= 1.6, just use bind or live instead of on.
Unfortunately, I think setInterval wins the prize:
<input type=text id=input_id />
<script>
setInterval(function() { ObserveInputValue($('#input_id').val()); }, 100);
</script>
It's the cleanest solution, at only 1 line of code. It's also the most robust, since you don't have to worry about all the different events/ways an input can get a value.
The downsides of using 'setInterval' don't seem to apply in this case:
The 100ms latency? For many applications, 100ms is fast enough.
Added load on the browser? In general, adding lots of heavy-weight setIntervals on your page is bad. But in this particular case, the added page load is undetectable.
It doesn't scale to many inputs? Most pages don't have more than a handful of inputs, which you can sniff all in the same setInterval.
Binding to the input event seems to work fine in most sane browsers. IE9 supports it too, but the implementation is buggy (the event is not fired when deleting characters).
With jQuery version 1.7+ the on method is useful to bind to the event like this:
$(".inputElement").on("input", null, null, callbackFunction);
Unfortunately there is no event or set of events that matches your criteria. Keypresses and copy/paste can both be handled with the keyup event. Changes through JS are trickier. If you have control over the code that sets the textbox, your best bet is to modify it to either call your function directly or trigger a user event on the textbox:
// Compare the textbox's current and last value. Report a change to the console.
function watchTextbox() {
var txtInput = $('#txtInput');
var lastValue = txtInput.data('lastValue');
var currentValue = txtInput.val();
if (lastValue != currentValue) {
console.log('Value changed from ' + lastValue + ' to ' + currentValue);
txtInput.data('lastValue', currentValue);
}
}
// Record the initial value of the textbox.
$('#txtInput').data('lastValue', $('#txtInput').val());
// Bind to the keypress and user-defined set event.
$('#txtInput').bind('keypress set', null, watchTextbox);
// Example of JS code triggering the user event
$('#btnSetText').click(function (ev) {
$('#txtInput').val('abc def').trigger('set');
});
If you don't have control over that code, you could use setInterval() to 'watch' the textbox for changes:
// Check the textbox every 100 milliseconds. This seems to be pretty responsive.
setInterval(watchTextbox, 100);
This sort of active monitoring won't catch updates 'immediately', but it seems to be fast enough that there is no perceptible lag. As DrLouie pointed out in comments, this solution probably doesn't scale well if you need to watch lots of inputs. You can always adjust the 2nd parameter to setInterval() to check more or less frequently.
Here is a solution that doesn't make use of jQuery (Its really quite obsolete and not necessary these days)
Using the event "input" you can look for any kind of change:
Deleting, Backspacing, Pasting, Typing, anything that will change the inputs value.
The input event is directly related to the text input. ANY time the text is changed in ANY fashion, input is dispatched.
document.querySelector("#testInput").addEventListener("input", test);
function test(e) {
var a = document.getElementById('output');
a.innerText += "Detected an Update!\n";
}
<input id="testInput">
<br>
<a id="output"></a>
Here is a slightly different solution if you didn't fancy any of the other answers:
var field_selectors = ["#a", "#b"];
setInterval(function() {
$.each(field_selectors, function() {
var input = $(this);
var old = input.attr("data-old-value");
var current = input.val();
if (old !== current) {
if (typeof old != 'undefined') {
... your code ...
}
input.attr("data-old-value", current);
}
}
}, 500);
Consider that you cannot rely on click and keyup to capture context menu paste.
Add this code somewhere, this will do the trick.
var originalVal = $.fn.val;
$.fn.val = function(){
var result =originalVal.apply(this,arguments);
if(arguments.length>0)
$(this).change(); // OR with custom event $(this).trigger('value-changed');
return result;
};
Found this solution at val() doesn't trigger change() in jQuery
I have created a sample. May it will work for you.
var typingTimer;
var doneTypingInterval = 10;
var finaldoneTypingInterval = 500;
var oldData = $("p.content").html();
$('#tyingBox').keydown(function () {
clearTimeout(typingTimer);
if ($('#tyingBox').val) {
typingTimer = setTimeout(function () {
$("p.content").html('Typing...');
}, doneTypingInterval);
}
});
$('#tyingBox').keyup(function () {
clearTimeout(typingTimer);
typingTimer = setTimeout(function () {
$("p.content").html(oldData);
}, finaldoneTypingInterval);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<textarea id="tyingBox" tabindex="1" placeholder="Enter Message"></textarea>
<p class="content">Text will be replace here and after Stop typing it will get back</p>
http://jsfiddle.net/utbh575s/
We actually don't need to setup loops for detecting javaScript changes.
We already setting up many event listeners to the element we want to detect. just triggering any un harmful event will make the job.
$("input[name='test-element']").on("propertychange change click keyup input paste blur", function(){
console.log("yeh thats worked!");
});
$("input[name='test-element']").val("test").trigger("blur");
and ofc this is only available if you have the full control on javascript changes on your project.
Although this question was posted 10 years ago, I believe that it still needs some improvements. So here is my solution.
$(document).on('propertychange change click keyup input paste', 'selector', function (e) {
// Do something here
});
The only problem with this solution is, it won't trigger if the value changes from javascript like $('selector').val('some value'). You can fire any event to your selector when you change the value from javascript.
$(selector).val('some value');
// fire event
$(selector).trigger('change');
Or in a single line
$(selector).val('some value').trigger('change');
Well, best way is to cover those three bases you listed by yourself. A simple :onblur, :onkeyup, etc won't work for what you want, so just combine them.
KeyUp should cover the first two, and if Javascript is modifying the input box, well I sure hope it's your own javascript, so just add a callback in the function that modifies it.
Here's a working example that I'm using to implement an autocomplete variation the populates a jqueryui selector (list), but I don't want it to function exactly like the jqueryui autocomplete which does a drop-down menu.
$("#tagFilter").on("change keyup paste", function() {
var filterText = $("#tagFilter").val();
$("#tags").empty();
$.getJSON("http://localhost/cgi-bin/tags.php?term=" + filterText,
function(data) {
var i;
for (i = 0; i < data.length; i++) {
var tag = data[i].value;
$("#tags").append("<li class=\"tag\">" + tag + "</li>");
}
});
});
Can't you just use <span contenteditable="true" spellcheck="false"> element in place of <input type="text">?
<span> (with contenteditable="true" spellcheck="false" as attributes) distincts by <input> mainly because:
It's not styled like an <input>.
It doesn't have a value property, but the text is rendered as innerText and makes part of its inner body.
It's multiline whereas <input> isn't although you set the attribute multiline="true".
To accomplish the appearance you can, of course, style it in CSS, whereas writing the value as innerText you can get for it an event:
Here's a fiddle.
Unfortunately there's something that doesn't actually work in IE and Edge, which I'm unable to find.
you can simply identify all changers in the form, like this
//when form change, show aleart
$("#FormId").change(function () {
aleart('Done some change on form');
});
You can bind the 'input' event to <input type="text">. This will trigger every time the input changes such as copy, paste, keypress, and so on.
$("#input-id").on("input", function(){
// Your action
})

Categories