Doesn't work click event on input by native js - javascript

I have html markup
<div id="site">
<header id="masthead">
<h1>Winery</h1>
</header>
Go to Shopping Cart <span></span>
<div id="content">
<div id="products">
<ul data-bind="foreach: products">
<li >
<div class="product-image">
<img data-bind="attr:{src: img}" alt="" />
</div>
<div class="product-description">
<h3 class="product-name"><span data-bind="text: name" /></h3>
<span class="product-id">ID <span data-bind="text: id" /></span></span>
<p class="product-price">€ <span data-bind="text: price" /></p>
<label for="qty-1">Quantity</label>
<span class="down" ></span>
<input type="text" data-bind="value: qty" class="qty" />
<span class="up"></span><br>
<input type="submit" value="Add to cart" class="btn" id="add" />
</div>
</li>
</ul>
</div>
<div id="browser">
</div>
</div>
and I want to hang a click event on input by native js, but event doesn't work on input
document.getElementById('add').onclick = function() {
document.getElementById('browser').remove();
}
If assign a handler through attribute html tag it's works
<input type="submit" value="Add to cart" class="btn" id="add" onclick="addToBlock()"/>

Make sure the document is loaded before assigning event handlers:
window.onload = function() {
document.getElementById('add').onclick = function() {
document.getElementById('browser').remove();
}
};
If you use jQuery, you could have it execute potentially earlier than with the above code, as it does not wait for images to be loaded:
$(function() {
$('#add').click(function () {
$('#browser').remove();
});
});
Executing it straight away, but by moving the code at the bottom of your document, like after the close of your body tag will work in most cases, although I have had deeply nested DOM hierarchies where this could fail:
...
</body>
<script>
document.getElementById('add').onclick = function() {
document.getElementById('browser').remove();
}
</script>
</html>
If you go for that last option, but want to add some precaution, but the code in a setTimeout with delay 0, which will make it run asynchronously allowing the DOM to be completely built:
setTimeout(function() {
document.getElementById('add').onclick = function() {
document.getElementById('browser').remove();
}
}, 0);

Problem was in ID, I have a few elements with the same ID and onclick work only for first element. I get by class
//get all input by class
var buttons = document.getElementsByClassName('btn');
//add onclick to each
for (var i = 0; i < buttons.length; i++) {
buttons[i].onclick = function() {
}
}

Related

Handling Events for Many Elements - optimalizing my solution

I am building a simple shop website (just to practise) and even though my current solution works, from what I read it is not optimal and could be improved through creating event listener on the parent element (here it would be cart-items instead of on every anchor element. The problem is that when I attach event handler to it, then only the first input is changed if there are two or more elements in the basket, no matter which increase button I click (the one from product one, two, ect.).
My question is: in such case is attaching event listener to the parent element really the best option, and if yes, how can I properly refactor my code to make increase/decrease button work on their closest input value, not only on the first one from the rendered list?
Below I attach my current JS Code:
const qtyBoxes = document.querySelectorAll('.cart-qty-box');
qtyBoxes.forEach((box) => {
const increase = box.querySelector('.increase');
const decrease = box.querySelector('.decrease');
const currQty = box.querySelector('.currQty');
increase.addEventListener('click', function(e) {
e.preventDefault();
currQty.value++;
$('#przelicz').click(); //uptades UI
});
decrease.addEventListener('click', function(e) {
e.preventDefault();
if(currQty.value > 0) {
currQty.value--;
}
$('#przelicz').click(); //updates UI
});
});
HTML:
<div class="cart-items">
///... Item 1 code ...
<div class="qty-box">
<div class="qty-ctl">
<a class="incr-btn decrease" data-action="decrease" href="#"></a>
</div>
<input id="qnt" class="qty currQty input-text" type="text" value="{$poz->count}"/>
<div class="qty-ctl">
<a class="incr-btn increase" data-action="increase" href="#"></a>
</div>
</div>
///... Item 2 code ...
<div class="qty-box">
<div class="qty-ctl">
<a class="incr-btn decrease" data-action="decrease" href="#"></a>
</div>
<input id="qnt" class="qty currQty input-text" type="text" value="{$poz->count}"/>
<div class="qty-ctl">
<a class="incr-btn increase" data-action="increase" href="#"></a>
</div>
</div>
</div>
Here I paste a link to the image if the description of what I am trying to build is not clear:
screenshot of basket
Yes, it is better to attach the event listener to the parent, because you have only one listener instead of multiple listeners (one for every button).
You can achieve this by checking to which box the target of the click-event (e.target) belongs:
const click_parent = e.target.closest('.qty-box');
and if it's an increase- or decrease-button, for example:
if (e.target.classList.contains('increase')) {
The rest works like in your snippet.
Working example:
document.querySelector('.cart-items').addEventListener('click', function(e) {
e.preventDefault();
const click_parent = e.target.closest('.qty-box');
const currQty = click_parent.querySelector('.currQty');
if (e.target.classList.contains('increase')) {
currQty.value++;
$('#przelicz').click(); //uptades UI
} else if (e.target.classList.contains('decrease')) {
if (currQty.value > 0) {
currQty.value--;
}
$('#przelicz').click(); //uptades UI
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="cart-items">
///... Item 1 code ...
<div class="qty-box">
<div class="qty-ctl">
<a class="incr-btn decrease" data-action="decrease" href="#">decrease</a>
</div>
<input id="qnt" class="qty currQty input-text" type="text" value="2" />
<div class="qty-ctl">
<a class="incr-btn increase" data-action="increase" href="#">increase</a>
</div>
</div>
///... Item 2 code ...
<div class="qty-box">
<div class="qty-ctl">
<a class="incr-btn decrease" data-action="decrease" href="#">decrease</a>
</div>
<input id="qnt" class="qty currQty input-text" type="text" value="3" />
<div class="qty-ctl">
<a class="incr-btn increase" data-action="increase" href="#">increase</a>
</div>
</div>
</div>

Dirty HTML or dirty jQuery for passing variables?

I have to pass variables to jQuery. There are two different approach as I see:
clean HTML, dirty jQuery:
<div class="itemContainer" data-id="1">
Item information
<input type="button" class="rename">
<input type="button" class="delete">
</div>
$('.rename').click(function() {
var id = $(this).parent().attr('data-id');
});
$('.delete').click(function() {
var id = $(this).parent().attr('data-id');
});
PROs:
clean, not redundant HTML,
CONS:
not so clean jQuery,
if the DOM structure changes, its hard to detect the errors, and it has to be fixed at 2 places
clean jQuery, dirty HTML:
<div class="itemContainer">
Item information
<input type="button" class="rename" data-id="1">
<input type="button" class="delete" data-id="1">
</div>
$('.rename').click(function() {
var id = $(this).attr('data-id');
});
$('.delete').click(function() {
var id = $(this).attr('data-id');
});
PROs:
clean jQuery,
works even DOM structure changes
CONS:
not so clean, redundant HTML,
which one would you prefer to use?
Your first HTML structure is the better implementation as it avoids repetition of the same data-id attribute.
With regard to the jQuery, you can use a single event handler by separating the selectors with a comma (,), and you can use closest() to find the required parent element. This is more robust as you can then change the HTML structure within that parent however you require and it will not break the JS logic, so long as the clicked element is still a child node. Finally, note that you should use data() to get/set data attributes where possible, not attr(). Try this:
$('.rename, .delete').click(function() {
var id = $(this).closest('.itemContainer').data('id');
console.log(id);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="itemContainer" data-id="1"> Item information
<input type="button" class="rename" value="Rename" />
<input type="button" class="delete" value="Delete" />
</div>
<div class="itemContainer" data-id="99"> Item information
<p>
Extra information...
<div class="another-child">
<input type="button" class="rename" value="Rename" />
<input type="button" class="delete" value="Delete" />
</div>
</p>
</div>
Put the selectors you want to add the listener to together in the selector string you use to add a .click listener to (separated by commas), and you don't need to repeat yourself at all:
$('.rename, .delete').click(function() {
var id = $(this).parent().attr('data-id');
console.log(id);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="itemContainer" data-id="1">
Item information
<input type="button" class="rename">
<input type="button" class="delete">
</div>
<div class="itemContainer" data-id="2">
Item information
<input type="button" class="rename">
<input type="button" class="delete">
</div>
You can combine the click event for both the element using Multiple Selector. You can specify any number of selectors to combine into a single result. This multiple expression combinator is an efficient way to select disparate elements.
clean jQuery, Clean HTML:
$('.rename, .delete').click(function() {
var id = $(this).parent().attr('data-id');
console.log(id);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="itemContainer" data-id="1">
Item information
<input type="button" class="rename">
<input type="button" class="delete">
</div>
I would use event delegation and a single data-attribute. You don't need jQuery for it. Added a button for restructuring the DOM to demonstrate that the handler keeps working after it.
(() => {
const evtHandler = evt => {
const origin = evt.target;
console.clear();
if (origin.id === "redoDOM") { return restructure(); }
if (origin.parentNode.classList.contains("itemContainer")) {
console.log(`${origin.classList} data-id: ${origin.parentNode.dataset.id}`);
}
};
document.addEventListener("click", evtHandler);
function restructure() {
if (!document.querySelector("#BttnContainer")) {
let container = document.createElement("div");
container.id = "BttnContainer";
container.innerHTML = `
<p>
div.itemContainer elements are wrapped.
Check if the button handler still works
</p>`;
Array.from(document.querySelectorAll(".itemContainer"))
.forEach(v => container.appendChild(v));
document.body.insertBefore(container, document.body.firstChild);
} else {
console.log("Already wrapped");
}
}
})();
#BttnContainer {
color: green;
}
<p>Click buttons to show data-id value of the surrounding element</p>
<div class="itemContainer" data-id="1">
Item information (1)
<button class="rename">rename</button>
<button class="delete">delete</button>
</div>
<div class="itemContainer" data-id="2">
Item information (2)
<button class="rename">rename</button>
<button class="delete">delete</button>
</div>
<p>
Click to wrap buttons in a new element
<button id="redoDOM">Restructure</button>
</p>

selecting all class within this in query

well right now I am doing something like this to find all textbox values which has the same class name.
function generalBottom(anchor) {
var sends = $('input[data-name^="noValues"]').map(function(){
$(this).attr('value',$(this).val());
return $(this).val();
}).get();
}
and i call this function on a onclick of submit button like generalBottom(this)
and I have something like as per my requirement
When I click submit button of User I call a general function passing this as a parameter, but the above code gives me the text values of client as well
["perfect", "hyperjack", "julie", "annoying", "junction", "convulated"], which is undesired, I want only ["annoying", "junction", "convulated"] using my anchor params.
How to do this via my this parameter, I thought to traverse through my tags using children(), parent() but I won't be knowing how many fields user have added as its all dynamic, user can add as many values(text boxes).
I tried this
1) $(anchor).find('.rightAbsNo')
2) $(anchor).find('input[data-name^="noValues"]')
3) $(anchor).find('.rightAbsNo').map(function () {
console.log($(this).find('. showNoButton')); })
None of this worked for me.
My html is somewhat like this, code
<div id="attach0" class="leftbottomno">
<div style="overflow: hidden" class="leftbottomAbsolute" id="">
<form>
<span class="absno"><input type="text" required=""
id="absdelete" data-inputclass="leftbottomAbsoluteNo_class"
value="" class="leftbottomabsolutenotest keys" data-value=""
style="margin-bottom:4px; color: #1c1c1c;"> </span>
<a onclick="addAbsoluteValues(this);" style="margin-left: 50px">
<i class="fa fa-plus-circle color-blue-grey-lighter"></i> </a>
</form>
<a onclick="deleteAbsoluteEmpty(this);> </a><br>
<div class="rightAbsNo" id="yesValueattach">
<div class="rightAbsNoValue">
<input type="text" id="nonattach" placeholder="values"
data-name="noValues" data-inputclass="absYes_class" value="annoying"
class="showNoButton showActivity value" data-value="">
<button type="button" onclick="generalBottom(this);">
<i class="glyphicon glyphicon-ok"></i></button>
</div>
</div>
<div class="rightAbsNo" id="yesValueattach">
<div class="rightAbsNoValue" id=""> <input type="text"
data-name="noValues" data-inputclass="absYes_class" subattribute=""
value="" class="showNoButton showActivity value" data-value="">
<button type="button" onclick="generalBottom(this);">
<i class="glyphicon glyphicon-ok"></i></button>
</div>
</div>
<div class="rightAbsNo" id="yesValueattach">
<div class="rightAbsNoValue" id="">
<input type="text" data-name="noValues"
data-inputclass="absYes_class" placeholder="values" subattribute=""
value="junction" class="showNoButton showActivity value"
data-value="" >
<button type="button" style="display: none;"
onclick="generalBottom(this);">
<i class="glyphicon glyphicon-ok"></i>
</button>
</div>
</div>
</div>
</div>
First of all, you need to define a container to the groups with something like :
<div class="container">input groups</div>
<div class="container">input groups</div>
and change <button type='submit'> to <button type='button'> to prevent submitting the form.
Then change your function to this:
function generalBottom(anchor) {
var all_inputs = $(anchor).parent(".container").find("input");
var input = $(anchor).siblings('input').first();
all_inputs.each(function(){
$(this).val(input.val());
});
}
Here's Jsfiddle
first $(anchor).siblings(input) find inputs
then go through each element from first step and return their value
function generalBottom(anchor) {
var input = 'input[data-name^="noValues"]'
var values = $.map($(anchor).siblings(input), (elemnt, index)=>{
return elemnt.value
})
$('#shows').val(values.join())
}
$('button').on('click',function(){
generalBottom(this)
})
hope this helps

Unable to attach Event to an Submit button in a form

On the following page "https://www.capgemini.com/new-ways-to-accelerate-innovation". there are multiple sections with "Expand" button and when you click on expand button a form gets exposed. the issue here is am not able to attach click event to the "Submit" button.
I have tried using addeventlistener but the event is not getting assigned.
How do I do that, please advise.
https://www.capgemini.com/new-ways-to-accelerate-innovation
Expand Button is in the below code.
<div class="exp_article-header-bg">
<div class="exp_article-header-inner">
<h2 class="exp_article-header-title">TechnoVision 2017</h2>
<div class="exp_article-header-author"></div>
<div class="exp_article-header-lead">
<p>
TechnoVision 2017 gives you a framework to create a new digital story to solve problems and grasp new opportunities. Our 37 technology building blocks will help you to navigate the technology maze and give a clear direction to your business.
</p>
</div>
<div class="exp_article-header-expand">
**
<div class="exp_link exp_link--white exp_link--expand">
<span class="exp_link-label">EXPAND</span>**
<span class="exp_button-arrow exp_button-arrow--down"></span>
</div>
</div>
</div>
</div>
Form gets exposed when you click the above Expand button. The Submit button is in the form as highlighted below.
<form accept-charset="UTF-8" method="post" action="https://go.pardot.com/l/95412/2017-08-09/2tfbfg" class="form" id="pardot-form">
<style type="text/css">
form.form p label {
color: #000000;
}
</style>
<p class="form-field email pd-text required ">
<label class="field-label" for="95412_59459pi_95412_59459">Email Address</label>
<input type="text" name="95412_59459pi_95412_59459" id="95412_59459pi_95412_59459" value="" class="text" size="30" maxlength="255" onchange="piAjax.auditEmailField(this, 95412, 59459, 44072473);">
</p>
<div id="error_for_95412_59459pi_95412_59459" style="display:none"></div>
<p style="position:absolute; width:190px; left:-9999px; top: -9999px;visibility:hidden;">
<label for="pi_extra_field">Comments</label>
<input type="text" name="pi_extra_field" id="pi_extra_field">
</p>
<!-- forces IE5-8 to correctly submit UTF8 content -->
<input name="_utf8" type="hidden" value="☃">
<p class="submit">
<input type="submit" accesskey="s" value="Submit Now">
</p>
<script type="text/javascript">
//<![CDATA[
var anchors = document.getElementsByTagName("a");
for (var i = 0; i < anchors.length; i++) {
var anchor = anchors[i];
if (anchor.getAttribute("href") && !anchor.getAttribute("target")) {
anchor.target = "_top";
}
}
//]]>
</script>
<input type="hidden" name="hiddenDependentFields" id="hiddenDependentFields" value="">
</form>
Have CSS display:none; for the element which needs to be expanded. when expand is clicked call a javascript function which checks if the element is hidden , if hidden change the CSS display: block;.
Check the below working code.
<body>
<div class="exp_article-header-bg">
<div class="exp_article-header-inner">
<h2 class="exp_article-header-title">TechnoVision 2017</h2>
<div class="exp_article-header-author"></div>
<div class="exp_article-header-lead"><p>TechnoVision 2017 gives you a framework to create a new digital story to
solve problems and grasp new opportunities. Our 37 technology building blocks will help you to navigate the
technology maze and give a clear direction to your business.</p>
</div>
<div class="exp_article-header-expand">
**
<div class="exp_link exp_link--white exp_link--expand">
<button onclick="myFunction()" class="exp_link-label">EXPAND</button>
**
<span class="exp_button-arrow exp_button-arrow--down" id="expandDiv"
style="color: #000066; background-color: gainsboro;display: none;">I Got Expanded</span></div>
</div>
</div>
</div>
</body>
Javascript function:-
<script>
function myFunction() {
var x = document.getElementById('expandDiv');
if (x.style.display === 'none') {
x.style.display = 'block';
} else {
x.style.display = 'none';
}
}
</script>
check on plnkr: https://plnkr.co/edit/MWKYxmV6Jk2eId3Owt2u?p=preview
where is ur form opening? if u're usingjquery, just target the form id and do .submit()
You're going to want to use the 'onsubmit' event listener, most likely with a preveninstead of a click event.
document.querySelector("#submit-button").addEventListener("submit", function(event) {
//your stuff here
event.preventDefault();
}, false);

jquery link not working after removeClass('disabled')

I have a script that disables links with a class "disabled"
//disabled links
$(document).ready(function() {
$(".disabled a").click(function() {
return false;
});
});
Additionally, I have a script that when the ".edit" button is clicked toggles the disabled state of the inputs in it's own form. It also does a removeClass('disabled') on any matching links in the form.
//toggle form edit
$("#edit").click(function(e) {
e.preventDefault();
$(this).closest("form").find("input").prop('disabled',false);
$(this).closest("form").find(".input-group-addon").removeClass('disabled');
$("#save").prop('disabled',false);
$("#edit").prop('disabled',true);
$(".alert").hide(400, "swing");
});
Then there is a script for adding and deleting input fields
//add input fields
$(".form-group").on('click', 'a.addInput', function() {
var original = $(this).closest(".input-group");
original.clone().insertAfter(original);
});
//remove input fields
$(".form-group").on('click', 'a.deleteInput', function() {
var original = $(this).closest(".input-group");
if($(this).closest(".form-group").children(".input-group").length > 1) {
original.remove();
}
});
HTML:
<form class="edit">
<div class="panel">
<div class="panel-heading">
<span><i class="fa fa-user" aria-hidden="true"></i> Basic Information</span>
<span class="pull-right"><input id="save" class="btn btn-success" type="submit" value="Save" disabled></span>
<span class="pull-right"><button id="edit" class="btn btn-default">Edit</button></span>
</div>
<div class="panel-body">
<div class="form-group">
<label for="email">Email</label>
<div class="input-group">
<input type="email" class="form-control" placeholder="Email" name="email" value="engelo#dingosoft.us" disabled required>
<div class="input-group-addon disabled"><span class="fa fa-plus"></span></div>
<div class="input-group-addon disabled"><span class="fa fa-minus"></span></div>
</div>
</div>
<div class="form-group">
<label for="phone">Phone</label>
<div class="input-group">
<input type="tel" class="form-control" pattern="\d{3}[\-]\d{3}[\-]\d{4}" placeholder="Format: 555-555-5555" name="phone" value="419-555-1212" disabled required>
<div class="input-group-addon disabled"><span class="fa fa-plus"></span></div>
<div class="input-group-addon disabled"><span class="fa fa-minus"></span></div>
</div>
</div>
</div>
</div>
</form>
The problem I am having is that when the class "disabled" is removed from the links, the links ('a.addInput') & ('a.deleteInput') do not function. What am I missing here?
Click handlers are attached to elements, not to selectors. So when you do this:
$(".disabled a").click(function() {
return false;
});
You are assigning that behavior to all elements which match at that moment (in this case, when the document loads). No matter what changes you make to the DOM after the fact, any elements which were matched when you invoked the above code will still have the above click handler.
One approach here could be to assign the click handler to a common unchanging parent, instead of to the elements themselves. By using .on() in this way, you can evaluate the selector dynamically when the click event happens instead of just once when the page loads. Something like this:
$(document).on("click", ".disabled a", function() {
return false;
});
Then the second selector (".disabled a") will be evaluated with each click. So if the DOM has changed such that an element no longer matches that selector, this click handler won't be used.
You need to add prevent the event.
$(".form-group").on('click', 'a.addInput', function(e) {
e.preventDefault();
var original = $(this).closest(".input-group");
original.clone().insertAfter(original);
});
//remove input fields
$(".form-group").on('click', 'a.deleteInput', function(e) {
e.preventDefault();
var original = $(this).closest(".input-group");
if($(this).closest(".form-group").children(".input-group").length > 1) {
original.remove();
}
});
or you can add a href="javascript:void(0);" to addInput and deleteInput.
I hope it will be help to achieve your goal...

Categories