I am using the google search API and I want that when you click on an image, this image will be copied to a different location.
I created a fiddle here: http://fiddle.jshell.net/wjewg062/
It works this way: The user types in a term in the input field and images will be displayed. When he/she clicks on one twice it will displayed in the image div.
I put the onClick event listener on to the searchresults div, hence the extra click in the beginning. However, I want it to be displayed on the first click.
Now, if I comment this out
var searchresults = document.getElementById('searchresults');
searchresults.addEventListener("click", function(event){
event.preventDefault();
imageing();
});
it doesn't work. The images will be links. I believe the reason for this is that the results are displayed in gs-image-box and not created yet. I tried calling the imaging function in different other functions like the searchImg or the OnLoad but nothing work.
I thought of using a check if element is clicked function described here Detect if I'm clicking an element within an element
but I think there must be an easier way.
I'm running out of ideas, can anyone give an idea or hint?
Thanks !
The images are dynamically created right? Check out this post Event binding on dynamically created elements?
In short, events are attached to elements upon pageload. so a newly created dynamic element such as the ones that google creates, aren't attached to the event. so google probably has a way to circumvent the whole "you need to load the page to attach events to elements" thing but it requires an extra click. Using the syntax found in the post should help you.
By the way. Using Jquery doesn't really show down your site because it's usually cached in the client's browser.
The info you need is already in your searchresults eventListener. The target of this event will be the image you click, even if you add the event on a div higher in the structure.
A javascript event will by default be dispatched from the top element (window) all the way through the element that received the click, then will go back to the top. Any element that is an ancestor of the element that was clicked will receive the event info, so you can listen on any ancestor, but the target remains the element that was actually clicked.
In your case, by simply passing the target to your imageing() function, you can apply the behaviors you want without any extra manipulations.
One problem you might face, is if user clicks on searchresult but not on an img element. Then you'll have a bug, so you should handle these cases.
Something like this:
var searchresults = document.getElementById('searchresults');
searchresults.addEventListener("click", function (event) {
console.log(event.target, this);
event.preventDefault();
if(event.target.tagName == 'IMG'){
imageing(event.target);
}
});
function imageing(targetImg) {
var imageresult = document.getElementsByClassName('gs-image-box');
var xu = document.getElementById('companylogo');
var imgsrc = targetImg.src;
xu.src = imgsrc;
}
http://fiddle.jshell.net/pwjLrfnt/3/
Related
As said in the title, I am trying to customize the contextmenu event. The situation is this: I want to catch the event, preventing it from firing on some elements (I'm ok here, all good), then I want to call it targeting another element (this is not working). At first I just tried dispatching it by creating a custom event and using myTargetElement.dispatchEvent(), the custom element does fire, but context menu won't open.
The reason I need this is that I want to open the contenteditable context menu when the user clicks anywhere. I've tried something similar to the last example on this MDN page, and I logged the event type, it is firing. Here's some example code of what I'm doing.
HTML
<div id="prevent">This div will prevent default event behaviour.</div>
<div id="my-target" contenteditable>Fire here the event and open context menu</div>
For instance, I cannot put one div inside the other.
JS
function showMenu(){
const preventer = document.getElementById('prevent');
const myTarget = document.getElementById('my-target');
const myEvent = new Event('contextmenu', {
bubbles:false //I had to use this, as setting it true was logging an error on Firefox
});
myTarget.dispatchEvent(myEvent);
console.log(myEvent.type); //it does log the event name
}
The listener that prevents default is not important, as when I just run the showMenu() (even when removing every other bit of js) on console it still has not the intended effect. I'm also able to listen to the 'contextmenu' event when I add a listener and run showMenu().
I'm beginning to think that there is not a direct solution to this, but workarounds and ideas would be really appreciated.
I have a Chrome extension that intercepts and checks tweets before they get posted. To do this, I've add an event listener to the Tweet button. Sine the content is dynamic, I use the solution proposed in this thread:
initialize : function() {
let that = this;
let jsInitChecktimer = setInterval(checkForJsFinished, 111);
function checkForJsFinished () {
if (document.querySelector("div[data-testid='tweetButtonInline']")) {
clearInterval (jsInitChecktimer);
console.log("Button found");
that.addSubmitNewTweetClickHandler();
}
}
},
addSubmitNewTweetClickHandler : function() {
let that = this;
let buttonSubmitTweet = document.querySelector("div[data-testid='tweetButtonInline']");
buttonSubmitTweet.addEventListener('click', function(e) {
console.log("CLICK");
// Stop default event from happening
e.preventDefault();
e.stopImmediatePropagation();
// Do stuff
});
},
If the tweet passed the checks alright, it gets submitted by programmatically triggering the event using .trigger('click').
This works fine, but only once. After a tweet has been submitted and posted, the event listener on the Tweet button is gone, and I cannot intercept the next tweet to check it. I've tried calling initialize() after submitted again -- maybe the button gets removed and newly added to the DOM (it actually disappears fire a moment when submitting a tweet) -- but the querySelector finds the button immediately. But even after calling initialize() again, no click even on the Tweet button fires.
What could be the issue here? My problem is that I don't even know where to look for and how to debug this.
After many more hours, I've finally figured it out. The problem was essentially the highly dynamic content of the new Twitter website. After submitting a tweet, the Tweet button gets indeed removed and added again. In needed to do a serious of changes:
Use a MutationObserver to keep track of any changes. Every time there's a change, call the initialize() function. To avoid too many calls, I do this in case of certain changes (unnecessary detail here)
Change the addSubmitNewTweetClickHandler() method so that the event listener first gets removed in order to avoid duplicate listeners (please note that I use objects hence the use of this compared to my original question)
addSubmitNewTweetClickHandler : function() {
let that = this;
let buttonSubmitTweet = document.querySelector("div[data-testid='tweetButtonInline']");
buttonSubmitTweet.removeEventListener('click', this.handleSubmitNewTweetClick );
this.handleSubmitNewTweetClick = this.handleSubmitNewTweetClick.bind(this)
buttonSubmitTweet.addEventListener('click', this.handleSubmitNewTweetClick );
},
This change required to create the reference function handleSubmitNewTweetClick
Overall, it's still not a perfect solution since I call initialize() many unnecessary time. However, I failed to reliably identify when the Tweet button was added to the document. When I used the MutationObserver none of the added nodes had the attribute data-testid which I need to identify the correct button. I have node idea why this attribute was not there. Maybe the attribute is added some times after added to button, but even with an additional MutationObserver looking for attribute changes I could detect this.
Anyway, it works now and it's only for a prototype.
I am binding the scroll events to all my html elements. To get the all the elements i am using the below filter
var element = $(myelemt).parentsUntil("html").add($(window));
return element
here element will return the body, window and all parents htmls tags.
For this html elements i am binding the events like below code:
element.on("scroll", function (e) {
$("#mywrapper3").html($("#mywrapper3").html() + "scrolling<br>");
}
Here i want to prevent particular child div element only from binding. How i can achive this?.
For example in my page for one div element(element with mywrapper id in sample) i dont want to bind this scroll event.
Also, I have to filter the element like in first code only. So how to achieve this instead of using stop propagation. Is there any way to do this.
I have prepared the one jsfiddle.Please get the link below
https://jsfiddle.net/khkcjb6o/
Thanks for any help
The .off() method is what you need. Originally I had started answering with an iframe solution and came up with the better solution later.
Since an iframe's context is different than it's parent, it is not included if you register everything on the parent page.
In the PLUNKER, the first section has an iframe with srcdoc and content within. Scroll the iframe and you'll notice that it isn't triggering the scroll counter.
Same thing with the second section that has a normal iframe.
The third and fourth section have scrolling content.
As expected, both trigger the scroll event.
Click the IV OFF button which uses the .off() method.
Now scroll section IV and notice the scroll counter isn't increasing.
.off() is what you need. Make sure to use this expression:
$('*').on('scroll', function() {....
That * will register everything but iframe content on a page so you don't have to write all of that code you had in your question.
You could jus use the :not() CSS selector
var element = $(myelemt + ':not(#mywrapper3)').parentsUntil("html").add($(window));
element.on("scroll", function (e) {
$("#mywrapper3").html($("#mywrapper3").html() + "scrolling<br>");
}
Some code that looks like the following is firing the click event via the Enter key, but is not responding to the mouse click.
//a is an anchor element
a.addEventListener('click', function (e)
{
//Do Stuff...
});
This page demonstrates the problem. The relevant bit of code is at line 176. This is in the middle of development and currently only (sort of) works in Chrome.
Also, I just verified that it works if I use mousedown, so it's not just the case of an invisible element sitting in front of the anchor.
Any ideas?
Edit: Now that you've shown us the actual code you're using, the problem is related to the fact that the autoSuggest() function has it's own click handler and in that click handler, it is clearing the container which removes all <a> elements in the container so your link object gets destroyed (probably before your click event gets to process). So, you can get events that happen before the click (like mousedown), but after a click, the element is removed from the DOM.
If you tell us what you're trying to actually do when an auto-suggest item is clicked that is different than the default behavior of the autoSuggest() function and you point to any documentation for that function, then perhaps we could offer a better way to solve your issue.
The link may be firing and taking you off to a new page (or reloading the current page), thus preventing you from seeing the click code run. Usually when you process a click event on a link element, you need to prevent the default behavior:
//a is an anchor element
a.addEventListener('click', function (e) {
e.preventDefault();
//Do Stuff...
});
Another possibility is that you are trying to install the event handler too soon either before the DOM has been loaded or before this particular link has been created and thus no actual click event handler is attached to the DOM object. You can verify whether the event handler is even getting called by temporarily putting an alert("Click handler called"); in the event handler and see if that pops up or not.
Is it possible, with Javascript or some other technology to determine which hyperlink a user has clicked on, without changing the hyperlink source code.
For example:
Can you click on a 'tag' button, then click on a hyperlink hosted in a different iframe, and be able to calculate which hyperlink the user clicked on, without changing any of the source code in that iframe?
Using jQuery, you are able to set the context of your selection. i.e.
$('a', $('#iframe-id')).click(function() {...});
You can then implement an event handler that will handle the iFrame hyperlink clicks. The "this" property within the handler will allow you to interrogate the hyperlink and obtain properties such as innerText etc.
you need to put an event on each a link ,
and then you will get all the information about the specific click.
this will work only in the some document,
so if you try to do a test between the link inside an iframe and a link in your page you will not get an event for the iframe link.
in order to attach the event for all link you need to run on all the links in the page ,
the best way to do that is by jQuery selector. or other js framework like YUI
$("a").click(function () {
alert('')
});
getElementsByTagName("a") - will give you all the links in the page.
I just thought of a solution, would this work, or are there other options?
The solution would be to proxy the content of the iframe soruce page, replacing href's with code to call a javascript function which would identify which href was clicked on.
This could then be used in conjunction with the tag'ing click to accurately tag a link.
This would also mean the original source, doesn't need to change at all.
What do you need ?-)
If you got an iframe, you use as a target for links, you must do some server-side processing or add something to the url of the links, that you can read when the page loads ...
But detecting time of page-load requires a script in the page, that is inside the iframe, or a function which tests the availability of the elements in the page in the iframe in short intervals ...
-- but you can only succeed if the page comes from the same domain as the main-page, as cross-domain scripting is illegal and thus impossible !-)
I think it should be possible. The contents of an IFrame is accessible from the outer document (the page in which the iframe is embedded) so you should be able to add event handlers (see other answers) on those elements after the iframe has loaded.
See also Wikipedia on Iframe which gives some examples and frameworks which actually work on content within an IFrame.
You can inject code into an iframe, but only if that iframe is on the same domain as the page you're injecting from, for obvious security reasons.
<iframe id="framedpage" src="framedpage.html"></iframe>
<button type="button" id="tagbutton">Tag</button>
<script type="text/javascript">
function framedclicks_bind() {
var f= document.getElementById('framedpage');
var fdoc= f.contentDocument;
if (!fdoc) fdoc= f.contentWindow.document; // for IE
if (fdoc)
for (var i= fdoc.links.length; i-->0;)
fdoc.links[i].onclick= framedclicks_click; // bind to all links
}
function framedclicks_click() {
alert('You clicked on '+this.href);
return false; // don't follow link
}
document.getElementById('tagbutton').onclick= framedclicks_bind;
</script>
Might want to cleaning-up depending on application needs (eg. to ensure the frame is always loaded before trying to bind, or that unbinding can happen, or that any onclicks from the original links are remembered), but that'd be the general shape of things.
Good solution to find out which element was clicked is to use event delegation. If you attach event listener to each element using a loop (over document.links or document.getElementsByTagName), you have two problems:
- browser has many listeners to maintain
- events are attached only to elements that were in the DOM when you called the loop; any element dynamically added later doesn't have an event listener.
A simple example of event delegation:
document.onclick = function(e){
e = e || window.event;
var t = e.target || e.srcElement;
if(t.nodeName=='A'){
alert( t.href );
}
}
If you want to find clicked link inside an iframe just use iframe's contentDocument instead of document.