jQuery focus blur pass parameter - javascript

I can't seem to access the variable defaultValue down in my .blur() function. I've tried various stuff but with no luck. So far I only get an empty object. What's wrong?
jQuery(document).ready(function(){
jQuery('#nameInput, #emailInput, #webInput').focus(function(){
var defaultValue = jQuery(this).val();
jQuery(this).val("");
})
.blur(function(defaultValue){
if(jQuery(this).val() == ""){
jQuery(this).val(defaultValue);
}
});
});

Looks like the question is about the passing data into the .blur or .focus event.
per jQuery API - http://api.jquery.com/blur/
blur( [eventData ], handler(eventObject) )
So if you want to pass data - you can send a parameter to event - which will appear as data in event object.
see this fiddle for more info
http://jsfiddle.net/dekajp/CgP2X/1/
var p = {
mydata:'my data'
};
/* p could be element or whatever */
$("#tb2").blur(p,function (e){
alert('data :'+e.data.mydata);
});

Because your code is wrong :-) you define var inside function (var defaultValue) which is then immediately wiped out.
There are two solutions: define your var as a global var before you bind blur event, or store it in the data of object liket his (which I recommend):
$(document).ready(function(){
$('#nameInput, #emailInput, #webInput').focus(function(){
$(this).val("").data('defaultValue',jQuery(this).val());
}).blur(function(defaultValue){
if($(this).val() == ""){
$(this).val($(this).data('defaultValue'));
}
});
});

It seems to me that you don't understand the basics of JavaScript.
First of all variables in JS are localized to function's scope, so you can't declare variable with var in one function and access it in other function
Second, you can't pass anything to DOM-event handler, except event-object, this is defined by the DOM specification, sometimes you can use event data parameter to the blur jQuery method.
Try this:
jQuery(document).ready(function(){
var defaultValue;
jQuery("#nameInput, #emailInput, #webInput").focus(function(){
defaultValue = jQuery(this).val();
jQuery(this).val("");
})
.blur(function(){
if(jQuery(this).val() == ""){
jQuery(this).val(defaultValue);
}
});
});
First of all, you need to distinguish blur method (function) and handler (function) which is the argument to the blur. You was trying to pass the defaultValue exactly to handler, but that can't be done. Inside handler the defaultValue would be equal eventObject, so you can do smth like console.log(defaultValue.timeStamp) and you'll see smth like 123482359734536
In your approach you can't even use event.data argument to the blur cause it will be set at the time of blur's call (attaching handler). You need to declare a var outside of the both handlers, so it will be visible to both of them
You may consider to read some comprehensive book on JS.
I read "Professional JaveScript For Webdevelopers" by Nicolas Zakas. There is a new edition

Related

How to capture change in text when that change is through javascript function. Javascript change event is not working in this case

My Code is as below.
$(document).ready(function($)
{
var form = $("#video_detail_form");
var name = $("#videoTitle");
var nameInfo = $("#valid_videoTitle");
function validateName(){
//if it's NOT valid
var titleValue=$.trim(name.val());
if(titleValue.length == 0){
nameInfo.text("Please Enter Title");
return false;
}
//if it's valid
else{
nameInfo.text("");
return true;
}
}
name.blur(validateName);
name.keyup(validateName);
name.change(validateName);
$('#editVideoCancel').click(function(){
cancelVideoDetailAjaxCall( '/video/cancelVideoDetail', callBackCancelVideoDetail);
});
});
My cancelVideoDetailAjaxCall function changes text of the videoTitle input box. But my this code is not capturing that event by name.change.
If I change manually then it captures it. So when dynamically my callback function is changing the text then change event is not capturing it.
How should I capture that change?
You can actually extend your value change catching to all changes coming from some script using the jQuery val method, by setting a custom setter in jQuery.valHooks.
Imagine you change the input type to myCustomType, then you will implement jQuery.valHooks.myCustomType.set method which will be called each time val is used to set the input value, and you will include your specific call here. But I insist : it is not a best practice.
You will surely find explicit code on the web for that hooks.
As comments have mentioned, if you programmatically change the value via jQuery you must also trigger that change programmatically, if you want anything subscribed to it to register that change.
You can always make up your own events and trigger them accordingly if you don't want to "interfere" with other things already subscribed to regular events:
$el.on('mycustomevent', function() { ... })
$el.trigger('mycustomevent');
You can even subscribe with the same callback for the 'regular event' and your 'custom event':
$el.on('change', myChangeCallback);
...
$el.on('mycustomevent', myChangeCallback);
If you don't want to keep typing $el.val('...').trigger('mycustomevent') repeatedly, then declare a helper function that does that for you:
// helper function for changing the value
function changeInput(newVal) {
if(!this.$target) this.$target = $('#text'); // stash the target for reuse
this.$target
// programmatically change the value; does not fire 'change' event
.val(newVal)
// now trigger your custom action that behaves
.trigger('customaction'); // add extra parameters, etc
}
Full example: https://jsfiddle.net/drzaus/ds6g745s/8/

jQuery Event Handler created in loop

So I have a group of events like this:
$('#slider-1').click(function(event){
switchBanners(1, true);
});
$('#slider-2').click(function(event){
switchBanners(2, true);
});
$('#slider-3').click(function(event){
switchBanners(3, true);
});
$('#slider-4').click(function(event){
switchBanners(4, true);
});
$('#slider-5').click(function(event){
switchBanners(5, true);
});
And I wanted to run them through a loop I am already running something like this:
for(i = 1; i <= totalBanners; i++){
$('#slider-' + i).click(function(event){
switchBanners(i, true);
});
}
In theory that should work, but it doesnt seem to once I load the document... It doesnt respond to any specific div id like it should when clicked... it progresses through each div regardless of which one I click. There are more event listeners I want to dynamically create on the fly but I need these first...
What am I missing?
This is a very common issue people encounter.
JavaScript doesn't have block scope, just function scope. So each function you create in the loop is being created in the same variable environment, and as such they're all referencing the same i variable.
To scope a variable in a new variable environment, you need to invoke a function that has a variable (or function parameter) that references the value you want to retain.
In the code below, we reference it with the function parameter j.
// Invoke generate_handler() during the loop. It will return a function that
// has access to its vars/params.
function generate_handler( j ) {
return function(event) {
switchBanners(j, true);
};
}
for(var i = 1; i <= totalBanners; i++){
$('#slider-' + i).click( generate_handler( i ) );
}
Here we invoked the generate_handler() function, passed in i, and had generate_handler() return a function that references the local variable (named j in the function, though you could name it i as well).
The variable environment of the returned function will exist as long as the function exists, so it will continue to have reference to any variables that existed in the environment when/where it was created.
UPDATE: Added var before i to be sure it is declared properly.
Instead of doing something this .. emm .. reckless, you should attach a single event listener and catch events us they bubble up. Its called "event delegation".
Some links:
http://davidwalsh.name/event-delegate
http://net.tutsplus.com/tutorials/javascript-ajax/quick-tip-javascript-event-delegation-in-4-minutes/
http://www.sitepoint.com/javascript-event-delegation-is-easier-than-you-think/
http://lab.distilldesign.com/event-delegation/
Study this. It is a quite important thing to learn about event management in javascript.
[edit: saw this answer get an upvote and recognized it's using old syntax. Here's some updated syntax, using jQuery's "on" event binding method. The same principle applies. You bind to the closest non-destroyed parent, listening for clicks ON the specified selector.]
$(function() {
$('.someAncestor').on('click', '.slider', function(e) {
// code to do stuff on clicking the slider. 'e' passed in is the event
});
});
Note: if your chain of initialization already has an appropriate spot to insert the listener (ie. you already have a document ready or onload function) you don't need to wrap it in this sample's $(function(){}) method. You would just put the $('.someAncestor')... part at that appropriate spot.
Original answer maintained for more thorough explanation and legacy sample code:
I'm with tereško : delegating events is more powerful than doing each click "on demand" as it were. Easiest way to access the whole group of slider elements is to give each a shared class. Let's say, "slider" Then you can delegate a universal event to all ".slider" elements:
$(function() {
$('body').delegate('.slider', 'click', function() {
var sliderSplit = this.id.split('-'); // split the string at the hyphen
switchBanners(parseInt(sliderSplit[1]), true); // after the split, the number is found in index 1
});
});
Liddle Fiddle: http://jsfiddle.net/2KrEk/
I'm delegating to "body" only because I don't know your HTML structure. Ideally you will delegate to the closest parent of all sliders that you know is not going to be destroyed by other DOM manipulations. Often ome sort of wrapper or container div.
It's because i isn't evaluated until the click function is called, by which time the loop has finished running and i is at it's max (or worse overwritten somewhere else in code).
Try this:
for(i = 1; i <= totalBanners; i++){
$('#slider-' + i).click(function(event){
switchBanners($(this).attr('id').replace('slider-', ''), true);
});
}
That way you're getting the number from the id of the element that's actually been clicked.
Use jQuery $.each
$.each(bannersArray, function(index, element) {
index += 1; // start from 0
$('#slider-' + index).click(function(event){
switchBanners(index, true);
});
});
You can study JavaScript Clousure, hope it helps

How do I redefine `this` in Javascript?

I have a function which is a JQuery event handler. Because it is a JQuery event handler, it uses the this variable to refer to the object on which it is invoked (as is normal for that library).
Unfortunately, I need to manually call that method at this point. How do I make this inside the called function behave as if it were called from JQuery?
Example code:
function performAjaxRequest() {
//Function which builds AJAX request in terms of "this"
}
function buildForm(dialogOfForm) {
var inputItem;
dialogOfForm.html('...');
dialogOfForm.dialog('option', 'buttons', {
"Ok" : performAjaxRequest
});
inputItem = dialogOfForm.children(':not(label)');
//Redirect enter to submit the form
inputItem.keypress(function (e) {
if (e.which === 13) {
performAjaxRequest(); //Note that 'this' isn't the dialog box
//as performAjaxRequest expects here, it's
//the input element where the user pressed
//enter!
}
}
}
You can use the function's call method.
someFunction.call(objectToBeThis, argument1, argument2, andSoOnAndSoOn);
If dialog is the object that you need to be set to this then:
performAjaxRequest.apply(dialog, []);
// arguments (instead of []) might be even better
should do the trick.
Otherwise, in jQuery you can simply call the trigger method on the element that you want to have set to this
Say, for example, that you wanted to have a click event happen on a button and you need it to happen now. Simply call:
$("#my_button").trigger("click");
Your #my_button's click handler will be invoked, and this will be set to the #my_button element.
If you need to call a method with a different this ... say for example, with this referring to the jQuery object itself, then you will want to use call or apply on your function.
Chuck and meder have already given you examples of each ... but to have everything all in one place:
// Call
my_function.call(object_to_use_for_this, argument1, argument2, ... argumentN);
// Apply
my_function.apply(object_to_use_for_this, arguments_array);
SEE: A List Apart's Get Out of Binding Situations
Are you looking for..
functionRef.apply( objectContext, arguments);
You should of course learn to master call() and apply() as people have stated but a little helper never hurts...
In jQuery, there is $.proxy. In pure js, you can re-create that niftyness ;) with something like:
function proxyFn( fn , scope ){
return function(){
return fn.apply(scope,arguments);
}
}
Usage Examples:
var myFunctionThatUsesThis = function(A,B){
console.log(this,arguments); // {foo:'bar'},'a','b'
};
// setTimeout or do Ajax call or whatever you suppose loses "this"
var thisTarget = {foo: 'bar'};
setTimeout( proxyFn( myFunctionThatUsesThis, thisTarget) , 1000 , 'a', 'b' );
// or...
var contextForcedCallback = proxyFn( myAjaxCallback , someObjectToBeThis );
performAjaxRequest(myURL, someArgs, contextForcedCallback );
If you dont abuse it, it's a sure-fire tool to never loose the scope of "this".
use a closure
i.e assign this to that early on; then you can do what you like with it.
var that = this;

How to refer to object in JavaScript event handler?

Note: This question uses jQuery but the question has nothing to do with jQuery!
Okay so I have this object:
var box = new BigBox();
This object has a method named Serialize():
box.AddToPage();
Here is the method AddToPage():
function AddToPage()
{
$('#some_item').html("<div id='box' onclick='this.OnClick()'></div>");
}
The problem above is the this.OnClick() (which obviously does not work). I need the onclick handler to invoke a member of the BigBox class. How can I do this?
How can an object refer to itself in an event handler?
You should attach the handler using jQuery:
function AddToPage()
{
var self = this;
$('#some_item').empty().append(
$("<div id='box'></div>")
.click(function() { self.OnClick(someParameter); })
);
}
In order to force the event handler to be called on the context of your object (and to pass parameters), you need to add an anonymous function that calls the handler correctly. Otherwise, the this keyword in the handler will refer to the DOM element.
Don't add event handlers with inline code.
function AddToPage()
{
$('#some_item').html("<div id='box'></div>");
$('#box').click(this.OnClick);
}
EDIT:
Another way (avoids the extra select):
function AddToPage()
{
var div = $('<div id="box"></div>'); // probably don't need ID anymore..
div.click(this.OnClick);
$('#some_item').append(div);
}
EDIT (in response to "how to pass parameters");
I'm not sure what params you want to pass, but..
function AddToPage()
{
var self = this, div = $('<div></div>');
div.click(function (eventObj) {
self.OnClick(eventObj, your, params, here);
});
$('#some_item').append(div);
}
In jQuery 1.4 you could use a proxy.
BigBox.prototype.AddToPage= function () {
var div= $('<div>', {id: box});
div.click(jQuery.proxy(this, 'OnClick');
div.appendTo('#some_item');
}
You can also use a manual closure:
var that= this;
div.click(function(event) { that.OnClick(event); });
Or, most simply of all, but requiring some help to implement in browsers that don't yet support it (it's an ECMAScript Fifth Edition feature):
div.click(this.OnClick.bind(this));
If you are using jQuery, then you can separate your code from your markup (the old seperation of concerns thing) like this
$(document).ready(function() {
var box = new BigBox();
$('#box').click(function() {
box.serialize();
});
});
You only need to add the click handler once for all divs with id of box. And because the click is an anonymous function, it gets the scope of the function it is placed in and therefore access to the box instance.

How can I programmatically invoke an onclick() event from a anchor tag while keeping the ‘this’ reference in the onclick function?

The following doesn't work... (at least not in Firefox: document.getElementById('linkid').click() is not a function)
<script type="text/javascript">
function doOnClick() {
document.getElementById('linkid').click();
//Should alert('/testlocation');
}
</script>
<a id="linkid" href="/testlocation" onclick="alert(this.href);">Testlink</a>
You need to apply the event handler in the context of that element:
var elem = document.getElementById("linkid");
if (typeof elem.onclick == "function") {
elem.onclick.apply(elem);
}
Otherwise this would reference the context the above code is executed in.
The best way to solve this is to use Vanilla JS, but if you are already using jQuery, there´s a very easy solution:
<script type="text/javascript">
function doOnClick() {
$('#linkid').click();
}
</script>
<a id="linkid" href="/testlocation" onclick="alert(this.href);">Testlink</a>
Tested in IE8-10, Chrome, Firefox.
To trigger an event you basically just call the event handler for that
element. Slight change from your code.
var a = document.getElementById("element");
var evnt = a["onclick"];
if (typeof(evnt) == "function") {
evnt.call(a);
}
Granted, OP stated very similarly that this didn't work, but it did for me. Based on the notes in my source, it seems it was implemented around the time, or after, OP's post. Perhaps it's more standard now.
document.getElementsByName('MyElementsName')[0].click();
In my case, my button didn't have an ID. If your element has an id, preferably use the following (untested).
document.getElementById('MyElementsId').click();
I originally tried this method and it didn't work. After Googling I came back and realized my element was by name, and didn't have an ID. Double check you're calling the right attribute.
Source: https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/click
$("#linkid").trigger("click");
Old thread, but the question is still relevant, so...
(1) The example in your question now DOES work in Firefox. However in addition to calling the event handler (which displays an alert), it ALSO clicks on the link, causing navigation (once the alert is dismissed).
(2) To JUST call the event handler (without triggering navigation) merely replace:
document.getElementById('linkid').click();
with
document.getElementById('linkid').onclick();
Have a look at the handleEvent method
https://developer.mozilla.org/en-US/docs/Web/API/EventListener
"Raw" Javascript:
function MyObj() {
this.abc = "ABC";
}
MyObj.prototype.handleEvent = function(e) {
console.log("caught event: "+e.type);
console.log(this.abc);
}
var myObj = new MyObj();
document.querySelector("#myElement").addEventListener('click', myObj);
Now click on your element (with id "myElement") and it should print the following in the console:
caught event: click
ABC
This allows you to have an object method as event handler, and have access to all the object properties in that method.
You can't just pass a method of an object to addEventListener directly (like that: element.addEventListener('click',myObj.myMethod);) and expect myMethod to act as if I was normally called on the object. I am guessing that any function passed to addEventListener is somehow copied instead of being referenced. For example, if you pass an event listener function reference to addEventListener (in the form of a variable) then unset this reference, the event listener is still executed when events are caught.
Another (less elegant) workaround to pass a method as event listener and stil this and still have access to object properties within the event listener would be something like that:
// see above for definition of MyObj
var myObj = new MyObj();
document.querySelector("#myElement").addEventListener('click', myObj.handleEvent.bind(myObj));
If you're using this purely to reference the function in the onclick attribute, this seems like a very bad idea. Inline events are a bad idea in general.
I would suggest the following:
function addEvent(elm, evType, fn, useCapture) {
if (elm.addEventListener) {
elm.addEventListener(evType, fn, useCapture);
return true;
}
else if (elm.attachEvent) {
var r = elm.attachEvent('on' + evType, fn);
return r;
}
else {
elm['on' + evType] = fn;
}
}
handler = function(){
showHref(el);
}
showHref = function(el) {
alert(el.href);
}
var el = document.getElementById('linkid');
addEvent(el, 'click', handler);
If you want to call the same function from other javascript code, simulating a click to call the function is not the best way. Consider:
function doOnClick() {
showHref(document.getElementById('linkid'));
}
In general I would recommend against calling the event handlers 'manually'.
It's unclear what gets executed because of multiple registered
listeners
Danger to get into a recursive and infinite event-loop (click A
triggering Click B, triggering click A, etc.)
Redundant updates to the DOM
Hard to distinguish actual changes in the view caused by the user from changes made as initialisation code (which should be run only once).
Better is to figure out what exactly you want to have happen, put that in a function and call that manually AND register it as event listener.

Categories