Using click events on dynamically added DOM elements - javascript

Question: Why does it work when element is hard-coded into HTML but does not work when added dynamically via Jquery?
I am teaching my self Jquery within my self learning of javascript, and I am just creating a simple troubleshooting assistant app for the sake of learning.
I actually have my code posted here: https://repl.it/#jllrk1/OrganicBothRay.
The way I have it set up so far is the user clicks on the header block to begin, which is set up with a onetime click function to create a UL for some products at my job in which we provide IT Service.
I then am trying to be able to click each product in that list to pull troubleshooting walkthroughs for that specific product (it will guide the user based on what they click or enter).
For testing purposes I just tried having the background of the list item in which is clicked to change to red.
I cannot get this to work, or my console.log to fire telling me that the function is not getting called.
however, if I hard code in the ul into the html, using the same code for the click events, it works just fine.
Am I doing something wrong?
Just looking to gain a better understanding!
$(function () {
//*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_
//set up variables
//*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_
//var $liItems = $('.product li');
var $chief = $(".chiefblock");
var $container = $("#container");
var $this = $(this);
var $error = '';
var initList = function () {
console.log("initList initiated");
$container.append('<div class="product"><ul><li>TASC</li><li>TABE</li><li>Las Links</li><li>TerraNova</li><li>E-Direct</li></ul></div>');
$("p").text("Start by selecting a product");
}
var navItems = function (event){
console.log("navItems initiated");
var target = $(event.target);
if (target.is("li") ) {
target.css("background-color", "red" );
}
}
var nObject = function () {
$container.append('<div id = "tasc"><h2>Tasc</h2><p></p></div></div>');
$('#newItem').prepend('<h2>Item</h2>');
}
$('.chiefblock').one('click', initList)
//$('li').on('click', navItems) this i tried and does not work
$('#newObject').on('click', nObject)
$('ul').on('click', navItems)
//$liItems.on('click', navItems)this i tried and does not work
});

for dynamically added DOM elements use
$(document).on('click', '#element', function() {
console.log($(this))
})

Related

Troubleshooting Conditional Form

I'm new to Javascript and trying to build a conditional form using bootstrap and JQuery. I would really appreciate the help as I've been working most of the day on this to no avail.
I'm trying to show the div with id physician (and subsequent field) when the select field with the name AppointmentType has a value of Orthopedic or Rheumatology. Here is the link to the live form.
Here is my javascript:
$( document ).ready(function() { //wait until body loads
//Inputs that determine what fields to show
var appttype = $('#secureform input:select[name=AppointmentType]');
var physician = document.getElementById("physician");
appttype.change(function(){ //when the Appointment Type changes
var value=this.value;
physician.addClass('hidden'); //hide everything and reveal as needed
if (value === 'Orthopedic' || value === 'Rheumatology'){
physician.removeClass('hidden'); //show doctors
}
else {}
});
});
These lines are going to cause errors (which you should see in your devtools console):
var appttype = $('#secureform input:select[name=AppointmentType]'); // `input:select` is not a valid selector and causes the rest of the script to fail
physician.addClass('hidden'); // `addClass` is a jQuery method, so this should be `$(physician).addClass('hidden')`
physician.removeClass('hidden');// `removeClass` is a jQuery method, so this should be `$(physician).removeClass('hidden')`
Correct those lines and it should work.
If it helps, I would write it like this:
$( document ).ready(function () {
//Inputs that determine what fields to show
var apptType = $('#secureform select[name="AppointmentType"]'); // dropped the `input:` part
var physician = document.getElementById('physician');
physician.classList.add('hidden'); //hide this initially, outside the change handler
apptType.change(function () { // when the Appointment Type changes
var value = $(this).val().toLowerCase(); // leave case-sensitivity out of it.
var showables = [ // using an array as I prefer using a simple `indexOf` for multiple comparisons
'orthopedic',
'rheumatology',
];
var isShowable = showables.indexOf(value) > -1;
physician.classList.toggle('hidden', !isShowable);
// or, the jQuery equivalent:
// $(physician).toggleClass('hidden', !isShowable);
});
});
Your selector is incorrect:
var appttype = $('#secureform input:select[name=AppointmentType]');
// this should be
var appttype = $('#secureform select[name=AppointmentType]');
Furthermore you are mixing jquery with vanilla JS. Your are using vanilla js here
var physician = document.getElementById("physician");
Physician is now a dom object and not a jquery object. You should use this instead:
var physician = $("#physician");
Additionally you should replace
var value=this.value;
with this
var value= $(this).val();

Value from HTML to another via registered element

I'm totally newbie when talking about HTML, so this can be obvious to you, but I hope you can help me.
We have a top-menu.html which have some dropdown menus. One of these menus is a checkbox menu.
I have to get the value (and the change event of it) in another HTML, the index.html.
There's a JS code registering an element that can be used by index.html. Still, I don't know how to retrieve the checkbox value.
top-menu.html JS:
function build_component() {
var template = (document._currentScript || document.currentScript)
.ownerDocument.querySelector('#top-menu-template');
var topMenu = Object.create(HTMLElement.prototype);
topMenu.createdCallback = function() {
// import template into
var clone = document.importNode(template.content, true);
this.appendChild(clone);
};
document.registerElement('page-top-menu', { prototype: topMenu });
}
Ok, so I can use <page-top-menu> in index.html. How to get checkbox.checked value now?
Using jquery you can easily do this
html:
<input type="checkbox" value="0" class="check1">
jquery: You can use local storage to save your value
$('.check1').on('change',function(){
var val1 = $(this).val();
localStorage.setItem("value", val1);
alert(val1);
}
To retrieve that you can use following code remove it if you don't want any more
var valnew = localStorage.getItem("value");
alert(valnew);
localStorage.removeItem("value");

Making the search field (with results) disappear when clicking outside on Ipad

I have two html elements as follows :
A input element whose class is "fts-input". This input serves as a search box.
A div container, containing all the list of results, whose class is "dropdown-items-wrapper"
I made a code who worked in all browsers except Safari, that made the search results disappear when clicking outside of the search field, or outside of the search results. This code is :
var ftsInput = $('.fts-input');
var dropDownList = $('.dropdown-items-wrapper');
function closeSearchWhenClickingElsewhere(event, dropDown) {
var clickedElement = event.target;
if (!clickedElement) return;
var elementClasses = clickedElement.classList;
var clickedOnSearchOrResults = elementClasses.contains('fts-input') ||
elementClasses.contains('dropdown-items-wrapper');
if(!clickedOnSearchOrResults) {
dropDown.fadeOut('slow');
}
}
$document.on('click', (e) => {
this.closeSearchWhenClickingElsewhere(e, dropDownList);
});
But this code seems to not work on Ipad (iOs Safari). Do you have a clue why it isn't working ?
You have to wrap around document within the $ jQuery symbol.
So your code becomes,
$(document).on('click', (e) => {
this.closeSearchWhenClickingElsewhere(e, dropDownList);
});
Alternatively, you can assign as this:
$document = $(document);
Created a fiddle for you which works fine on Safari 10: https://jsfiddle.net/1ymrtcbf/

exchanging values in a select list with jQuery

I'm trying to swap select option values with jQuery when a links clicked, at the moment its just resetting the select when the links clicked, not sure what's going wrong?:
jQuery:
$(function () {
$("#swapCurrency").click(function (e) {
var selectOne = $("#currency-from").html();
var selectTwo = $("#currency-to").html();
$("#currency-from").html(selectTwo);
$("#currency-to").html(selectOne);
return false;
});
});
JS Fiddle here: http://jsfiddle.net/tchh2/
I wrote it in a step-by-step way so it is easier to understand:
$("#swapCurrency").click(function (e) {
//get the DOM elements for the selects, store them into variables
var selectOne = $("#currency-from");
var selectTwo = $("#currency-to");
//get all the direct children of the selects (option or optgroup elements)
//and remove them from the DOM but keep events and data (detach)
//and store them into variables
//after this, both selects will be empty
var childrenOne = selectOne.children().detach();
var childrenTwo = selectTwo.children().detach();
//put the children into their new home
childrenOne.appendTo(selectTwo);
childrenTwo.appendTo(selectOne);
return false;
});
jsFiddle Demo
Your approach works with transforming DOM elements to HTML and back. The problem is you lose important information this way, like which element was selected (it is stored in a DOM property, not an HTML attribute, it just gives the starting point).
children()
detach()
appendTo()
That happens because you remove all elements from both <select> fields and put them as new again. To make it working as expected you'd better move the actual elements as follows:
$("#swapCurrency").click(function(e) {
var options = $("#currency-from > option").detach();
$("#currency-to > option").appendTo("#currency-from");
$("#currency-to").append(options);
return false;
});
DEMO: http://jsfiddle.net/tchh2/2/
You are replacing the whole HTML (every option) within the <select>. As long as each select has the same amount of options and they correspond to each other, you can use the selected index property to swap them:
$("#swapCurrency").click(function (e) {
var selOne = document.getElementById('currency-from'),
selTwo = document.getElementById('currency-to');
var selectOne = selOne.selectedIndex;
var selectTwo = selTwo.selectedIndex;
selOne.selectedIndex = selectTwo;
selTwo.selectedIndex = selectOne;
return false;
});
JSFiddle

Convert jQuery script to standalone javascript

Is it possible for this jQuery code to run as a standalone javascript? This is the only javascript I'd like to use in my project so I'd prefer not to load the entire jquery library just for this 1k script.
//chris coyier's little dropdown select-->
$(document).ready(function() {
//build dropdown
$("<select />").appendTo("nav.primary");
// Create default option "Go to..."
$("<option />", {
"selected": "selected",
"value" : "",
"text" : "Go to..."
}).appendTo("nav select");
// Populate dropdowns with the first menu items
$("div#brdmenu ul li a").each(function() {
var el = $(this);
$("<option />", {
"value" : el.attr("href"),
"text" : el.text()
}).appendTo("nav.primary select");
});
//make responsive dropdown menu actually work
$("nav.primary select").change(function() {
window.location = $(this).find("option:selected").val();
});
});
I've tried to find previous answers but most questions are for converting to jquery and not vice-versa :)
It is obviously possible to do those things in straight javascript, but there is no way (that I am aware of) to automatically do that conversion. You will have to go through line by line and do the conversion yourself.
Here is something similar to market's answer. I'm assuming you want to get all the links in UL elements inside the brdmenu element. If you only want the first link on the LI elements, just adjust the loop that gets them.
Also, this is not a good idea. Using select elements for links went out of fashion a long time ago, users much prefer real links. Also, when navigating the options using cursor keys in IE, a change event is dispatched every time a different option is selected so users will only get to select the next option before being whisked away to that location. Much better to add a "Go" button that they press after selecting a location.
The main change is to use an ID to get the nav.primary element, which I assume is a single element that you should be getting by ID already.
function doStuff() {
function getText(el) {
return el.textContent || el.innerText;
}
var div, link, links, uls;
// Use an ID to get the nav.primary element
var navPrimary = document.getElementById('navPrimary');
// Create select element and add listener
var sel = document.createElement('select');
sel.onchange = function() {
if (this.selectedIndex > 0) { // -1 for none selected, 0 is default
window.location = this.value;
}
};
// Create default option and append to select
sel.options[0] = new Option('Go to...','');
sel.options[0].setAttribute('selected','');
// Create options for the links inside #brdmenu
div = document.getElementById('brdmenu');
uls = div.getElementsByTagName('ul');
for (var i=0, iLen=uls.length; i<iLen; i++) {
links = uls[i].getElementsByTagName('a');
for (var j=0, jLen=links.length; j<jLen; j++) {
link = links[j];
sel.appendChild(new Option(getText(link), link.href));
}
}
// Add select to page if found navPrimary element
if (navPrimary) {
navPrimary.appendChild(sel);
}
}
window.onload = doStuff;
It's only 28 lines of actual code, which is only 10 more than the original, doesn't require any supporting library and should work in any browser in use (and most that aren't).
Have a go with this.
The one thing I'm leaving out is $(document).ready, but there are a number of solutions for that available on stackoverflow. It's a surprisingly large amount of code!
But the other functionality:
// build the dropdown
var selectElement = document.createElement('select');
var primary = document.getElementsByClassName('primary')[0];
// create a default option and append it.
var opt = document.createElement('option');
var defaultOpt = opt.cloneNode(false);
defaultOpt.selected = true;
defaultOpt.value = "";
defaultOpt.text = "Go to...";
selectElement.appendChild(defaultOpt);
// populate the dropdown
var brdmenuUl = document.getElementById('brdmenu').getElementsByTagName('ul')[0];
var listItems = brdmenuUl.getElementsByTagName('li');
for(var i=0; i<listItems.length; i++){
var li = listItems[i];
var a = li.getElementsByTagName('a')[0];
var newOpt = opt.cloneNode(false);
newOpt.value = a.href;
newOpt.text = a.innerHTML;
selectElement.appendChild(newOpt);
}
// now listen for changes
if(selectElement.addEventListener){
selectElement.addEventListener('change', selectJump, false);
}
else if(selectElement.attachEvent){
selectElement.attachEvent('change', selectJump);
}
function selectJump(evt){
window.location = evt.value;
}
primary.appendChild(selectElement);​
some notes!
We're not looking specifically for nav.primary, we're just finding the first occurrence of something with class .primary. For best performance, you should add an ID to that element and use getElementById instead.
Similarly with the lists in #brdmenu, we look for the first UL, and the first A inside each LI. This isn't exactly what the jQuery does, if you are going to need to iterate more than one UL inside #brdmenu you can use another for loop.
I think that should all work though, there's a fiddle here

Categories