I have a script that builds a dynamic div with contents. The button that initializes the build uses an onclick command and a ajax call to retrieve the appropriate info, then builds the div. This all works great, it builds the div, and jquery shows the div and the button changes to the close button. The problem now is that the button still has the onclick command attached to it, and I was to strip this command off, and reapply it if the user wants to view the information again.
The button code on initial load:
<img class="showPixFeature hidden" id="butShowImage_<?php echo $row_rsFeatureAds['AdID']; ?>" src="../images/class_see_more.png" align="absmiddle" onclick="getRemoteInfo('PicDetailFeature_<?php echo $row_rsFeatureAds['AdID']; ?>')" style="cursor: pointer" />
Script that builds the div:
function showImage(IDS, selectedID){
var adType = new Array();
adType = IDS.split("_");
//alert(adType);
var thumbs = new Array();
thumbs = adType[1].split("~");
var adID = thumbs[0];
//alert(adType[0] + '_' + thumbs[0]);
var picImage = document.getElementById(adType[0] + '_' + thumbs[0]);
removeChildren(picImage);
var picThumbs = document.createElement('div');
arLen = thumbs.length;
//alert(arLen);
if(arLen > 2){
for ( var i=1, len=arLen; i<len; ++i ){
//alert(thumbs[i]);
var thumbNail = document.createElement('img');
thumbNail.src = "../images/listings/" + adID + "_" + thumbs[i] + "_sm.jpg";
thumbNail.className = "thumbNails";
thumbNail.id = adID + '_' + thumbs[i];
picThumbs.appendChild(thumbNail);
picImage.appendChild(picThumbs);
addHandler(adID, thumbs[i], 1);
}
}
var previewImageContainer = document.createElement('div');
var previewImage = document.createElement('img');
previewImage.id = 'full_' + adID;
previewImage.src = "../images/listings/" + adID + "_" + "1_.jpg";
previewImage.className = 'thumbNails';
previewImageContainer.style.width = "700px";
previewImageContainer.style.textAlign = 'center';
previewImageContainer.appendChild(previewImage);
picImage.appendChild(previewImageContainer);
var closeButton = document.createElement('img')
closeButton.src = '../images/close_pix.png';
closeButton.id = 'close_' + adType[0] + '_' + adID;
picImage.appendChild(closeButton);
addHandler(adID, 'close_' + adType[0], 2);
$("#" + adType[0] + '_' + adID).show('blind', {}, '1300');
$("#butShowImage_" + thumbs[0]).attr("src", "../images/close_pix.png");
$("#butShowImage_" + thumbs[0]).removeClass('hidden').addClass('shown');
}
Is there a way of stipping that onclick command off?
Thanks for you help!
I prefer to .delegate() and .undelegate() methods for binding event stuffs like that. Delegate is little bit different from the .bind() and .live() methods
Here is the great explaination about the diffrences
http://net.tutsplus.com/tutorials/javascript-ajax/quick-tip-the-difference-between-live-and-delegate/
kep it in mind :)
There are several issues I would fix with your code. First and foremost is to separate your functionality from your markup. This means removing the onclick events that you are firing through your elements. Now, this gets more complicated because you are passing PHP vars through your markup as well.
So your issue can be broken down into to sections.
Removing event handlers from your markup. This is, among other things i'm sure, a poor way to organize functionality.
A more robust means of communicating between JavaScript/PHP. In order to really take advantage of the web-based environment it will save you a lot of trouble passing variables in a more organized fashion. I would recommend looking into pairing Ajax with JSON. jQuery has some good implementations of both of these ($.Ajax() | $.parseJSON()).
The primary goal here is to clean up your markup to make it more readable, and better contain the different functions of your application - Functionality, Style, and information.
First, clean up your element a bit by removing the onclick event listener
<img src="example.jpg" id="someId_<?php echo id;?>;" class="showPixFeature" />'
Second, attach your event listener in whichever fashion you would like. Use $.delegate if you are dynamically generating the images. Use $.bind if you are not.
$('.showPixFeature').bind('click', function(){
// this function will execute everytime an element is clicked
// you have access to the element ID here via 'this' because
// the functions context is the element that fires it
alert($(this).attr('id'));
});
You can then remove the bound event with $.unbind() API. OR $.undelegate if you are using delegate. From here we can add an ajax call to
$('#my-element').unbind('click');
You could use .one(). It's the same as using .bind(), and it unbinds it after it's used once.
Related
I have a code that works perfectly when the number of thumbnails to rotate is 16 and the location is the same for all (only changes the name of the file due to the thumbnail number). Example: http: //www.urltoimage1.jpg....http: //www.urltoimage16.jpg
This is the html:
<img width="189" height="142" src="http: //www.urltoimage8.jpg" class="someclass" id="latest-499" onmouseover="thumbStart('latest-499', 16, 'http: //www.urltoimage');" onmouseout="thumbStop('latest-499','http: //www.urltoimage8.jpg');">
Here is the javascript:
// JavaScript Document
//rotating thumb functions
var rotateThumbs = new Array();
function changeThumb( index, i, num_thumbs, path)
{
if (rotateThumbs[index])
{
if(i<=num_thumbs){
document.getElementById(index).src = path + i + ".jpg";
i++;
setTimeout("changeThumb('"+ index +"'," + i + ", " + num_thumbs + ", '" + path + "')", 600);
}else{
changeThumb( index, 1, num_thumbs, path);
}
}
}
function thumbStart(index, num_thumbs, path)
{
rotateThumbs[index] = true;
changeThumb( index, 1, num_thumbs, path);
}
function thumbStop(index, srco)
{
rotateThumbs[index] = false;
document.getElementById(index).src = srco;
}
Now, the problem is for some articles the thumbnails are not in the same location. Example: http: //www.urltoimage1.jpg....http: //www.urltoimageksks16.jpg
I think that, in the existence of this discrepancy, it is better to copy all the urls of the thumbnails to the class of the image, leaving the html in this way:
<img width="189" height="142" src="http: //www.urltoimage8.jpg" class="http: //www.urltoimage1.jpg,http: //www.urltoimage2.jpg,...,http: //www.urltoimageksks16.jpg" id="latest-499" onmouseover="thumbStart" onmouseout="thumbStop('latest-499','http: //www.urltoimage8.jpg');">
Now that I have all the urls in the class of the img tag, how can achieve that the thumbnail rotate?
Thanks
don't store the urls in the class attributes, use Data Attributes instead. (or Data Attributes from jQuery)
something like
<img .. data-thumbnail-url="http: //www.urltoimageksks16.jpg" .. />
if you're using jQuery (you've added it to your tags), you could use directly
var thumbnailSrc = jQuery('img').data('thumbnail');
if you're not using it (since I don't see any jQuery at all in your code) you have to use this instead
var thumbnailSrc = document.getElementById(index).dataset.thumbnail
using that, you could replace your src attribute. you'll probably want to store in data attributes the original src.
About rotating itself (It is not clear if it is part of your question or if you want to know if it is ok to store the urls in class attributes), there are answers for that using jquery, like jQuery animate image rotation You only need to adapt the functionality to be executed on hovering. You could use pure css as well Spin or rotate an image on hover
On a side note, use this
var rotateThumbs = [];
rather than
var rotateThumbs = new Array();
See In JavaScript, why is [ ] preferred over new Array();?
Can someone explain why this code isn't working. If you click the cats quickly, it freezes the browser.
render: function(catName){
var cat = controller.getCat(catName);
var displayArea = $('#displayArea');
var catImage = $('#catImage');
var num = $('#numClicks');
// the two lines below are not performant
catImage.attr('src', cat.url);
num.text(cat.numClicks);
// the three lines below can replace the two lines above and they work. Why?
//displayArea.empty();
//displayArea.append('<img src=\"' + cat.url + '\"' + '</img>');
//displayArea.append('<p>' + cat.numClicks + '</p>');
$("#displayArea img").click(function(){
cat.numClicks++;
controller.updateClicks(cat.name, cat.numClicks);
view.render(cat.name);
});
}
Here is the jsfiddle: https://jsfiddle.net/ryangittens/fo2g24dp/1/
You're constantly re-hooking the click event. Changing the src of an img doesn't unhook the handlers. (Note that I'm assuming, partially on the basis of the commented-out code, that #catImage is inside #displayArea.)
Just hook click on $("#displayArea img") once.
it's because you are adding a click event every time render is called.
try
$("#displayArea img").off('click',).on('click', function(){
cat.numClicks++;
controller.updateClicks(cat.name, cat.numClicks);
view.render(cat.name);
});
This will remove previously bound events
I want to use EggImageDropdown, but I have problems with the script.
I embedded it in my testing site and there it works:
http://herzschloss.de/hs/test.php at "Mein Wunschbild".
Now I want to use the same script with the same linked in js-code here:
http://herzschloss.de/Liebesschloss-bestellen at "Mein Wunschbild"
But I get an error.
TypeError: jQuery(...).val(...).EggImageDropdown is not a function
This is the live generated script that didn't work:
function onclick(event) {
var t = jQuery('select[id=dropdown_demo]').val('herz.png').EggImageDropdown('close').EggImageDropdown('update',{src:'hs-motive/herz.png'});t.trigger('change');
}
This is the code:
jQuery('option',element).each(function(i,el){
dropdown.append('<img style="width:100%" onclick="var t=jQuery(\'select[id=' + selectName + ']\').val(\''+ $(el).val() + '\').EggImageDropdown(\'close\').EggImageDropdown(\'update\',{src:\''+ $(el).text() + '\'});t.trigger(\'change\');" src="' + $(el).text() + '"/>');
});
It would be great if you help me!
It's very difficult to embed that much code into an onclick attribute. Better to not do it.
To correct it, create the function directly in the loop instead of creating an attribute.
jQuery('option',element).each(function(i,el){
var img = $('<img>', {style: "width:100%;", src: $(el).text()});
img.click(function() {
var t=jQuery('select[id=' + selectName + ']');
t.val($(el).val()).EggImageDropdown('close')
.EggImageDropdown('update', {src:$(el).text()});
t.trigger('change');
});
dropdown.append(img);
});
Furthermore, looking at your linked site, it appears that the EggImageDropdown function doesn't exist, which means you're not successfully loading the plugin.
I am trying to update data-coords (11th line), but when I do it the code runs but the data-coords don't update. Why? It looks valid to me, am I missing something?
$(document).on('click', '.next-prev-js', function (e) {
var item = e.target;
if($(item).is("img") && tagging){
var offset = $(item).offset();
var imgid = $(item).attr("data-image-id");
var obi = $("#blackout-image").offset();
x = (e.clientX - offset.left);
y = (e.clientY - offset.top);
addTag(e.clientX - obi.left - 55, e.clientY - 55);
saveCoords(x, y, imgid);
$(item).attr("data-coords", x+","+y);
tagging = false;
$(".tag-self").text("Tag yourself");
$("#blackout-image img").css({cursor: "pointer"});
$("#blackout-image .face").delay(3000).fadeOut("fast");
return false;
}
var action = $(item).attr("data-action");
nextPrevImage(action);
return false;
});
Here is the HTML portion (This is inside a php echo statement):
<a class='thumb-photo' href=''>
<img class='thumb-img' data-coords='$x,$y' data-id='$id' data-image-id='$imid' data-file='$f' src='/user-data/images/image.php?id=$id&file=$f&height=240&width=240' width='240' height='240' />
</a>
Demo
(Don't refresh the page during this process)
If you click on one of the images, it will open in a viewer .
On the left hover over "Where is He" and a square will show where the data-coords are (from thumbnail image)
Next click on "Tag yourself", then click on a location in the image.
Close the viewer by pressing "esc" or clicking on the transparent area
Click on the image again, and mouse over "Where is He" the coords are still the old coords, but they should have been updated after you clicked on the new location
http://wows.phpsnips.com/profile.php?id=1&tab=photos
You should use the data method.
$(item).data({coords: x+","+y});
or
$(item).data("coords", x+","+y);
works in jsfiddle.
You can see your data attributes with:
console.log($(item).data());
The way the data- attributes work is that the value gets copied into the jQuery data object on page load. After that they aren't really connected anymore. So if you change the attribute, the object won't update automatically. Same for the other way around.
I made a quick test to demonstrate the behavior:
jQuery:
var $d = $('div');
alert('Load: Attribute "a" gets copied to data object.\rData Attribute: ' + $d.attr('data-test') + '\rData Object: ' + $d.data('test'));
$d.attr('data-test','b');
alert('Changed attribute to "b". Attribute changed, object still "a".\rData Attribute: ' + $d.attr('data-test') + '\rData Object: ' + $d.data('test'));
$d.data('test','c');
alert('Changed data object to "c". Object changed, attribute still "b".\rData Attribute: ' + $d.attr('data-test') + '\rData Object: ' + $d.data('test'));
Demo:
http://jsfiddle.net/F5qkq/
So in your case, you only change the data attribute with attr but that way the internal data-object remains the same because they aren't connected anymore.
The data-attribute is only really used to initialize the data object with a startvalue. But after that, as said before, you should only work with jQuery's data function to change the internal data object.
I'm pretty new to anything AJAX and ran into the following problem. I hope someone here is able to help me out. I'm sure it's an easy fix but I just don't see it :(
What I'm trying to do is change the onmouseover and onmouseout events dynamically for the element, here are the relevant bits of code:
The HTML Element (notice there are multiple of these, hence the dynamic part of their id)
<?
if (ownsgame($id, $userid)) {?>
<a><img src="images/collection/got.gif" id="ownedimage<?=$id?>" title="<?=$itemtitle?> (<?=$platformdisplay?>) is in your collection" alt="You own this game" align="center" width="62" height="22" onclick="changeOwned('<?=$id?>')" onmouseover="changeImageSrc('ownedimage<?=$id?>', 'images/collection/del.gif')" onmouseout="changeImageSrc('ownedimage<?=$id?>', 'images/collection/got.gif')"/></a>
<? } else { ?>
<a><img src="images/collection/add.gif" id="ownedimage<?=$id?>" title="Add <?=$itemtitle?> (<?=$platformdisplay?>) to your collection" alt="You do not own this game" align="center" width="62" height="22" onclick="changeOwned('<?=$id?>')" onmouseover="changeImageSrc('ownedimage<?=$id?>', 'images/collection/add.gif')" onmouseout="changeImageSrc('ownedimage<?=$id?>', 'images/collection/add.gif')"/></a>
<?} ?>
The JavaScript function:
function changeImageSrc(id, src) {
document.getElementById(id).src = src;
}
The (relevant) AJAX code:
var http = createRequestObject();
var jsid = "";
function changeOwned(id) {
http.open('get', 'changeowned.php?id=' + id + '&user=<?=$userid?>');
jsid = id;
http.onreadystatechange = processResponse;
http.send(null);
}
function processResponse() {
if((http.readyState == 4) && (http.status == 200)){
var response = http.responseText;
var elementid = 'ownedimage' + jsid;
var element = document.getElementById(elementid);
if (response == "1") {
image = "images/collection/got.gif";
alt = "you own this game";
mouseoverstr = 'images/collection/del.gif';
mouseoutstr = 'images/collection/got.gif';
element.removeEventListener('mouseout', function(){changeImageSrc('ownedimage' + jsid, 'images/collection/add.gif')}, false);
element.removeEventListener('mouseover', function(){changeImageSrc('ownedimage' + jsid, 'images/collection/add.gif')}, false);
} else {
image = "images/collection/add.gif";
alt = "add this game to your collection";
mouseoverstr = 'images/collection/add.gif';
mouseoutstr = 'images/collection/add.gif';
element.removeEventListener('mouseout', function(){changeImageSrc('ownedimage' + jsid, 'images/collection/got.gif')}, false);
element.removeEventListener('mouseover', function(){changeImageSrc('ownedimage' + jsid, 'images/collection/del.gif')}, false);
}
element.src = image;
element.alt = alt;
element.addEventListener('mouseover', function(){changeImageSrc('ownedimage' + jsid, mouseoverstr)}, false);
element.addEventListener('mouseout', function(){changeImageSrc('ownedimage' + jsid, mouseoutstr)}, false);
}
}
It seems to work fine at first but produces some weird behaviour. The referenced PHP works fine and produces the correct response. The srcand alt of the image get changed as well. In fact, it first looks like the new mouseover/out work too. But when you click on more than one image on the site (which have different IDs) they suddenly start influencing each other. When you mouseover over one, the other changes its image aswell. Why is this happening? I really am clueless as the jsid part is fine and I don't understand why the mouseover suddenly changes two images. It looks as if multiple eventhandlers for different IDs are assigned to the same image element. No idea why that is though. I hope some of you with more AJAX knowledge can help me here, quite frustrated :(
A couple of things there: :-)
1) addEventListener and removeEventListener work with the newer DOM2 handler chain, which is completely separate from the older "DOM0" style (the onXYZ attributes). So you can't remove a handler via removeEventListener that you've originally assigned via an onXYZ attriubte. To do that, assign "" to the attribute's reflected property.
element.onmouseover = "";
2) When you use removeEventListener, you must pass in the same function reference that you used originally. So this will never remove anything:
element.removeEventListener('mouseout', function(){changeImageSrc('ownedimage' + jsid, 'images/collection/got.gif')}, false);
...because it creates a brand new function to pass into removeEventListener, and since that function isn't on the event handler chain, the call is ignored.
I'd probably approach the problem by having a single event handler, but then changing the data it works with. You can do that by storing the alternate image URLs on the actual element itself, using a data-xyz attribute (say, data-oversrc and data-stdsrc or some such). Then your two functions (one for mouseover, one for mouseout) that change the URL based on the image:
function handleMouseOver() {
this.src = this.getAttribute('data-oversrc');
}
function handleMouseOut() {
this.src = this.getAttribute('data-stdsrc');
}
I'd drop the onXYZ handlers from the elements entirely, and replace them with a one-time addEventListener (attachEvent on IE) that assigns both of those.
data-xyz attributes, like all custom attributes, are invalid in HTML4 and earlier. As of HTML5, they validate, and since no major browser has a problem with invalid attributes anyway, you can start using them right away.
Off-topic #1: These days, I usually recommend using a JavaScript library to smooth over browser differences and implement useful functionality for you. For instance, your code using addEventListener and removeEventListener will fail on IE prior to IE9 because it simply doesn't have those methods. If you use a library like jQuery, Prototype, YUI, Closure, or any of several others, they'll deal with that stuff for you so you can focus on your own value-add.
Off-topic #2: The mouseover event happens repeatedly when the mouse is passing over the element, and both it and mouseout bubbles up the DOM. This means that for hover effects like yours, if you can't use CSS (and you can't on IE6), you're better off using the mouseenter and mouseleave events, most of the time. But those are IE-specific events not supported by most other browsers. Enter any decent JavaScript library. :-) They'll emulate mouseenter and mouseleave on browsers that don't support them directly. Of the list above, I know for certain that jQuery and Prototype do that; I'd be surprised if the others don't have similar functionality.
The issue is the removeEventListener, it's not working like you think it is. What's happening is when you do this:
element.removeEventListener('mouseout',function(){/* handlers */},false);
That function() { } is a new anonymous function you just created, not the existing one on the element as a listener...so when it goes to remove that listener, it just isn't there, because that was a different anonymous function (even if it had the exact same code, it's a different reference) that you assigned via addEventListener.
There are a few work-arounds for this, given that you're making AJAX requests I'm assuming you're not making hundreds/thousands here, so you could just store the handlers you assign for removing them later, like this:
var http = createRequestObject();
var jsid = "";
var handlers = {};
function changeOwned(id) {
http.open('get', 'changeowned.php?id=' + id + '&user=<?=$userid?>');
jsid = id;
http.onreadystatechange = processResponse;
http.send(null);
}
function processResponse() {
if((http.readyState == 4) && (http.status == 200)){
var response = http.responseText,
elementid = 'ownedimage' + jsid,
element = document.getElementById(elementid),
image, alt, mouseoverstr, mouseoutstr;
if (response == "1") {
element.src = "images/collection/got.gif";
element.alt = "you own this game";
mouseoverstr = 'images/collection/del.gif';
mouseoutstr = 'images/collection/got.gif';
} else {
element.src = "images/collection/add.gif";
element.alt = "add this game to your collection";
mouseoverstr = 'images/collection/add.gif';
mouseoutstr = 'images/collection/add.gif';
}
//Create a holder if this is the first time for this elementid
if(!handlers[elementid]) handlers[elementid] = {};
//Remove old handlers
element.removeEventListener('mouseover', handers[elementid].mouseover, false);
element.removeEventListener('mouseout', handers[elementid].mouseout, false);
//Store new handlers
handlers[elementid].mouseover = function(){changeImageSrc('ownedimage' + jsid, mouseoverstr)};
handlers[elementid].mouseout = function(){changeImageSrc('ownedimage' + jsid, mouseoutstr)};
//Add hew handlers as listeners
element.addEventListener('mouseover', handers[elementid].mouseover, false);
element.addEventListener('mouseout', handers[elementid].mouseout, false);
}
}