Reference to a div without IDs - javascript

I have a problem with addEvent(or something else I don't know). This is my code.
HTML :
<div style="background-color:red;height:30px;width:30px;" ></div>
<div style="background-color:yellow;height:30px;width:30px;" ></div>
JS :
function addEvent(elm,ev,fun)//Cross-browser addEvent
{
if(elm.addEventListener)elm.addEventListener(ev,fun,false);
else if(elm.attachEvent)
{
var r=elm.attachEvent("on"+ev,fun);
return r;
}
}
function myFun(x)
{
alert(x.style.backgroundColor);
}
var allDiv=document.getElementsByTagName("div");
myFun(allDiv[0]);//Here it works
for(var i=0;i<allDiv.length;i++) {
//But not here when you click the div
addEvent(allDiv[i],
"click",function(){
myFun(allDiv[i])
});
}
I want that the alert works but without using IDs and without puting an inline onclick. Is it possible ?
http://jsfiddle.net/G9gBS/1/

You've fall into a common trap when using closures in JavaScript. I is closed over but changes on all click functions are calling myFunc with allDiv[allDiv.length -1] you can use a self executing function to get around this
for(var i=0;i<allDiv.length;i++) {
addEvent(allDiv[i],
"click",(function(j) {
return function(){
myFun(allDiv[j])
}
}(i)));
}
this no longer closes over i (i is never referenced in the function assigned to the click event).
in this particualr case however you can simply pass this. An event handler is called in the context of the element firing the event so you can do
for(var i=0;i<allDiv.length;i++) {
addEvent(allDiv[i],
"click",function(){myFun(this)});
}
or even shorter using jQuery
var myFun function(x)
{
alert(x.style.backgroundColor);
}
$("div").click(myFun);

Instead of calling it as allDiv[i], pass in this to the callback function. At the time the onclick callback is called, i is out of scope and can't be resolved by allDiv[i]. The callback is called in context of the calling <div>, referenced by this.
for(var i=0; i<allDiv.length; i++) {
addEvent(allDiv[i], "click", function() {
// allDiv[i] is out of scope in the callback. Use this instead.
myFun(this);
});
}
Updated jsFiddle.

change
for(var i=0;i<allDiv.length;i++)addEvent(allDiv[i],"click",function(){myFun(allDiv[i])});
to
for(var i=0;i<allDiv.length;i++)addEvent(allDiv[i],"click",function(){myFun(this)});
And if I want to access to i onclick, what do I pass as parameter?
like that, is one way (another would be to use a bind):
for(var i=0;i<allDiv.length;i++){
var bob = i;
addEvent(allDiv[i],"click",function(){
alert(bob);
myFun(this,bob);
});
}

Related

Migrate onClick from HTML to Javascript file

In my HTML, this works
<div id="portfolio1" onclick="changeMainFrame('lib/portfolio1.html')">
to trigger the following function:
function changeMainFrame(srcURL){
var target = document.getElementById("mainFrame");
target.src = srcURL;
}
I want to migrate it to my javascript doc. But this does not work:
document.getElementById("portfolio1").onclick = changeMainFrame("lib/portfolio1.html");
I can not find out how to fix this. Any hints? Cannot find a similar situation anywhere for something so simple yet time consuming.
document.getElementById("portfolio1").onclick = function() {
changeMainFrame("lib/portfolio1.html");
}
You're calling the function changeMainFrame. What you want to do is supply a function wrapper.
document.getElementById("portfolio1").onclick = function() {
changeMainFrame("lib/portfolio1.html");
}
function changeMainFrame(txt) {
alert(txt);
}
<div id="portfolio1">Click Me</div>
You need to assign a function to document.getElementById("portfolio1").onclick which will be called when that element gets clicked. The problem is that instead of assigning a function, you assigned the result of invoking/calling that function. What you can do instead is provide a function in which inside it you call changeMainFrame:
document.getElementById("portfolio1").onclick = function() {
changeMainFrame("lib/portfolio1.html");
};
You need to either use .onclick or the onclick attribute. Both of them require a handler function, and what you were passing was just the result of running your changeMainFrame function (null). Wrapping it in a function() { } yields your expected result.
function changeMainFrame(srcURL){
var target = document.getElementById("mainFrame");
target.src = srcURL;
}
document.getElementById("portfolio1").onclick = function(){changeMainFrame('https://codepen.io')}
<div id="portfolio1">go to codepen.io</div>
<iframe id="mainFrame" src="https://example.com"></iframe>

Do I need to remove and replace event handlers with JQuery to swap them?

I want the events click and touchstart to trigger a function.
Of course this is simple with JQuery. $('#id').on('click touchstart', function{...});
But then once that event is triggered, I want that same handler to do something else when the events are triggered,
and then later, I want to go back to the original handling function.
It seems like there must be a cleaner way to do this than using $('#id').off('click touchstart'); and then re-applying the handler.
How should I be doing this?
You can create a counter variable in some construct in your javascript code that allows you to decide how you want to handle your event.
$(function() {
var trackClicks = (function() {
var clicks = true;
var getClicks = function() {
return clicks;
};
var eventClick = function() {
clicks = !clicks;
};
return {
getClicks: getClicks,
eventClicks: eventClicks
}
})();
$('#id').on('click touchstart', function {
if (trackClicks.getClicks()) {
handler1();
} else {
handler2();
}
trackClicks.eventClick();
});
function handler1() { //firsthandler};
function handler2() { //secondhandler};
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
The way I would do this is by creating a couple of functions for the handler function to call based on certain flags. Sudo code would be something like this:
function beginning_action() {
...
}
function middle() {
...
}
var beginning_state = true;
$('#id').on('click touchstart', function{
if(beginning_state) {
beginning_action();
} else {
middle();
}
});
Then all you need to do is change the variable beginning_state to change which function is called. Of course you would give them better names that describe what they do and not when they do it.
Additionally, if you want the handler to call more than two functions you can change the beginning_state variable from a boolean to an int and check it's value to determine which function to call.
Good luck!

jQuery off() is not unbinding events when using bind

function bubble(content, triggerElm){
this.element = $('<div class="bubble" />').html(content);
this.element.css(.....) // here is positioned based on triggerElm
}
bubble.prototype.show = function(){
$(document).on('click', this._click.bind(this));
this.element.css(....)
};
bubble.prototype.hide = function(){
$(document).off('click', this._click.bind(this));
this.element.css(....)
};
bubble.prototype._click = function(event){
console.log('click', this);
if(this.element.is(event.target) || (this.element.has(event.target).length > 0))
return true;
this.hide();
};
var b = new bubble();
b.show();
b.hide();
I keep seeing click in the console, so the click does not unbind.
But if I remove the bind() call the click is unbinded. Does anyone know why? I need a way to be able to change "this" inside my test function, that's why I'm using bind().
The problem is that this._click.bind() creates a new function every time it's called. In order to detach a specific event handler, you need to pass in the original function that was used to create the event handler and that's not happening here, so the handler is not removed.
If there are only going to be a few bubbles in your app, you could and simply not use this. That will remove a lot of the confusion about what this is referring to and ensure that each bubble retains a reference to its own click function that can be used to remove the event as needed:
function bubble(content, triggerElm) {
var element = $('<div class="bubble" />').html(content);
element.css(.....); // here is positioned based on triggerElm
function click(event) {
console.log('click', element);
if (element.is(event.target) ||
element.has(event.target).length > 0) {
return true;
}
hide();
}
function show() {
$(document).on('click', click);
element.css(....);
}
function hide() {
$(document).off('click', click);
element.css(....);
}
return {
show: show,
hide: hide
};
}
var b1 = bubble(..., ...);
b1.show();
var b2 = bubble(..., ...);
b2.show();
See how this frees you from using contrivances like .bind() and underscore-prefixed methods.
One option would be to namespace the event:
$(document).on('click.name', test.bind(this));
$(document).off('click.name');
Example Here
try use jQuery's proxy to get a unique reference of your function.
In this way, when you call $.proxy(test, this), it will check if this function has already been referenced before. If yes, proxy will return you that reference, otherwise it will create one and return it to you. So that, you can always get your original function, rather than create it over and over again (like using bind).
Therefore, when you call off(), and pass it the reference of your test function, off() will remove your function from click event.
And also, your test function should be declared before use it.
var test = function(){
console.log('click');
};
$(document).on('click', $.proxy(test, this));
$(document).off('click', $.proxy(test, this));
http://jsfiddle.net/aw50yj7f/
Please read https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
bind creates a new function therefore doing $(document).on('click', test.bind(this)); is like $(document).on('click', function(){}); and each time you execute it you invoke a new anonymous function thus you dont have a reference to unbind.
If you would do something like:
var test = function(){
console.log('click');
};
var newFunct = test.bind(this);
$(document).on('click', newFunct );
$(document).off('click', newFunct );
It should work fine
e.g: http://jsfiddle.net/508dr0hv/
Also - using bind is not recommended, its slow and not supported in some browsers.
rather than binding this to the event, send this as a parameter:
$("#DOM").on("click",{
'_this':this
},myFun);
myFun(e){
console.info(e.data._this);
$("#DOM").off("click",myFun);
}

Javascript pass parameter to function

i try to pass paramater to function. When i click the div it will alert the paramater that i pass
i have 2 file
index.html
script.js
here's what i try
Example 1
index.html
<div id="thediv" >
script.js
window.onload = initialize;
//bind event listener
function initialize(){
document.getElementById("thediv").onclick = myFunction(" something ");
}
//end of bind
//function
function myFunction(parameter) { alert( parameter ) };
//end of all function
the trouble is the function its executed without click
Example 2
index.html
<div id="thediv" onclick="myfunction('something')" >
script.js
function myFunction(parameter) { alert( parameter ) };
yap its done with this but the trouble if i have many element in index.html it will painful to read which element have which listener
i want to separate my code into 3 section (similiar with example1)
the view(html element)
the element have which listener
the function
what should i do? or can i do this?
(i don't want to use another library)
Placing () (with any number of arguments in it) will call a function. The return value (undefined in this case) will then be assigned as the event handler.
If you want to assign a function, then you need to pass the function itself.
...onclick = myFunction;
If you want to give it arguments when it is called, then the easiest way is to create a new function and assign that.
...onclick = function () {
myFunction("arguments");
};
Your first solution logic is absolutely ok .. just need to assign a delegate ... what you are doing is calling the function .. So do something like this ...
//bind event listener
function initialize(){
document.getElementById("thediv").onclick = function () { myFunction(" something "); };
}
//end of bind
Instead of assign you invoke a function with myFunction();
Use it like this
//bind event listener
function initialize(){
document.getElementById("thediv").onclick = function(){
myFunction(" something ");
}
}

Only last item has bound click/hover events?

I'm a newbie to Javascript & HTML5. I'm iterating through a set of objects called requests and creating divs for them. I'm trying to have it so that if any of the items are hovered over the style class changes, and if they are clicked on that I will later invoke a function but for now just want an alert. Only the last item gets it.
I've looked at what seemed like similar issues other people have had, but I can't see where I am going wrong.
for (i= 0; i<reqs.length; i++) {
var requestID = "request"+i;
// Build the DIV for each request
element.innerHTML += "<div id="+requestID+" class=request><img class=requestImage src=images/"
+reqs[i].image+" alt=Face /> "+reqs[i].name+"</div>";
var requestElement = $('#'+requestID);
requestElement.hover(
function() {
$(this).removeClass().addClass("requestHover");
},
function() {
$(this).removeClass().addClass("request");
}
);
requestElement.click(
// if the request is clicked, then alert me - testing
function() {
alert('Handler for .click() called.');
}
);
}// end for
From my understanding the $('#request1') should reference the first div item, and $('#request2') the second, etc. It behaves like each .hover and .click assignment overwrites the previous one.
I'd write it this way
for (i= 0; i<reqs.length; i++) {
var requestID = "request"+i;
// Build the DIV for each request
element.innerHTML += "<div id="+requestID+" class=request><img class=requestImage src=images/"
+reqs[i].image+" alt=Face /> "+reqs[i].name+"</div>";
}// end for
var requestElement = $(".request");
requestElement.hover(
function() {
$(this).removeClass().addClass("requestHover");
},
function() {
$(this).removeClass().addClass("request");
}
);
requestElement.click(
// if the request is clicked, then alert me - testing
function() {
alert('Handler for .click() called.');
}
);
Edit to answer to your comment:
No, it's a matter of closure. At the end of the loop, requestID is always the same, so $("#"+requestID); is always the same. It's has if there is only one bind.
To overcome such a thing, you have some option:
using $.each to loop (see http://forum.jquery.com/topic/binding-event-to-element-dynamically , http://forum.jquery.com/topic/binding-click-event-in-a-loop, http://api.jquery.com/jQuery.each/ )
using the live() method (see http://api.jquery.com/live/, http://jsfiddle.net/VrzUb/1/ (used for the click))
assigning the events thanks to a selector common to each object (e.g. using classes, as above)
You can assign the event listener after the for loop, maybe that solves your problem:
for (...) {
}
$('div.request').hover( ... );

Categories

Resources