Apologies in advance I feel as if this is a very simple solution and I am in the middle of a severe brain fart. I am simply trying to grab the data-id of an item I am clicking using ES6 syntax but no matter which way I run it I keep getting undefined.
HTML
<ul>
<li class="list-item" data-id="item-1">Click me</li>
<li class="list-item" data-id="item-2">Click me</li>
<li class="list-item" data-id="item-3">Click me</li>
</ul>
JS
let $el = $('ul');
class List {
constructor($el) {
this.$el = $el;
this.$listItem = $el.find('li');
this.attachHandlers();
}
attachHandlers() {
this.$listItem.on('click', () => {
var data = $(this).attr('data-id');
console.log(data);
});
}
}
const _init = () => {
if ($el.length) {
$el.each((i, v) => {
new List($(v));
});
}
};
_init();
Ive simplified the code down as much as possible, anybody see what I am doing wrong here?
The problem is in your attachHandlers method. Since you are using an arrow function, this refers to the class and not the element that was clicked.
Change the arrow function to a regular function.
In addition to Josan's answer, if you want to continue using the arrow function, use it like this:
class List {
constructor($el) {
this.$el = $el;
this.attachHandlers();
}
attachHandlers() {
this.$el.on('click', 'li', (e) => {
var data = $(e.currentTarget).attr('data-id');
console.log(data);
});
}
}
For more discussion, refer to this thread.
Simpler and easier by just using JQuery:
$(".list-item").on('click', function() {
console.log($(this).data('id'));
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
<li class="list-item" data-id="item-1">Click me</li>
<li class="list-item" data-id="item-2">Click me</li>
<li class="list-item" data-id="item-3">Click me</li>
</ul>
Related
I am trying to toggle a class on and off whenever i click on a list item. I have tried several things like using classList.toggle and wrapping the list elements in a anchor tag and then trying to add a class to the list items through that but the more things i try the more confused i get.
Here below is the snippet of my code.
var li = document.querySelectorAll("li");
li.addEventListener('click', (e) => {
addDoneClass();//
});
function addDoneClass() {
li.className = "done"
}
.done {
text-decoration: line-through;
}
<ul>
<li random="23">Notebook</li>
<li>Jello</li>
<li>Spinach</li>
<li>Rice</li>
<li>Birthday Cake</li>
<li>Candles</li>
</ul>
You might look at my JavaScript code an wonder why i done it that way that is because i was very confused at this point and that was the last thing that i tried.
const elements = document.querySelectorAll("li");
elements.forEach((element) => {
// First option
element.addEventListener('click', function() {
this.classList.toggle('active');
});
// Second option
//element.addEventListener('click', function() { customHandle(this); });
// Third option
//element.addEventListener('click', (e) => customHandle(e.target.closest('li')));
});
// For the second and third options
//function customHandle(element) {
// element.classList.toggle('active');
//}
li.active {
text-decoration: line-through;
}
<ul>
<li>Notebook</li>
<li>Jello</li>
<li>Spinach</li>
<li>Rice</li>
<li>Birthday Cake</li>
<li>Candles</li>
</ul>
In my opinion, it's better if you add one event listener to the ul element, than have multiple for the li elements.
You can use classList.add("class") and classList.remove("class") functions, more information. You will also need to check if the current item already has the class, for that use the classList.contains("class") function.
Here's an example (updated with ternary operator):
const ul = document.getElementById("list");
ul.addEventListener('click', (e) => {
const li = e.target;
li.classList.contains('done') ? removeDoneClass(li) : addDoneClass(li)
});
function addDoneClass(li) {
li.classList.add("done");
}
function removeDoneClass(li) {
li.classList.remove("done");
}
.done {
text-decoration: line-through;
}
<ul id="list">
<li random="23">Notebook</li>
<li>Jello</li>
<li>Spinach</li>
<li>Rice</li>
<li>Birthday Cake</li>
<li>Candles</li>
</ul>
Tip: use the classList.toggle("class"), it does the same thing, but it's the cleaner way.
You Have To Use "this" Keyword To Reffer The Currently Clicked Element. You Can Achieve This Using JQuery Like This.
li.active { text-decoration : line-through; }
$("li").click(function () {
this.classList.toggle('active');
});
The problem is with scope.
function addDoneClass() {
li.className = "done"
}
In your context, li is an array of list items. Without running, I would guess that clicking on any list item was striking through all of the list items. Instead you need to pass the specific list item that you want changed.
li.addEventListener('click', (e) => {
addDoneClass(this); //this is the list item being clicked.
});
function addDoneClass(obj) {
// Now you can change to toggle if you want.
obj.className = "done"
// ie obj.className.toggle("done");
}
querySelectorAll returns a nodelist and addEventLister can only be applied to one node at a time. So to fix your code you should loop over each li in the list. And since you are using the event (evt) with addEventListener, you can use event.currentTarget to get the element clicked.
var listItems = document.querySelectorAll("li");
var listItemCount = listItems.length;
for (var i = 0; i < listItemCount; i++) {
listItems[i].addEventListener('click', (evt) => {
addDoneClass(evt);//
});
}
function addDoneClass(evt) {
evt.currentTarget.className = "done";
}
.done {
text-decoration: line-through;
}
<ul>
<li random="23">Notebook</li>
<li>Jello</li>
<li>Spinach</li>
<li>Rice</li>
<li>Birthday Cake</li>
<li>Candles</li>
</ul>
I am trying to find out which exact list item was selected in the navigation menu. With this information, I will remove the class active from the previous menu link and add it to the newly selected one.
<ul class="nav navbar-nav navbar-right">
<li class="active">Home</li>
<li>About</li>
<li>Portfolio</li>
<li>Contact</li>
</ul>
JavaScript:
let menuClick = document.getElementsByClassName(".nav");
menuClick.addEventListener('click', changeActive(), false);
function changeActive(){
//enter code here
}
Using
Vanilla JS - DEMO
var menuItems = document.querySelectorAll(".nav a"); // Get all matching selectors; same as SizzleJS $(selector)
for(var i=0; i < menuItems.length; i++){ // Loop through each element and add click event listener
menuItems[i].addEventListener('click', function(event){ // adding event listener.
event.preventDefault();
for(var i=0; i < menuItems.length; i++){
menuItems[i].parentElement.className = ''; // remove current `active` class from parent element `li`. This is not the best approach for removing classes in Vanilla JavaScript; see this answer http://stackoverflow.com/a/2155786/2151050
}
this.parentElement.className = 'active'; // add `active` to current clicked element.
}, false);
}
I am not going to force you to use jQuery, but you should consider it for doing more, and writing less code. :). Here's the jQuery version
jQuery - DEMO
var menuItems = $(".nav a");
$(".nav a").on('click', function(event) {
event.preventDefault();
menuItems.parent().removeClass('active');
$(this).parent().addClass('active');
});
Get the first element of the nodelist for nav:
let menuClick = document.getElementsByClassName("nav")[0];
Attach an event listener (note: changeActive not changeActive()). This will use event delegation to catch the events that bubble up from the anchors.
menuClick.addEventListener('click', changeActive, false);
Now add some code to your function:
function changeActive(e){
// grab the element that's active
let active = this.querySelector('li.active');
// remove the class
active.classList.remove('active');
// add the active class to the parent of the clicked anchor
e.target.parentNode.classList.add('active');
}
DEMO
There is many way to do that:
You can use onhashchange to detect hash changes
function locationHashChanged() {
if(location.hash === "#pageOne") {
// do something
}
else if(location.hash === "#pageTwo") {
// do something
}
}
window.onhashchange = locationHashChanged;
Or simply can bind click event to menu items
HTML:
<ul class="nav navbar-nav navbar-right">
<li class="active">Home</li>
<li>About</li>
<li>Portfolio</li>
<li>Contact</li>
</ul>
JS:
var navs = document.querySelectorAll('.nav a');
navs.click = function (e) {
document.querySelector('active').className.replace('active','');
var target = e.target;
taret.className += ' active';
};
here is way a way with javascript..Note you will have to loop to add a click handler to all objects in the menu.
here is a snippet
function click(e){
alert(e.target.innerHTML);
}
var el=document.getElementsByClassName('nav navbar-nav navbar-right')
for(var i=0;i<el.length;++i){
function t(i){
el[i].addEventListener('click',click,false)
}
t(i)
}
<ul class="nav navbar-nav navbar-right">
<li class="active">Home</li>
<li>About</li>
<li>Portfolio</li>
<li>Contact</li>
</ul>
I'm trying to show ul on click. I can do it with simple jQuery but I would like to use the oop way. Please correct me if I'm wrong thanks!
HTML
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" id="toggleDropdown">
<i class="icon-envelope"></i>
</a>
<ul style="display:none;" id="dropdown">
<li>No new messages are available</li>
</ul>
</li>
jQuery
(function(){
var dropdowns = {
dropDownContainer: $('#toggleDropdown'),
dropDown : $('#dropdown'),
init:function(){
$(dropDownContainer).click(function(){
dropDown.show(200);
})
}
};
dropdowns.init();
})();
The thought is not wrong, your implementation is poor. You see, referencing properties or methods from you class. You should use this to create instant references inside your constructor .
Here is a simple example to start with:
(function () {
var testOOP = {
container: $('a'),
init: function (e) {
this.container.click(function (e) {
e.preventDefault();
alert(1)
})
}
};
testOOP.init();
})();
https://jsfiddle.net/jeatqLLe/1/
You don't have access to dropDown or dropDownContainer at that point; use $('#dropdown') and $('#dropDownContainer') in the init function.
I think you got it almost correct. Use "this" to refer your objects properties as follows.
(function(){
var dropdowns = {
dropDownContainer: $('#toggleDropdown'),
dropDown : $('#dropdown'),
init:function(){
$(this.dropDownContainer).click(function(){
this.dropDown.show(200);
})
}
};
dropdowns.init();
})();
If I'm running jquery ui and using sortable in a ul element:
$("#example").sortable({
update: function () {
//do something
}
});
<ul id="example">
<li data-ex="1.1"></li>
<li data-ex="0.1"></li>
<li data-ex="1.4"></li>
</ul>
Is there a way to trigger an event that sorts my elements by the data attribute on the fly? Essentially I'd like a button that sorts the li elements by the data attribute also also triggers the update in sortable().
You can try this:
$(document).ready(function () {
$("#example").sortable({//Sortable initialisation
update: function () {
updatehandler();//Custom function which handles sortable update.
}
});
$('a').click(function () {// Click handler to sort
var list = $('#example');
var listItems = list.find('li').sort(function (a, b) {
return $(a).attr('data-ex') - $(b).attr('data-ex');
});
list.find('li').remove();
list.append(listItems);
updatehandler();//Call updatehandler after sorting
return false;
});
});
function updatehandler() {
//Your update handler code.
alert('updated');
}
HTML:
Sort
<ul id="example">
<li data-ex="1.1">1.1</li>
<li data-ex="0.1">0.1</li>
<li data-ex="1.4">1.4</li>
</ul>
Demo : http://jsfiddle.net/lotusgodkk/GCu2D/151/
I'm not too familiar with sortable, but this fiddle shows how you can get the data-ex attribute's value, and define a variable to use for sorting in the plugin:
http://jsfiddle.net/FF7z6/
I added class="sort" to your html, and then we get the value by using the following:
var dataEx;
$('.sort').click(function(){
var dataEx = $(this).attr("data-ex");
alert(dataEx);
});
I'm trying to make a drop down menu - upon the first hit on div it should extend,upon second hit it should come back where it was.I'm very new to javascript so I'm not really sure where I went wrong it looks perfect to me,the code:
$(document).ready(function() {
$("#firstList").hide();
$("#firstExtend").click(function()
{
if(("#firstList").hide == true)
{
$("#firstList").show("blind",250);
}
else
{
$("#firstList").hide("fade",250);
}
});
});
HTML:
<div id="firstExtend" class="list">Praplesti</div>
<ul id="firstList">
<li class="list">Nium</li>
<li class="list">cia</li>
<li class="list">kazkas</li>
<li class="list">tur</li>
<li class="list">but cj</li>
<li class="list">tikiuosiveiks</li>
</ul>
</div>
the if (object.hide) clause is a bit off. You can use .is(":property") to check. So in your case, do:
if ( $("#firstList").is(":visible") )
try this:
$(document).ready(function () {
$("#firstList").hide();
$("#firstExtend").click(function () {
if (("#firstList").is(':hidden')) {
$("#firstList").show("blind", 250);
} else {
$("#firstList").hide("fade", 250);
}
});
});