Cant call function after creating element. jQuery - javascript

So my target is to run a function when click on "li" but number of li depends from user choice...
Function work when i create exactly amount of li elements...
$("li").click(function(){
var e = $(this).attr("id");
alert(e);});
li{
border: 1px solid black;
cursor: pointer;
display: inline-block;
padding:5px 10px 5px 10px;
}
ul{
display: inline-block;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul id="questlist">
<li id='quest1'>1</li>
<li id='quest2'>2</li>
<li id='quest3'>3</li>
<li id='quest4'>4</li>
<li id='quest5'>5</li>
<li id='quest6'>6</li>
<li id='quest7'>7</li>
<li id='quest8'>8</li>
<li id='quest9'>9</li>
<li id='quest10'>10</li>
</ul>
But when i would like to create list from user choice i cant run function already try:
function countList(ListX){
for(k=0;k<ListX; k++){
ke = k+1;
node = document.createElement("LI");
node.setAttribute("id", "quest"+ke);
textnode = document.createTextNode(ke);
node.appendChild(textnode);
document.getElementById("questlist").appendChild(node);
}}
and
function countList(ListX){
for(k=0;k<ListX; k++){
ke = k+1;
document.getElementById("questlist").innerHTML += "<li id='quest"+ke+"'>"+ke+"</li>";
}}
var ListX = 10;
function countList(ListX){
for(k=0;k<ListX; k++){
ke = k+1;
node = document.createElement("LI");
node.setAttribute("id", "quest"+ke);
textnode = document.createTextNode(ke);
node.appendChild(textnode);
document.getElementById("questlist").appendChild(node);
}}
countList(ListX);
$("li").click(function(){
var e = $(this).attr("id");
alert(e);});
li{
border: 1px solid black;
cursor: pointer;
display: inline-block;
padding:5px 10px 5px 10px;
}
ul{
display: inline-block;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul id="questlist"></ul>
Both of function create me "li" elements with expected id, or at least after i open a console and analyze each "li" element i can see expected id.
Need

Use the on method instead of click handler on li element, like this
$('body').on('click', 'li', function() {
var e = $(this).attr("id");
alert(e);
});
Rest of your code is fine, just use above code instead of $("li").click..
Working Demo here

The official documentation says:
Event handlers are bound only to the currently selected elements; they
must exist at the time your code makes the call to .on()
What you need is to make sure the actual element exist at the time you attaching the event. So if your li tags doesn't exist at the time of attaching event, the .click() method will fail. You next choice is to bind the event on one of the parents (in your case it would be the UL tag, like so:
$("#questlist").on("click", "li", function() {
var e = $(this).attr("id");
alert(e);
})
Also from now on use .on() method, it attaches event handlers to a selected set of elements and it works perfectly for elements present on the page.

Related

JavaScript: Added EventListener to Element - But when I click on it, the Target is a Nested Element [duplicate]

In MDN Event.target reference there is an example about implementing event delegation:
Event delegation example
// Assuming there is a 'list' variable containing an instance of an
// HTML ul element.
function hide(e) {
// Unless list items are separated by a margin, e.target should be
// different than e.currentTarget
e.target.style.visibility = 'hidden';
}
list.addEventListener('click', hide, false);
// If some element (<li> element or a link within an <li> element for
// instance) is clicked, it will disappear.
// It only requires a single listener to do that
Unclear part of the example
What i don't understand in the example is this comment:
// Unless list items are separated by a margin, e.target should be
// different than e.currentTarget
Question
How can margin on <li> elements make difference between Event.target and Event.currentTarget?
Have in mind what makes event.target different than event.currentTarget as stated in MDN Event.currentTarget reference:
I think the point is that if there's no margin, then it'll be impossible to click directly on the ul since the li elements will entirely fill its space.
If there is a margin, then it'll at least be possible to click the ul, in which case event.target and event.currentTarget will be the same.
function hide(e) {
document.querySelector("pre").textContent += 'e.target = ' + e.target.nodeName + ", e.currentTarget = " + e.currentTarget.nodeName + "\n";
}
document.querySelector("#list").addEventListener('click', hide, false);
ul {
border: 2px solid orange;
}
li {
padding: 10px;
color: blue;
margin: 30px;
border: 1px dashed blue;
}
<pre></pre>
<ul id="list">
<li>click me
<li>click me
<li>click me
</ul>

Is There Any Way To Implement Multiple class Id's in a single javascript function?

I have listed 4 elements in div class main ul li.
I want to hide these element when a button is clicked. I tried it with below code but only first <li> element is working
function toggle(id){
var e = document.getElementById(id);
if(e.style.display == 'none'){
e.style.display = 'block';
} else {
e.style.display = 'none';
}
}
.main ul {
display: table;
padding: 2px 20px;
}
.main ul li {
display: none;
}
<div class="main">
<ul>
<li>one</li>
<li>two</li>
<li>three</li>
</ul>
</div>
<button class="btn" onclick="toggle(li)">hide</button>
How can I fix it?
You can use jquery for hide and show purpose as below. Initially, you apply display none property to your li element through css. It will hide elements on page load.
<div class="main">
<li>one</li>
<li>two</li>
<li>three</li></ul></div>
<button class="btn" onclick="toggle()">hide</button>
.main ul{
display:table;
padding:2px 20px 2px 20px;
}
.main ul li{
display:none;
}
function toggle(id) {
var e = $('ul')
if($('ul').is(":visible"))
{
$('ul').hide();
}
else
{
$('ul').show();
}
}
Vanilla solution
demo and code example
li is an tag, not id. So you have to get elements by tag using e.g.
var elements = document.getElementsByTagName()
Now you can't use elements directly because it's an array of elements. So you have iterate every element in an array e.g. using for loop like I did. Then you assign current element to the var, in my case element and create if statement as you do did it before.
Your code won't work because you are passing in the ul in the function which doesn't make any sense, That's why it won't work.
I have modified your code to the easiest way possible
var btn = document.querySelector('button');
var ul = document.querySelector('ul');
btn.onclick = function(){
ul.classList.toggle('newClass');
}
.newClass {
display: none;
}
<div class="main">
<ul>
<li>one</li>
<li>two</li>
<li>three</li>
</ul>
</div>
<button class="btn">hide</button>
Hope this helps.

give an onclick function to be executed to every element with a certain class

How would i go about making something like this - i have multiple elements with a certain class and i would like this to happen:
element1 - onclick fires someFunction(13);
element2 - onclick fires someFunction(27);
element3 - onclick fires someFunction(81);
i am loading these elements in dynamically so i can't put it manually into my js file. I also can't give them an onclick as i load them with php.
I am looking for a purely js answer so please no jQuery.
function setMyHandler(){
var elements = document.getElementsByClassName('someClass');
for(var i = 0; i < elements.length; i++){
elements[i].onclick = function(){};
}
}
But I would be better advised to use you event delegate. Set Handler on root element. And checking event.target. http://javascript.info/tutorial/event-delegation
Approach #1
In your PHP code, create your elements with onclick tags, with intended input into the function.
<div class="someclass" onclick="someFunction(1)"></div>
Approach #2
When the page loads, iterate through all elements with your given classname and attach listeners to them. For this approach to work, the divs must have the numbers which will be entered in SomeFunction included in arbitrary tags.
<div data="13" > =) </div>
window.onload = function() {
for (var i =0; i < document.getElementsByClassName("classname").; i++){
var Div = document.getElementsByClassName("classname")[i];
Div.addEventListener("click", function(){
someFunction(Div.data);
});
}
}
You can delegate events by attaching event listener to parent element. To get the target element you can use event.target
Here's the sample code how you can achieve it:
var parentElement = document.querySelector("#parent");
parentElement.addEventListener("click", function () {
var currentTarget = event.target;
if (currentTarget.tagName === "LI") { // If you want LI to be clickable
currentTarget.style.backgroundColor = "#eee";
currentTarget.style.color = "#606060";
}
});
Here's the jsfiddle for the same: https://jsfiddle.net/dx8Lye29/
The simplest way of doing this is giving the elements a data-attribute with the parameter for the function you want to run:
<div class="someclass" data-parameter="12">
<div class="someclass" data-parameter="13">
<div class="someclass" data-parameter="14">
and then run this:
function setMyHandler(){
var elements = document.getElementsByClassName('someclass');
for(var i = 0; i < elements.length; i++){
elements[i].onclick = function(){ myFunction(this.data.parameter); };
}
}
Here is a link for data attributes: data attributes
And here is a snipplet to see the simple version of it in action:
function setMyHandler(){
var elements = document.getElementsByClassName('someclass');
for(var i = 0; i < elements.length; i++){
elements[i].onclick = function(){window.alert(this.dataset.somevalue);};
}
}
setMyHandler();
body {
display: flex;
justify-content: center;
}
div.someclass {
margin: 2%;
width: 50px;
height: 50px;
border-radius: 50%;
cursor: pointer;
background: #80bfff;
box-shadow: 0px 2px 6px 0px rgba(0,0,0,0.7);
transition: background 0.3s ease;
}
div.someclass:hover {
background: #3399ff;
}
<div class="someclass" data-somevalue="13"> </div>
<div class="someclass" data-somevalue="14"> </div>
<div class="someclass" data-somevalue="15"> </div>

Count Clicks and Sort Tags by the clicks Javascript

I have a list of tags, this list is populated by a database and MVC.
I have a razor code that pulls in each tag for sorting purposes.
Recently I was asked to have each tag track how many times it's clicked, and then reorder the tags displayed by how many times the tags have been clicked.
Here is my razor code for the list of tags
<ul class="pills" id="tags">
#foreach (var tag in tags)
{
<li>#tag</li>
}
</ul>
I tried
var clicks = 0 and adding onclick=clicks++ to the a href
but I think I might be on the wrong track. I think Javascript might be my go to.
Here's a simple solution that will work until you refresh the browser:
HTML partial:
<ul class="pills" id="tags">
<li data-click-count=0>tag1</li>
<li data-click-count=0>tag2</li>
<li data-click-count=0>tag3</li>
</ul>
jQuery snippet
When a tag is clicked, increment that tag's click count and then re-sort the tag list.
var $tags = $('#tags').find('li');
$tags.click(function (e) {
// Get the click count for the tag that was just clicked
var tagCount = $(e.currentTarget).attr('data-click-count');
$(e.currentTarget).attr('data-click-count', parseInt(tagCount) + 1);
// Remove tags from the DOM but keep data so you can reorder them
$tags.detach();
// Sort the tags by click count
$tags.sort(function(a, b) {
return $(b).attr('data-click-count') - $(a).attr('data-click-count');
});
// Insert them back into the unordered list DOM element
$('#tags').html($tags);
});
JSFiddle demo: https://jsfiddle.net/adamgibbons/ohos5a17/
Hopefully this fiddle will help. fiddle
I track clicks by adding an an attribute to each tag element. So every time that element is clicked, it increments the data-clicked attribute. Also, when it is clicked, I resort the tags then readd them to the dom in the correct order.
note this uses jquery
$(function(){
var $taglist = $('#tags');
var tags = [];
for(var i = 0; i < 5; i++){
tags.push($('<li class="tag" data-clicked="0">' + i + '</li>'));
$taglist.append(tags[i]);
}
var $tags = $('.tag');
$tags.on('click', onClick);
function onClick(e){
$(this).attr('data-clicked', incrementer($(this)));
tags = sort(tags);
$taglist.html('');
tags.forEach(function($tag){
$taglist.append($tag);
});
$tags.on('click', onClick);
}
});
function incrementer($elem){
return parseInt($elem.attr('data-clicked')) + 1;
}
function sort(tags){
return tags.sort(function($a, $b){
return $b.attr('data-clicked') - $a.attr('data-clicked');
})
}
#tags li {
display: inline;
text-align: center;
border: 1px solid black;
margin: 5px;
border-radius: 2px;
background-color: #e2e2e2;
box-shadow: 3px 3px 2px #f4e4e4;
cursor: pointer;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="container">
<ul id="tags">
</ul>
</div>

dynamic breadcrumbs using anchor tags and isinViewport

Working on creating a small jquery plugin for a client's website that is a simple breadcrumb system using anchor tags, that changes the last element in the breadcrumb list based on which anchor tag is currently visible. Further, I'm using HTML5 data- elements to store each page name, so that I can add that as the second element in the breadcrumb list as well.
For visibility, I'm using this plugin: https://github.com/zeusdeux/isInViewport
This is the fiddle I'm working with: http://jsfiddle.net/7F59C/4/
Here is the HTML:
<div class="header">head element
<div id="breadcrumbs" data-page="About">
<ul>
<li>Home</li>
<li class="currentpage"></li>
<li class="active"></li>
</ul>
</div>
</div>
<div class="spacer"></div>
<div class="gridContainer">
<div class="space">
take up some space<br />
<a class="crumb" id="About" href="#">About Us</a>
</div>
<div class="space">
take up more space<br />
<a class="crumb" id="Other_heading" href="#">Other heading</a>
</div>
</div>
The JS:
$(document).ready(function() {
$jbread();
});
$.fn.jbread = function () {
//set bc as breadcrumbs list
var bc = $("#breadcrumbs");
//BUILD CURRENT PAGE BREADCRUMB ITEM
//set currentpage to current page's data-page value
var currentpage = bc.data("page");
//set currentpage_link to current page's url
var currentpage_link = window.location.pathname;
//add currentpage as next li in breadcrumbs list
$(".currentpage").html('' + currentpage + '');
//UPDATE ACTIVE ITEM IN BREADCRUMB LIST
$.fn.updateCrumbs = function () {
var currentactive = $(e.target);
$(".active").html(currentactive);
}
//WORK WITH ISINVIEWPORT PLUGIN
$('div.gridContainer > a.crumb').updateCrumbs();
$('div.gridContainer > a.crumb:in-viewport(10)').updateCrumbs();
$(window).scroll(function() {
$('div.gridContainer > a.crumb').updateCrumbs();
$('div.gridContainer > a.crumb:in-viewport(250)').updateCrumbs();
});
//STYLE BREADCRUMB LIST
};
And, for good measure, CSS:
#breadcrumbs ul {
list-style: none;
float: left;
padding: 2px;
}
#breadcrumbs ul li a {
text-decoration: none;
color: black;
}
.space {
height: 500px;
background-color: red;
}
.header {
position: fixed;
height: 100px;
background-color: #FFF;
width: 100%;
margin-top: 0;
}
.spacer {
min-height: 100px;
}
INTENDED FUNCTIONALITY:
As the user is scrolling down the page, when one of the anchor tags with the class "crumb" comes intoViewport (which I have set as 250-350 pixels down the page), I would like the list item with the class of "active" to be updated with the anchor tag that just triggered the function. I'm not sure if I'm using $(e.target) correctly, or if it will even reference the correct thing.
I'm hoping to get this function working, and then I need to create an actual demo page to flesh out styling the list after it is populated. That's for another question.
Any thoughts, comments, or criticisms are welcome as I am very new to jQuery and am questioning my logic on this one.
Looks like you want something like
$.fn.updateCrumbs = function () {
var currentactive = this.text();
$(".active").text(currentactive);
}

Categories