Simulate Click with Vanilla Javascript - javascript

I have a SELECT element that I am replacing with a dropdown. I have successfully created the dropdown from the SELECT and child OPTION elements, but I need to add a click event.
This click event would be as such:
If LI is clicked, also click corresponding OPTION.
This is because Woocommerce must have some JS or PHP working where depending on the option, it shows stock status and variable amount. As such, I assume that the click event will also bind the OPTION value to the form for adding to cart.
I have this JS code:
window.onload = main;
function main(){
var select = document.querySelector('.turnintodropdown');
var selsOpts = document.querySelector('.turnintodropdown option');
var selsLi = document.querySelector('.selectOption');
var trigger = document.createElement('a');
var openDropdown = 'dropdownVisible';
var closeDropdown = 'dropdownHidden';
(function addDropdown() {
if(select) {
var selsCon = document.createElement('div');
var selsOuter = document.createElement('ul');
selsCon.classList.add('selectContainer');
selsOuter.classList.add('selectOuter');
select.parentNode.insertBefore(selsCon, select);
selsCon.appendChild(selsOuter);
for(var i=0; i<select.length; i++) {
if(select.childNodes[i].classList.contains('enabled') || select.childNodes[i].innerHTML == '- -'){ // Select First Child and <option> Tags with Enabled Class
// Create New Elements
var optsNew = document.createElement('li');
optsNew.innerHTML = select.childNodes[i].text;
optsNew.classList.add('selectOption');
// Set Attributes to New Elements
if(optsNew.innerHTML !== '- -') {
optsNew.setAttribute('value', select.childNodes[i].text);
}
else {
void(0);
}
optsNew.click(clickFunc);
// Add New LI <option> to UL <container>
selsOuter.appendChild(optsNew);
// Click Events
console.log(select.firstChild);
}
}
var clickFunc = function() {
select.click();
};
select.style.display = 'none';
}
})();
}
Any help would be greatly appreciated.
Regards
Michael

I was a bit long to answer, sorry.
the function was originally taken from this webpage and not modified, it is supposed to work with most old browsers. I actually tested on last versions of Firefox / Chrome / Opera / Edge with success.
The version which handles all types of events is more complicated because you have to make cases for standard events to process them by type (not all are MouseEvents).
It also supports the inline functions, with onclick= in the html tag, and works also for events set with jQuery.
Note that if you want the same support for old broswers, you'll have to differentiate cases for the setting of events too, the modern addEventListener being not supported by all.
function fireClick(node){
if ( document.createEvent ) {
var evt = document.createEvent('MouseEvents');
evt.initEvent('click', true, false);
node.dispatchEvent(evt);
} else if( document.createEventObject ) {
node.fireEvent('onclick') ;
} else if (typeof node.onclick == 'function' ) {
node.onclick();
}
}
used like this for example:
fireClick(document.getElementById("myId"));

Vanilla JS (without jQuery)
/**
* Simulate a click event.
* #public
* #param {Element} elem the element to simulate a click on
*/
var simulateClick = function (elem) {
// Create our event (with options)
var evt = new MouseEvent('click', {
bubbles: true,
cancelable: true,
view: window
});
// If cancelled, don't dispatch our event
var canceled = !elem.dispatchEvent(evt);
};
To use it, call the function, passing in the element you want to simulate the click on.
var someLink = document.querySelector('a');
simulateClick(someLink);
src / full article: https://gomakethings.com/how-to-simulate-a-click-event-with-javascript/

Related

Converting jQuery Code to detect clicks on links with a specific class to Native JavaScript

ok so I can achieve what I am looking to do using jQuery very easily using the following code:
<script type="text/javascript">
// <![CDATA[
$('.pnTrig').on('click', function(e){
e.preventDefault();
var id = $(this).attr('href').split("_").pop(); // get last character of string
console.log(id); // check correct character is returned
P7_TP3ctrl('p7TP3_1',id); // controls to show accordian panels
});
// ]]>
</script>
What I would like is for someone to show me how to convert this jQuery code to native JavaScript please.
Here is a documented vanilla Javascript version.
function clickHandler(event) {
// execute preventDefault() if don't want the link to be followed (default browser behavior)
event.preventDefault();
// get the event target (what `this` would refer to in jQuery)
var target = event.target;
// same as before
var id = target.href.split('_').pop();
// same as before
P7_TP3ctrl('P7_TP3', id);
}
// get all elements with `pnTrig` class
var triggers = document.querySelectorAll('.pnTrig');
// apply the event handler to all matching elements
for (var i = 0; i < triggers.length; i++) {
// attach the event handler (don't define the event handling function here)
triggers[i].addEventListener('click', clickHandler, false);
}
function P7_TP3ctrl(label, id) {
console.log("Clicked id: ", id);
}
Link One
Link Two

Call script from another script

In HTML5 I have a dropdown menu . When choosing different options I hide or show different parts of my page. Here is that script:
document
.getElementById('target')
.addEventListener('change', function () {
'use strict';
var vis = document.querySelector('.vis'),
target = document.getElementById(this.value);
if (vis !== null) {
vis.className = 'inv';
}
if (target !== null ) {
target.className = 'vis';
}
});
However what I want to do now, in another script is to preload an option from the dropdown. I can do it easily with this script:
setSelectedIndex(document.getElementById('target'),'content_1');
function setSelectedIndex(s, valsearch)
{
// Loop through all the items in drop down list
for (i = 0; i< s.options.length; i++)
{
if (s.options[i].value == valsearch)
{
// Item is found. Set its property and exit
s.options[i].selected = true;
break;
}
}
return;
}
This is where my problem comes up, my dropdow will get the value I want, but the part that I want to be shown when choosing that option won't come up.
That is because change events need to happen from the browser.
When the user commits the change explicitly (e.g. by selecting a value
from a 's dropdown with a mouse click, by selecting a date
from a date picker for , by selecting a file in the
file picker for , etc.);
If your using Jquery you can:
$("#id").val("value").trigger('change');
or you can use javascript if your not worried about building the event object:
if ("createEvent" in document) {
var evt = document.createEvent("HTMLEvents");
evt.initEvent("change", false, true);
element.dispatchEvent(evt);
}
else
element.fireEvent("onchange");
I would recommend moving your anonymous onchange function into a named function that you can call once onload, and again onchange.
Here is the function I wrote:
function setContent(id) {
//get the current visible content
var vis = document.querySelector('.vis');
//get the target element by id
var target = document.getElementById(id);
//make current vis element inv
if (vis) vis.className = "inv";
//make target element vis
if (target) target.className = 'vis';
}
and a fiddle
edited: got rid of querySelectorAll to stick closer to OP original code and updated fiddle. clarified and commented code.
The problem you have is changing a vale or the selected value of an input with JavaScript does not trigger any change event. So you would need to manually trigger the event.
function setSelectedIndex(s, valsearch)
{
// Loop through all the items in drop down list
for (i = 0; i< s.options.length; i++)
{
if (s.options[i].value == valsearch)
{
// Item is found. Set its property and exit
s.options[i].selected = true;
break;
}
}
//Setting the selected value with JavaScript does not trigger the change event so you need to manually trigger the change event
if ("createEvent" in document) {
var evt = document.createEvent("HTMLEvents");
evt.initEvent("change", false, true);
s.dispatchEvent(evt);
} else {
s.fireEvent("onchange");
}
return;
}

Check the form element triggered at onclick event

I have a js function inside a web page that trap the position of the click on it. I had to implement it in a way that is recognized if the page contain a form element, and, if so, do a check as to whether that the click that I'm recording is made on one at random form element or not.
I got up to check the form and to learn its elements, but I do not know how to check if the click is made ​​on a single element:
$('*').on('mousedown', function (e) {
// make sure the event isn't bubbling
if (e.target != this) {
return;
}
// do something with the click somewhere
// for example, get the coordinates:
x = e.pageX;
y = e.pageY;
pa = $(location).attr('href');
//Window dimension
var width = $(window).width();
//var width = $getWidth();
var height = $(window).height();
//Check if page contain a form
var elementF = document.querySelectorAll('form');
var fname = '';
var elements = '';
for (var i=0; i<elementF.length; i++){
fname = elementF[i].id;
elements = document.forms[fname].elements;
for (x=0; x<elements.length; x++){
//Now i need to check if element is clicked or not
}
}
What you're doing here is binding a mousedown event to every element on the page. This will be resource intensive and should not be necessary. Also, since it's bound everywhere, the if (e.target !== this){ return; } does prevent it from firing a million times whenever you mousedown on something, but also prevents it from bubbling. Just let it bubble and use e.target and e.currentTarget to tell stuff apart. There shouldn't be any reason to do $('*').on("mousedown")
Why can't you just do this?
$("form").on("click", function(e){
// e.currentTarget will be the form element capturing the click
console.log( $(e.currentTarget).html() );
// e.target will be whatever element you clicked on
// so you can do whatever you want with it
console.log( $(e.target).text() );
// All your handler code here
});
Some possibly helpful stuff
http://api.jquery.com/event.currenttarget/
Is there a difference between $(e.currentTarget) and $(this)?
http://learn.jquery.com/events/event-delegation/
Try
$('*').on('mousedown', function (e) {
var elementClicked = e.target.nodeName;
console.log("element: " + elementClicked)
})

Preventing blur when user clicks on specific div not working in Firefox

I am using jquery to keep the focus on a text box when you click on a specific div. It works well in Internet Explorer but not in Firefox. Any suggestions?
var clickedDiv = false;
$('input').blur(function() { if (clickedDiv) { $('input').focus(); } });
$('div').mousedown(function() { clickedDiv = true; })
.mouseup(function() { clickedDiv = false });
Point to note: the focus() method on a jquery object does not actually focus it: it just cases the focus handler to be invoked! to actually focus the item, you should do this:
var clickedDiv = false;
$('input').blur( function() {
if(clickeddiv) {
$('input').each(function(){this[0].focus()});
}
}
$('div').mousedown(function() { clickedDiv = true; })
.mouseup(function() { clickedDiv = false });
Note that I've used the focus() method on native DOM objects, not jquery objects.
This is a direct (brute force) change to your exact code. However, if I understand what you are trying to do correctly, you are trying to focus an input box when a particular div is clicked when that input is in focus.
Here's my take on how you would do it:
var inFocus = false;
$('#myinput').focus(function() { inFocus = true; })
.blur(function() { inFocus = false; });
$('#mydiv').mousedown(function() {
if( inFocus )
setTimeout( function(){ $('#myinput')[0].focus(); }, 100 );
}
Point to note: I've given a timeout to focussing the input in question, so that the input can actually go out of focus in the mean time. Otherwise we would be giving it focus just before it is about to lose it. As for the decision of 100 ms, its really a fluke here.
Cheers,
jrh
EDIT in response to #Jim's comment
The first method probably did not work because it was the wrong approach to start with.
As for the second question, we should use .focus() on the native DOM object and not on the jQuery wrapper around it because the native .focus() method causes the object to actually grab focus, while the jquery method just calls the event handler associated with the focus event.
So while the jquery method calls the focus event handler, the native method actually grants focus, hence causing the handler to be invoked. It is just unfortunate nomenclature that the name of this method overlaps.
I resolved it by simply replace on blur event by document.onclick and check clicked element if not input or div
var $con = null; //the input object
var $inp = null; // the div object
function bodyClick(eleId){
if (eleId == null || ($inp!= null && $con != null && eleId != $inp.attr('id') &&
eleId != $con.attr('id'))){
$con.hide();
}
}
function hideCon() {
if(clickedDiv){
$con.hide();
}
}
function getEl(){
var ev = arguments[0] || window.event,
origEl = ev.target || ev.srcElement;
eleId = origEl.id;
bodyClick(eleId);
}
document.onclick = getEl;
hope u find it useful

How to dynamically reconfigure Drupal's jQuery-based autocomplete at runtime?

Drupal has a very well-architected, jQuery-based autocomplete.js. Usually, you don't have to bother with it, since it's configuration and execution is handled by the Drupal form API.
Now, I need a way to reconfigure it at runtime (with JavaScript, that is). I have a standard drop down select box with a text field next to it, and depending what option is selected in the select box, I need to call different URLs for autocompletion, and for one of the options, autocompletion should be disabled entirely. Is it possible to reconfigure the existing autocomplete instance, or will I have to somehow destroy and recreate?
Have a look at misc/autocomplete.js.
/**
* Attaches the autocomplete behavior to all required fields
*/
Drupal.behaviors.autocomplete = function (context) {
var acdb = [];
$('input.autocomplete:not(.autocomplete-processed)', context).each(function () {
var uri = this.value;
if (!acdb[uri]) {
acdb[uri] = new Drupal.ACDB(uri);
}
var input = $('#' + this.id.substr(0, this.id.length - 13))
.attr('autocomplete', 'OFF')[0];
$(input.form).submit(Drupal.autocompleteSubmit);
new Drupal.jsAC(input, acdb[uri]);
$(this).addClass('autocomplete-processed');
});
};
The input's value attribute is used to create ACDB, which is a cache of values for that autocomplete path (uri). That is used in the Drupal.jsAC function to bind the element's keydown, keyup and blur events with triggers the autocomplete ajax operation (which caches its values in the ACDB object for that element), opens popups, etc.
/**
* An AutoComplete object
*/
Drupal.jsAC = function (input, db) {
var ac = this;
this.input = input;
this.db = db;
$(this.input)
.keydown(function (event) { return ac.onkeydown(this, event); })
.keyup(function (event) { ac.onkeyup(this, event); })
.blur(function () { ac.hidePopup(); ac.db.cancel(); });
};
What you'll need to do is change the input's value and also reattach the behavior. You'll reattach the behavior by removing the '.autocomplete-processed' class on the autocomplete text field input element and then call Drupal.attachBehaviors(thatInputElement).
This may not work. Things can go very badly if you attach the same behavior to the same element over and over again. It may be more sensible to create different autocomplete fields and simply hide and show them based on the value of the select. This would still require calling Drupal.attachBehaviors when you hide and display the widget, but the same behavior would remain attached if the switch happened more than once, and you wouldn't risk attaching the same behavior to the element multiple times.
Well, for reference, I've thrown together a hack that works, but if anyone can think of a better solution, I'd be happy to hear it.
Drupal.behaviors.dingCampaignRules = function () {
$('#campaign-rules')
.find('.campaign-rule-wrap')
.each(function (i) {
var type = $(this).find('select').val();
$(this).find('.form-text')
// Remove the current autocomplete bindings.
.unbind()
// And remove the autocomplete class
.removeClass('form-autocomplete')
.end()
.find('select:not(.dingcampaignrules-processed)')
.addClass('dingcampaignrules-processed')
.change(Drupal.behaviors.dingCampaignRules)
.end();
if (type == 'page' || type == 'library' || type == 'taxonomy') {
$(this).find('input.autocomplete')
.removeClass('autocomplete-processed')
.val(Drupal.settings.dingCampaignRules.autocompleteUrl + type)
.end()
.find('.form-text')
.addClass('form-autocomplete');
Drupal.behaviors.autocomplete(this);
}
});
};
This code comes from the ding_campaign module. Feel free to check out the code if you need to do something similar. It's all GPL2.
it should be as simple as dinamically change the "value" of the "hidden" autocomplete
input element that comes aside autocomplete form fields. ie.
$('select#myelement').bind('change', function(e) {
if (/* something */) {
$('input#myelement-autocomplete').attr('value', '/mycustom/path');
}
});
Working solution for Drupal 5
/*
* Błażej Owczarczyk
* blazej.owczarczyk#gmail.com
*
* Name: Autocomplete City Taxonomy
* Description: Hierarchical city selecting (province select and city autocomplete)
*/
var Act = Act || {};
Act.init = function () {
$('select.act-province').change(Act.provinceChange); // select with top taxonomy terms
}
/*
* Change event of select element
*/
Act.provinceChange = function () {
var context = $(this).parent().parent();
var currentTid = $(this).val();
Act.rewriteURI(context, currentTid);
Act.unbind();
Drupal.autocompleteAutoAttach();
};
/*
* Changes the value of hidden autocomplete input
*/
Act.rewriteURI = function (context, newTid) {
var tempArray;
tempArray = $('.autocomplete', context).val().split('/');
tempArray.pop();
tempArray.push(newTid);
$('.autocomplete', context).val(tempArray.join('/'));
};
/*
* Prevents muliple binding of the same events
*/
Act.unbind = function () {
$('.form-autocomplete').unbind().parents('form').unbind('submit');
};
$(document).ready(Act.init);

Categories