How to automatically click() dynamically created elements - javascript

I understand that you can bind an event listener to dynamic elements, but I want to have the js automatically click them. As in, there is a webpage with a series of buttons that pop up, I want to automatically click thru them, but each successive button is loaded dynamically and so I cannot do it simply.
Here's what I was hoping would work (works if you type it into console one line at a time):
$(".begin").click().delay(200);
$(".answer[value='1']").click().delay(200);
$(".answer[value='10']").click().delay(200);

If I don't misunderstand your problem. You want to click those buttons "once" they exist. Then you might create a timer after $('.begin')(here I assume the begin is to trig the button appear action) and constantly check those buttons and click them once it's active. It would look something like the following with setTimeInvertal(). And yes you need to create your own condition to stop or determine whether trig click or not.
You have to detect them manually, faster check = once (I assume you are not doing something illegally or abusing websites). The below code is a sample idea.
var btn_timer;
function startAction() {
//for example check every 3s
btn_timer = setTimeout(function(){
//check if btn exists or not
if($(".answer[value='1']").length) {
$(".answer[value='1']").click().delay(200);
}
//condition to stop your timer, or you can manually call it somewhere else;
if(...some condition) StopAction();
}, 3000);
}
function StopAction() {
clearTimeout(btn_timer);
}

Related

Javascript click event listener fires only once

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.

Looking for Javascript / jQuery Event trigger

I have got a javascript based menu generator that is from an external source. The menu functionality occurs via a click event bound to a specific ID... pretty standard.
What I want to do is perform another action on the DOM AFTER that click event fires.
I would rather not hack the code that came in the menu package.
I tried attaching my own click handler - but there isn't an obvious way of ensuring my click handler fires AFTER the menu system's handler. One approach I considered was basing an event on the addition/removal of a class that occurs with the menu system's click handler. But - I quickly found that there is no event based on the change of class on an element (that I know of).
Any ideas? (without hacking the original menu system's js)
You can use the javascirpt Mutation Observer, here is a great article about the subject : Listening to the DOM changes with MutationObserver
OR in an old fashion
If I understand, (1) you can add your own click event listener, (2) you want execute your code after a class name change on the menu element.
In that case, you can use a setInterval to check if the class has changed and if so, trigger your action.
Something like that :
myOnClickFunction(){
var menu = document.querySelector('#MyMenuID');
var timer = setInterval(() => {
if(menu.classList.contains('TheClassNameYouWantToCheck')){
//Clear the interval
clearInterval(timer);
//Execute your actions here
}
}, 50);
//You can also add a maximum checking time
//after 5 seconds the function stop checking for changes
setTimeout(()=>clearInterval(timer), 5000);
}

Changing the value of jQuery's $(this) object inside an event

I'm wanting to click an image (img#first) and have it split into three smaller versions of another image (img.cat). Each time img.cat is clicked, it throws the cloned elements in random directions and temporarily shows a lion in place of the img.cat that was clicked.
The cat replication and lion popup both work properly (as you can see by clicking the smaller cat in the upper left corner), but I don't know how to make it so a .click() event on img#first will call the function to replicate smaller cats. To reiterate, I want the img#first to spawn 3 smaller img.cat, then disappear, then if the user continues to click new img.cat objects they continue to spawn more of themselves. The problem is just getting that original img#first to start the chain reaction and then disappear forever.
Here's the Fiddle.
If I'm able to just make the entire .click(explode) function work on img#first and then swap that identifier somehow to img.cat after the initial click, wouldn't that do the trick?
For example:
var firstRun = 0
$('img#first').click(function() {
if (!firstRun) {
//do original stuff here
firstRun = 1;
} else {
$(this) = $('img.cat');
//do img.cat stuff here
}
});
Or do I need to isolate the explode function so that it can be called separately on two different objects while achieving the same effect?
I honestly have no idea how to go about accomplishing either of these tasks. Maybe there's a simpler way to get what I want.
Add a separate event which triggers only on clicking #first which programmatically triggers a click on img.cat then removes itself like this:
$('#first').click(function() {
$("img.cat").trigger("click");
$(this).remove();
});
Here is a working jsFiddle.
Update your $('img.cat').click() event listener's selector to $('img.cat, img#first) to select both img.cat and img#first. With this new event listener, you can remove your first $('img#first').click() listener. See my updated JSFiddle.

javascript how to execute one method after another

I have some animation in my code and I have faced a problem: When the user clicks the button more than once my animation will become faster and faster. To deal with this I have included the refresh page function (location.reload()) inside the function below.
Now I have a major problem: when I execute the button supposed the reload page function will be executed first then follow by day2 function then day1 function... the problem is now only the refresh page function is been executed.
How do I overcome this problem?
Javascript:
function day()
{
location.reload().then(day2).then(day1);
}
HTML:
<input type="button" id="buttonThree" value="Day" onclick="day()"/>
What you're doing doesn't work
Now I have a major problem: when I execute the button supposed the reload page function will be executed first then follow by day2 function then day1 function... the problem is now only the refresh page function is been executed.
Well, yeah. You refreshed the page. That involves leaving the page then re-entering it. Leaving the page means your JavaScript ends everything it's doing, and re-entering it means your JavaScript starts anew. JavaScript does not transcend page loads.
If you want your JavaScript to communicate with JavaScript on other pages, do so via other means: an #anchor in the URI, a query string in the URI, form data, sessionStorage, localStorage, or cookies - those are arranged in order of permanence and appropriateness, with cookies completely overdoing it, and #anchors and query strings being completely appropriate.
But that's completely unnecessary and inappropriate here. You shouldn't be doing what you're doing in the first place.
Let's address the actual problem of multiple button presses
I have some animation in my code and I have faced a problem: When the user clicks the button more than once my animation will become faster and faster.
Simply put, you shouldn't be doing what you're doing and this problem has a much simpler solution: disable the button, or set a boolean flag, in order to prevent the animation from running multiple times. Simply, don't allow the animation to run multiple times.
Option 1: Disabling the button
Disabling the button prevents it from sending onclick events, and signals to your user the button won't do anything for now. I recommend doing this if your button should not do anything longer whilst the animation is running, or whilst something else is happening.
The approach is to disable the button as soon as it's clicked. Later, once the tasks that button fired off (such as the animation) are finished, and it's OK to click the button again, you re-enable the button.
<input type="button" id="animateButton" value="Animate" onclick="animate()"/>
function animate() {
// 'this' refers to the button, when the button's click event
// calls this function
this.disabled = true;
startAnimation();
}
function startAnimation() {
// run the animation
// ...
// once the animation is completed, via whatever means you want
// (such as by jQuery's animate.complete callback),
// re-enable the button like this:
document.getElementById("animateButton").disabled = false;
// or address the button some other appropriate way.
}
Option 2: Boolean flag, leaving the button enabled but doing nothing
This approach involves using a boolean flag to ignore clicks when the animation is running, instead of disabling the button outright.
This lets the user click the button still. It's useful if you want the button enabled for whatever reason, such as if you want the button doing other things on click - just without starting the animation every time.
If it's not going to do anything except start the animation, however, you probably should use option 1 instead to disable it, signalling the button won't do anything for now.
If you want this button to do other things, I suggest you have it call a different function - for example, doStuff() - and have that function call the animate() function below.
<input type="button" id="animateButton" value="Animate" onclick="animate()"/>
var canAnimate = true;
function animate() {
if (!canAnimate) return; // do nothing if we're not allowed to animate yet
canAnimate = false;
startAnimation();
}
function startAnimation() {
// run the animation
// ...
// once the animation is completed, via whatever means you want
// (such as by jQuery's animate.complete callback),
// set the flag to say we can animate again, like this:
canAnimate = true;
}

How does jQuery handle nested functions and timing of events?

There are a couple of things that really trouble me with regards to how jQuery handles nested functions (not to the point that I can't sleep but it's getting there) and I wish a jQuery expert could explain how things work to bring me piece of mind.
Let's say you have the below HTML code:
<button id="first">click me first</button>
<button id="second">click me next</button>
And the following jQuery code:
$(document).ready(function() {
$('#first').click(function() {
$('#second').click(function() {
alert('test');
});
});
});
A dialog box will popup if you click the first button and then the second button.
I understand jQuery instantiates the $('#first').click() function when the DOM is ready and calls it when someone clicks on the first button.
However what I am puzzled with is the following:
[Q1] is the $('#second').click() function also instantiated on DOM ready or only when $('#one').click() is called?
Now, when you look at the jQuery code, there is nothing that "keeps us" in the $('#first').click() function, that is once the user clicks on the first button, the $('#second').click() function should be instantiated and we should exit the $('#one').click() function straight away. However after clicking the first button, jquery must somehow keep $('#second').click() indefinitely in memory in case the user clicks on the second button.
[Q2] how does jquery know to keep the $('#second').click() function in memory until the user clicks on the second button after clicking the first button?
Finally let's say you wanted to modify your code so that the user had to click the second button within 10 seconds of clicking the first button for the dialog box to appear:
[Q3] how would you implement this so that jQuery would know to stop listening for click events on the second button after 10 seconds?
Q1 - JS will simply load function definitions. It won't run it unless they are explicitly triggered/called. In this case, it will simply attach the event handler to #first and wait until someone clicks the button to fire the event. This will make the second function attach itself to the second button.
Q2 Again, it's not jQuery, it's JavaScript doing all the work. The method is simply attached to the DOM element and is triggered on the event it is attached to. JS is like any programming language and will keep all methods and variables in its memory.
The second click function isn't actually attached to the second button until after someone clicks on the first button. This is because, when the first button is clicked, JS knows to trigger the first method which does all the work of attaching the second method to the second button.
Q3 You could use setTimeout to unbind that method from the DOM element.
$(document).ready(function() {
$('#first').click(function() {
$('#second').click(function() {
alert('test');
setTimeout(function(){$('#second').unbind('click');}, 10000);
});
});
});
Note This unbinds all click event handlers from this DOM element. You can also unbind that particular method by passing it as a parameter. Check out the API docs for usage.
setTimeout : https://developer.mozilla.org/en/DOM/window.setTimeout
unbind : http://api.jquery.com/unbind/
[A1] The second function is only instantiated when #first is clicked as it is part of the execution of the first method. This also means that if you click #first n times you should get n alerts for every click on #second.
[A2] The function is rooted by the #second element. So long as that element is alive javascript knows to keep the function around.
[A3] You would need to save off the function pointer and do a setTimeout to clear it.
$(document).ready(function() {
$('#first').click(function() {
var secondFunction = function() {
alert('test');
};
$('#second').click(secondFunction);
setTimeout(function(){ $('#second').unbind('click', secondFunction); }, 10000);
});
});
A better implementation is probably something like:
$(document).ready(function() {
var enabled = false;
$('#first').click(function() {
enabled = true;
setTimeout(function(){ enabled = false; }, 10000);
});
$('#second').click(function() {
if(enabled) {
alert('test');
};
});
});
The answer to your first question: Yes, the second button will bind to click event only when a user clicks on the first button.
The second question: I'm not sure what you're asking.
The third one: Assuming the button one has nothing to do except bind the event to second button once clicked, you can set a timeout on document ready for 10 seconds. Now when the timer expires it must unbind the button one's click event hence blocking second button's event. I guess you understand now. e.g.
$(document).ready(function(){
setTimeout(removeEvent, 10000);
$('#first').click(function() {
$('#second').click(function() {
alert('test');
});
});
});
function removeEvent(){
$('#first').unbind('click');
}

Categories

Resources