Why Paste Event in jQuery fires on pre-paste? - javascript

I am trying to make textbox similar to the Twitter, for this I have written code for:
Word Count
Used Events Change, Keyup and Paste
Keyup and Change Events are working fine but paste event is little bit strange, when I paste something in textarea the word count doesn't change at that moment, after some debugging I found that paste event fires up before pasting something on textbox. I don't know how they handle this in Twitter.
Here is my code:
events:
'click #textboxId' : 'submitQuestion'
'keyup #textboxId' : 'wordCounter'
'change #textboxId' : 'wordCounter'
'paste #textboxId' : 'wordCounter'
wordCounter: ->
#Code for Word Count#
Due to pre-paste nature of paste event the work count doesn't changes on that instance.
Your suggestion and help will be appreciated.

See this example.
http://jsfiddle.net/urEhK/1
$('textarea').bind('input propertychange', function() {
$('#output').html($(this).val().length + ' characters');
});
That behavior was very weird. You would think that one of those events would catch this properly? I was surprised there weren't more answers to this via Google.

function update()
{
alert($textbox.val().length);
}
var $textbox = $('input');
$textbox.bind('keyup change cut paste', function(){
update(); //code to count or do something else
});
// And this line is to catch the browser paste event
$textbox.bind('input paste',function(e){ setTimeout( update, 250); });

You should now use on() instead of bind() see this post.
It's also unnecessary to create a named function, you can just create a anonymous function.
$('#pasteElement').on('paste', function() {
setTimeout(function(){
alert($('#pasteElement').val());
}, 100);
});

You can do one thing that firstly get original data . then you can get the event paste data and add them.
$("#id").on("paste keypress ",function(event){
// eg. you want to get last lenght
var length=$("#id").val().length;
if(event.type == "paste"){
//then you can get paste event data.=
length+=event.originalEvent.clipboardData.getData('text').length;
}
});`

Related

jQuery executing both branches of an if-else statement in Rails

I have the following jQuery on a Rails page:
$(document).on('click','.reportsArrow', function() {
if ( $(this).parent().hasClass('reportCollapsed') ) {
console.log("A");
$(this).parent().removeClass('reportCollapsed');
}else{
$(this).parent().addClass('reportCollapsed');
console.log("B");
}
});
When I click on an element with reportsArrow and without reportCollapsed, the log shows
B
A
Meaning it is executing the else part and then executing the if part. I want the function to only be executed once per click, and to only follow one code path. Why is it being executed twice and how do I stop this? I should point out that this toggles correctly in the mockups created by the web designer (on HTML/CSS/JS only). It looks like the problem is Rails related.
EDIT:
We have found a working solution:
$('.reportsArrow').click(function() {
$(this).parent().toggleClass('reportCollapsed');
});
The event would be getting fired more then once and propagated up-ward in the DOM tree. Use event.stopPropagation(). You can also use the toggleClass instead of branching.
$(document).on('click','.commonClass', function(event) {
event.stopPropagation();
$(this).parent().toggleClass('newClass');
});
Not sure why, but my days in unobtrusive javascript have taught me to be as specific and as least fuzzy as I can.
Never worried why, as long as it worked. Having been asked why (just here), my answer is "I will have to look it up". Sorry.
Thus, I would avoid setting a catch method on THE document and then filter actions: I would directly point the event catches on the element (or set of elements) I want to watch.
So, instead of using:
$(document).on('click','.reportsArrow', function() {
//...
});
I would go the direct way:
$('.reportsArrow').click(function () {
//..
});
Having read the API documentation for jQuery .on(), it appears to me that it would be probably more suitable to use .one() instead, so there is no continuation after hit "#1". But I have not tested it, so I can't say for sure.
You need to stop event propogation to child elements.also you can use toggleClass instead:
$(document).on('click','.commonClass', function(e) {
e.stopPropagation();
$(this).parent().toggleClass('newClass')
});
Try this,
You need to avoid event bubbling up the DOM tree. There must be a parent causing the event to fire twice or more time.
To avoid this use event.stopPropagation()
$(document).on('click','.commonClass', function(event) {
event.stopPropagation();
$(this).parent().toggleClass('newClass');
});
I could not reproduce your problem. Your code is working fine in my Firefox on a simple HTML page.
Please try this piece of code and come back with the console output:
function onClick(ev) {
console.log(ev.currentTarget, '\n', ev.target, '\n', ev);
if(ev.target === ev.currentTarget)
console.log($(this).parent().toggleClass('newClass').hasClass('newClass') ? 'B' : 'A');
};
EDIT:
and of course:
$(document).on('click', '.commonClass', onClick);
For readability put the logic into the jQuery selector using the :not like this
$(document).on('click','.reportCollapsed > .reportsArrow', function() {
$(this).parent().removeClass('reportCollapsed')
console.log("A");
})
$(document).on('click','not:(.reportCollapsed) > .reportsArrow', function() {
$(this).parent().addClass('reportCollapsed')
console.log("B");
})
Given that this works one time (click > else > B) could it be that something listens for DOMSubtreeModified or other DOMChange Events which again trigger a click on the document ?
Have you tried debugging/following the calls after the inital click? Afaik chrome has a nice gui to do this.

jQuery function bind on 'input propertychange' not firing as expected

I have jQuery code that calls a function as such:
$('#text_area').bind('input propertychange', function() {...
The element being bound to the function is a text area. When I type and delete text the function gets called just fine, however when I select all of the text, either through a hot-key or dragging the mouse, and then hit backspace the function is not called. This is the only instance where I can not get the function to call. Is this expected with the 'input propertychange' event? If so how can I change this to work as expected? Note that this holds true for Chrome, IE, and Firefox.
Would this suit your purposes?
$('#text_area').on('keyup', function() {
console.log('called');
});
Fiddle: http://jsfiddle.net/KyleMuir/ruJZD/
Also, as of jQuery 1.7 .on() (http://api.jquery.com/on/) is the preferred way to bind events.
EDIT: since someone was after right click pasted text, here is an update:
$('#text_area').on('keyup paste', function() {
console.log('called');
});
Fiddle: http://jsfiddle.net/KyleMuir/ruJZD/9/
You need to call a function when your text area get cleared. Or you want to call the same function when text is pasted into the text area.
You can use the same code what you are included in your question. I have included a working demo with this answer
<textarea id='textarea1'>data</textarea>
//....................
$("textarea").bind('input propertychange', function(){
alert($(this).val());
});
Note: Use jquery plugin
DEMO
If you want to prevent simultaneous triggers then use the below code
<textarea id="textarea"></textarea>
//.......
var text = "";
$("#textarea").on("change keyup paste", function() {
var Val = $(this).val();
if(Val == text) {
return; //prevent multiple simultaneous triggers
}
text = Val;
alert("changed!");
});
DEMO1
'Note: Checked with chrome and firefox'
.bind method has been deprecated latest 3 j query versions.
instead on we can use .on in to get correct answer.
<textarea id="anytextid"></textarea>
<div id="sethere"></div>
correct text for this change
$('#anytextid').on('input propertychange', function() {
$('#sethere').html($(this).val().length );
});

Trigger Bootstrap typeahead on paste event

I've been trying to manually trigger the typeahead search on right-click paste by catching the paste event as follows but I can't seem to find a way to trigger the typeahead's 'matcher' function manually to query the entered string.
$('#search-bar').bind("paste", function(e)
{
$(this).trigger("keydown"); // Tried keyup, input to no avail!
});
Any help would be much appreciated!
Shamelessly copied code from https://stackoverflow.com/a/15179532/559079
$('#search-bar').typeahead({
'updater' : function(item) {
myAjaxFunction(item);
}
});
function myAjaxFunction (item){
$.ajax({ //DO STUFF HERE });
}
$('#search-bar').bind("paste", function(e){
var self = $(this);
setTimeout(function(){self.trigger("keydown");}, 0);
});
(1) my lazy solution: call $('#yourtypeaheadfield').trigger('keyup') to "impersonate" a keyup / keypress event .. this is how Typeahead hooks into the JQuery API.
(2) "better" answer: fire the typeahead event exlicitly - $().trigger('typeahead.updater') - I could not figure out the syntax, though, and it is not documented (at least not for bootstrap 2.3.2).

how to bind to both blur and change, but only trigger a function once in Jquery/Javascript?

I'm trying to trigger a function when a select element is changed.
Since Ipad is having trouble with on('change'), I also want to bind to 'blur', which works fine on Ipad.
However I don't want both events to trigger the function twice, so I need some kind of hook to make sure if both change and blur trigger, that the underlying function is only fired once.
This is what I'm doing now, but ... not very nice:
// make sure binding is only assigned once
var compSel = $('#my_select');
if ( compSel.jqmData('bound') != true ){
console.log("bound");
compSel.jqmData('bound', true)
.on( $.support.touch ? 'blur' : 'change', function(){
console.log("trigger");
// run function xyz
})
}
This works if you can live with all touchable devices making do with blur.
Question:
Does anyone have a better idea to make sure blur and change only trigger a function once?
Thanks for help!
Try creating a function, bound to both events, and adding a timeout to call the function. This way, if the function is called multiple times, it will only run once.
Something like this (you can adjust the timeout if needed):
function blurChange(e){
clearTimeout(blurChange.timeout);
blurChange.timeout = setTimeout(function(){
// Your event code goes here.
}, 100);
}
$('#my_select').on('blur change',blurChange);
don't know about ipad, but on browser maybe something like this
$("#dataTable tbody").on("click blur", "tr", function(event){
if (event.type == "click")
{
//do stuff
}
else
{
//do nothing
}
});
It's not nice, but you can call to change into the blur function, and do all the stuff in the change function:
...
$(document).on("change", "#yourelement", function(){
//do your stuff
});
....
$(document).on("blur", "#yourelement", function(){
$("#yourelement").change();
//alternatively, you can trigger the change event
//$("#yourelement").trigger("change");
});
It doesn't look nice, but I think it should work.
EDIT: If the browser launches both events (blur and change), this code will call twice the change functionality. I think that you can achieve that behavior with some kind of flag:
var executed = false;
...
$(document).on("change blur", "#yourelement", function(){
if(!executed){
executed = true;
//do your stuff
}
});
Attach multiple events you can use it like this also
<select class="form-control" id="Category" name="Category" required>
<option value="">Choose an option</option>
<option value="1">Your Text</option>
</select>
<p class=""></p>
$( "#Category" ).on( "blur change", function( event ) {
if($(this).val()===""){
$(this).next().text("Please choose category").css("color","#a94442");
}
else
{
$(this).next().text("");
}
});
In the case that both events are always triggered, we can set a flag for the first trigger and run the script. The second trigger will see the flag and clear it, and return so it only runs the first time.
In this case, you can blur multiple times without making a change, so it will only run every other time. If there is a change, then it should run for sure (whether the flag is on or off).
$(document).on("change blur",".selector", function(){
if($(this).data("triggered") == "1"){
$(this).data("triggered","0");
return;
}
$(this).data("triggered","1");
// your script here
// fix for "every other time" issue described above
var el = $(this);
setTimeout(function(){ el.data("triggered","0"); }, 200);
}
You might consider the "input" event, if you want to detect a change before the user leaves the element.
You might also consider writing the script so that it is safe to run multiple times (idempotent) and efficient enough that it doesn't affect performance if it runs twice.
You can bind to multiple events at the same time:
$(document).on('blur change','#mySelector',function(){
// this is called on either
});

catch paste event

I need a catch copy & paste event. I have a example. But paste event fires 4 times. Why? I need a it a one time. Here is the code? Please help me?
$(function() {
return $('#myform').bind('paste', function(e) {
return alert("123");
});
});
I'm not sure which browser your experience four events being fired, but I've jus tested your code for myself and could not reproduce the behaviour. That being said, there are a few issues with your code as it is...
There is no need to return the jQuery object after binding the event.
There is no need to return alert(), since alert returns undefined.
Take a look at these changes:
$(function() {
$('#myform').bind('paste', function(e) {
console.log(e.type);
});
});
See live: http://jsfiddle.net/rwaldron/6CKxM/

Categories