addEventListener not modifying href on click - javascript

I am trying to change href attributes of specific classes onclick. However, the original href never changes.
<a class="vendor" href="https://jsfiddle.net">JSFiddle.net</a>
window.addEventListener("load", fixlinks);
function fixlinks() {
var link_class = document.getElementsByClassName("vendor")
for (var i = 0; i < link_class.length; i++) {
link_class[i].addEventListener("click", makeLinks(link_class[i]));
}
}
function makeLinks(expr) {
//RickRoll 'em
expr.setAttribute("href", "https://www.youtube.com/embed/dQw4w9WgXcQ");
}
//jsfiddle.net/qm9bnvon/5/

The solution is simply to not invoke the function but pass it instead, and use this to reference the bound element in the handler.
Updated DEMO: http://jsfiddle.net/qm9bnvon/11/
window.addEventListener("load",fixlinks);
function fixlinks() {
var link_class = document.getElementsByClassName("vendor")
for(var i = 0; i < link_class.length; i++) { // v----pass it, don't invoke it
link_class[i].addEventListener("click", makeLinks);
}
}
function makeLinks(event) {
// v---`this` refers to the bound element
this.setAttribute("href","https://www.youtube.com/embed/dQw4w9WgXcQ");
}

If the document.readyState property is complete then the onload handler will not fire. (This at least is the case for jsfiddle, which you linked in your question).
So you need to check for both cases:
if(document.readyState === "complete") {
fixlinks();
} else {
window.addEventListener("load",fixlinks);
}
The next issue is that you are not setting a callback in your click listener.
Because makeLinks doesn't return a function for the click handler to invoke:
function fixlinks() {
var link_class = document.getElementsByClassName("vendor")
for(var i = 0; i < link_class.length; i++) {
link_class[i].addEventListener("click",makeLinks(link_class[i]));
}
}
// here we return the callback
function makeLinks(expr) {
//RickRoll 'em
return function() {
expr.setAttribute("href","https://www.youtube.com/embed/dQw4w9WgXcQ");
};
}

Related

My own javascript class and addeventlistener template not working

So here I am experimenting with native javascript. What I am trying to achieve, but failed to do is to create some sort of shortcut for scenarios where I want to add an event listener to a div class.
Here I am trying to say: If the user clicked on a class then show an alert.
Why doesnt my code work?
function click(red){
var source = document.getElementsByClassName(red);
for (i = 0; i < source.length; i++) {
source[i].addEventListener('click', err, false);
}
function err() {
var x = 0;
}
}
if (click('red')) {
alert('rrr');
}
http://jsfiddle.net/y66wh26k/3/
I would use document.querySelectorAll instead of document.getElementsByClassName because it is more versatile.
But the main issue is that your click function actually wasn't returning anything, so your if(click('red')) would never execute. As well, your callback for the event listener being added wasn't really doing anything. So what I've done is made a callback argument, then passed that to addEventListener.
function click(selector, callback){
var source = document.querySelectorAll(selector);
for (var i = source.length-1; i >= 0; --i) {
source[i].addEventListener('click', callback, false);
}
}
click('.red', function() {
alert('rrr');
});
<div class='red'>xxx</div>
<div class='red'>xxx</div>
<div class='red'>xxx</div>

Issue adding event with addEventListener to Input in documentFragment

I am creating a div using createDocumentFragment(). In the Div is a table with a list of input. When you click on any of the checkboxes I want to trigger the alert('Yes'). when I add the event it does not add it to the input but with Firefox it seems to call the alert when it is added to the table.
Can someone explain what I am doing wrong?
function deptFilter(rPattern)
{
var lclData = JSON.parse(rPattern);
var loc = document.getElementById('show2');
var arrayKeys = Object.keys(lclData);
var outputData;
var LCL_List
var LCLTables;
var LCLtd;
var LCLtr;
var LCLInput;
var LCLDiv;
var LCL_List = document.createDocumentFragment(document.createElement('DIV'));
LCL_List.id = 'LCLTable';
for(var x = 0; x < arrayKeys.length; x++)
{
LCLDiv = LCL_List.appendChild(document.createElement('DIV'));
LCLTables = LCLDiv.appendChild(document.createElement('TABLE'));
for(var y = 0; y < lclData[arrayKeys[x]].length; y++)
{
LCLtr = LCLTables.appendChild(document.createElement('TR'));
LCLtd = LCLtr.appendChild(document.createElement('TD'));
LCLInput = LCLtd.appendChild(document.createElement('INPUT'));
LCLInput.id = lclData[arrayKeys[x]][y]['Name'];
LCLInput.type='checkbox';
LCLInput.addEventListener("click", alert("Yes"));
}
}
loc.appendChild(LCL_List);
}
When you install an event handler like this:
LCLInput.addEventListener("click", alert("Yes"));
You're executing alert() immediately and then passing the return value from that to addEventListener(). This is obviously NOT what you want. Instead, you need to pass a function reference to addEventListener and that function will then call your alert() sometime later:
LCLInput.addEventListener("click", function(e) {
alert("Yes");
});
Or you can define a named function and pass just its name:
function handleClick(e) {
alert("Yes");
}
LCLInput.addEventListener("click", handleClick);
This is the way to add event listner:
LCLInput.addEventListener("click", function() {
alert("Yes");
});

Adding a second submit handler

I am trying to modify an existing web page which looks like this
<script type="text/javascript" src="s1.js"></script>
s1.js has something like this
window.onDomReady = DomReady;
function DomReady(fn)
{
if(document.addEventListener)
{
document.addEventListener("DOMContentLoaded", fn, false);
}
else
{
document.onreadystatechange = function(){chState(fn);};
}
}
function chState(fn)
{
if(document.readyState == "interactive" || document.readyState == "complete")
fn();
}
window.onDomReady(addHndlrs);
function addHndlrs()
{
var forms = document.getElementsByTagName("form");
for(var i = 0; i < forms.length; i++)
{
var form = forms[i];
if(form.addEventListener)
{
form.addEventListener("submit", DoValidate, false);
}
else if (form.attachEvent)
{
form.attachEvent("onsubmit", DoValidate);
}
Other stuff.
}
When I click Submit on the form, DoValidate does called.
I am trying to modify this page to add another submit handler which is called after the first one.
I copied the above code, changed function names & put into s2.js.
window.onDomReady = DReady;
function DReady(fn)
{
if(document.addEventListener)
{
document.addEventListener("DOMContentLoaded", fn, false);
}
else
{
document.onreadystatechange = function(){Chk1State(fn);};
}
}
function Chk1State(fn)
{
if(document.readyState == "interactive" || document.readyState == "complete")
fn();
}
window.onDomReady(myready);
function myready()
{
var forms = document.getElementsByTagName("form");
for(var i = 0; i < forms.length; i++)
{
var form = forms[i];
if(form.addEventListener)
{
form.addEventListener("submit", mynewhandler, false);
}
else if (form.attachEvent)
{
form.attachEvent("onsubmit", mynewhandler);
}
}
}
In the form html, I added a reference to it
<script type="text/javascript" src="s1.js"></script>
<script type="text/javascript" src="s2.js"></script>
My new submit handler never gets called. I debugged it through firebug - I see DReady being called and my DOM Ready handler being registered. However myready never gets called, so my submit handler never gets registered.
What am I missing here? I tried changing order of inclusion of s1.js and s2.js but that doesn't seem to help. I want to do this without modifying s1.js
The code you provided seems to be fine! Have checked in Chrome 25, FireFox 19 and IE 10!
Normally I find it easier to just modify the code at runtime (not the source file), thanks to JavaScript being dynamic typed, you could overwrite the DoValidate function with your own, passing it the original DoValidate through closure in the s2.js:
var originalValidate = DoValidate;
DoValidate = function () {
originalValidate();
alert("my handler");
};

Sending an, intercepted and modified, submit re-loads the (wrong) page

I use a Greasemonkey script in Firefox to intercept a submit process in order to modify a certain post variable. I save the old submit routine to call it later and overwrite HTMLFormElement.prototype.submit with my interception (modification) function.
The problem I am currently facing is that something drops the post variable post=Submit and calling the (old) submit function after the modification takes me back to the current page.
var intercept_complete = false;
window.addEventListener('submit', function (e) {
e.stopPropagation();
e.preventDefault();
interceptor(e);
}, true);
function interceptor_setup() {
HTMLFormElement.prototype.real_submit = HTMLFormElement.prototype.submit;
HTMLFormElement.prototype.submit = interceptor;
}
function interceptor(e) {
var frm = e ? e.target : this;
if (!interceptor_onsubmit(frm)) {
return false;
}
if (!intercept_complete) {
ModifyAndPost(frm);
return false;
} else {
HTMLFormElement.prototype.real_submit.apply(frm);
return true;
}
}
function interceptor_onsubmit(f) {
return !f.onsubmit || f.onsubmit();
}
function ModifyAndPost(f) {
var attrs = new Array('name', 'type', 'value');
for (var i = 0; i < f.elements.length; i++) {
for (var a = 0; a < attrs.length; a++) {
if (attrs[a] == 'name') {
if (f.elements[i][attrs[a]] == "message") {
var current_message = f.elements[i][attrs[a + 2]];
if (current_message.indexOf("hello") != -1) {
var do_replace = confirm("Detected hello, would you like to replace that with bye?");
if (do_replace) {
f.elements[i][attrs[a + 2]] = current_message.replace("hello", "bye");
}
}
}
}
}
}
PerformSubmit(f);
}
function PerformSubmit(f) {
HTMLFormElement.prototype.real_submit.apply(f);
}
interceptor_setup();
Basically the script works and modifies the post variables successfully but when calling HTMLFormElement.prototype.real_submit.apply(f); to submit the modified form the request is missing the Post=Submit variable and the submit fails.
I tried removing e.stopPropagation() and e.preventDefault() and then it worked sometimes, but still dropped that post variable once in a while.
Would be great if anyone could point me in the right direction on this one. ;)

How to click a Button with specific text?

I am trying to modify the script below to click a button that looks like this on a site:
<button id="checkPrice-02070" onclick="checkPrice(02070,null); return false;" class="orangeDark">
<span>check price</span>
</button>
I am using the code below. So far, the page seems to keep reloading; nothing else happens.
Any advice to someone new?
(function () {
window.addEventListener("load", function (e) {
clickConfirmButton()
}, false);
})();
function clickConfirmButton() {
var buttons = document.getElementsByTagName('button');
var clicked = false;
for (var index = 0; (index < buttons.length); index++) {
if (buttons[index].value == "check price") {
buttons[index].click();
clicked = true;
break;
}
}
if (!clicked) {
setTimeout("window.location.reload()", 300 * 1000);
}
}
A <button>s value is not the visible text. You'd want to search textContent.
However:
If that sample HTML is correct, you'd be better off searching for ids that start with checkPrice. See the code below.
Are you sure you want to reload if the button is not found? If it is added by AJAX this is not the best approach. See this answer.
Don't use setTimeout with a string (to evaluate) argument like that. See the code below.
You do not need to wrap the code in an anonymous function.
Anyway, this should work, given the sample HTML:
window.addEventListener ("load", clickConfirmButton, false);
function clickConfirmButton (zEvent) {
var button = document.querySelector ("button[id^='checkPrice']");
if (button) {
button.click ();
}
else {
setTimeout (function () { location.reload(); }, 300 * 1000);
}
}
To check the button text anyway, use:
function clickConfirmButton (zEvent) {
var buttons = document.querySelectorAll ("button[id^='checkPrice']");
var clicked = false;
for (var index = 0, numBtn = buttons.length; index < numBtn; ++index) {
if (/check price/i.test (buttons[index].textContent) ) {
buttons[index].click();
clicked = true;
break;
}
}
if (!clicked) {
setTimeout (function () { location.reload(); }, 300 * 1000);
}
}

Categories