Trying to create a function that console.logs the data-attribute associated with an .active class each time the .active class changes elements.
So far I can only get the initial data attribute value of the first element's .active class. Calling the function after the .active class has changed elements produces the same results as initially calling the function.
// Variables
var activeItem = document.querySelectorAll('.active');
// Get the Data-Targ value from the .active_class
var active_href = function() {
for (i = 0; i < activeItem.length; ++i) {
var reports = activeItem[i].dataset.targ;
console.log('data-targ of .active is: ' + reports);
}
};
In reply to comments, this is how I am initially attaching the .active class.
It is being attached to the first child of the parent container.
(essentially, the first li of the ul it is contained in)
var first_child = ul.children[0];
var active = first_child.classList.add('active');
So, the active_href isn't calling the dynamically updated .active class placement along the ul > li chain that happens through Next and Previous buttons containing the event handlers that add and remove the active class.
Related
I have a function to add a class civil-active to the label that is clicked. When the next label is clicked the class is added to it too, naturally. But I want the class civil-active to be there only on the clicked label and get it removed from its previous and next sibling if present.
the code that is adding the class is
js
var labels = document.getElementsByTagName("label");
for (let i = 0; i < labels.length; i++) {
labels[i].addEventListener("click", addclass);
}
function addclass(event) {
event.target.classList.add("civil-active");
}
Please suggest me what should I do
In the event handler, find the element having the class and remove it.
function addclass(event) {
// Those lines will remove the class on the element that has it (if there is one)
let active = document.querySelector(".civil-active")
if(active){
active.classList.remove("civil-active");
}
event.target.classList.add("civil-active");
}
const showMovies = function (title, url, rating, id) {
const newMovieElement = document.createElement('li');
newMovieElement.className = 'movie-element';
newMovieElement.innerHTML = <div class='movie-elementimage'>
<img src='${url}' alt='${title}'>
</div>
<div class='movie-elementinfo'>
<h2>${title} </h2>
<p> ${rating}/5 Stars</p>
</div>
;
document.getElementById('movie-list').append(newMovieElement);
newMovieElement.addEventListener('click', function () {
newMovieElement.style.display = 'none';
});
};
Every time showMovies function is called I create a new LI and store it in const newMovieElement.
Now suppose two times this function is called, then the last created LI would have been stored in const newMovieElement.
I also add an eventListener on every LI created for deletion of LI.
Now Suppose I click the first LI, then which LI should disappear because newMovieElement.style.display = 'none'; at the time of click, newMovieElement stores 2nd LI and thus this will set the display:none of the newMovieElement(2nd LI added) and not the first LI ?
The result is that if I am clicking 1st LI, then it is only disappearing(which is indeed required) but technically shouldn't 2nd LI disappear according to code?
Each dynamically created function (e.g. your event handler) get the surrounding scope bound to it, so it has access to those variables (including newMovieElement). This is called "lexical scoping" or "closure". And each newMovieElement contains another <li> element.
Read here:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures
https://exploringjs.com/es6/ch_variables.html
I have a div <div id="MetricsTypeYearModelList"></div> . In this div i am dynamically adding a ul element
$("#MetricsTypeYearModelList").append('<ul class="modal__list mCustomScrollbar" id="MetricsTypeYearModelListUl"></ul>');
After this i am looping over a JSON object and adding li element dynamically to the ul element
for (var i = 0; i < metricsTypeYearModel.length; i++)
{
var obj = metricsTypeYearModel[i];
$("#MetricsTypeYearModelListUl").append('<li data-name='+obj.ModelTypeName+' data-value='+obj.ModelTypeID+' data-id='+obj.ModelTypeID+' class="pModel"> '+obj.ModelTypeName+'</li>');
}
I have used "mCustomScrollbar" class in my ul element but this does not show up, normal scroll bar does show up. How can i show the CustomScrollBar
You can set the live configuration property to true in order to target elements that are dynamically added to the DOM.
So
$(".mCustomScrollbar").mCustomScrollbar({
live:true // add this after your existing config options
});
Alternatively, and in this case might be a better option, just manually call mCustomScrollbar on the newly added element, after adding the contents to it.
for (var i = 0; i < metricsTypeYearModel.length; i++)
{
var obj = metricsTypeYearModel[i];
$("#MetricsTypeYearModelListUl").append('<li data-name='+obj.ModelTypeName+' data-value='+obj.ModelTypeID+' data-id='+obj.ModelTypeID+' class="pModel"> '+obj.ModelTypeName+'</li>');
}
$('#MetricsTypeYearModelListUl').mCustomScrollbar();
I am dynamically creating li with javascript, I want to add a close button to each li element created dynamically to delete the li element on click of the close button.This is my code so far:
function addNew(){
// get value from input field
var taskName = document.getElementById('task-name').value;
// innerHTML to be inserted inside li
var fullText = taskName + '<span class = "close" onclick =
"addListener(this)">×</span>';
// calling create function from Element object
Element.createNew('li','className','tasks',0,fullText);
}
// remove function
function addListener(e){
e.parentNode.parentNode.removeChild(e.parentNode);
}
The problem is the remove function removes the last li instead of li being clicked.
Here is the JSFiddle of the problem.
store all the list items in an array.
//suppose your list items have a class name 'lists'
//create a global var
var lis = document.getElementsByClassName('lists');
initially it'll be empty,
so in your add method(in which you're appending the new list item to ul,
push the new list item in the lists array.
and in the addEvent(e) method , loop around every element in the lists array
function addEvent(e){
for(var i=0; i<lists.length; i++){
if(lists[i] === e){
//remove the lists element by using lists[i] instead of e
// and remember to pop the lists[i] and resize the lists array
}
}
I'm trying to move elements between two lists. Elements when clicked should move to the other list. Prototype JS code:
document.observe('dom:loaded', function() {
$$('li.available-item').each(function(element){
element.observe('click', function(){
element.removeClassName('available-item');
element.addClassName('selected-item');
$('selected-list').insert(element);
});
});
$$('li.selected-item').each(function(element){
element.observe('click', function(){
element.removeClassName('selected-item');
element.addClassName('available-item');
$('available-list').insert(element);
});
});
});
Sample elements:
<ul id="available-list">
<li class="available-item">Apple</li>
<li class="available-item">Orange</li>
<li class="available-item">Grapes</li>
</ul>
<ul id="selected-list">
<li class="selected-item">Pineapple</li>
<li class="selected-item">Papaya</li>
</ul>
While it's working the first time I'm clicking on the elements, once an element moves to the other list they don't move to the other (original) list when clicked.
What am I doing wrong here?
The reason is that when you move an item, it's still got the old event handler attached that will just move it again.
This is a classic place for using event delegation. Instead of watching for clicks on the elements, look for clicks on the lists (since clicks bubble up) and then move the relevant element. Something like this:
$('available-list').observe('click', function(event) {
var li;
li = event.findElement('li');
if (li) {
event.stop();
li.addClassName('selected-item').removeClassName('available-item');
$('selected-list').insert(li);
}
});
...and the converse for selected-list.
You could even use just one handler for both lists:
$('available-list').observe('click', listClick);
$('selected-list').observe('click', listClick);
function listClick(event) {
var fromType, toType, li;
// Get the clicked list item
li = event.findElement('li');
if (li) {
// We're handling it
event.stop();
// Determine whether moving to the selected or available list
if (this.id.startsWith("selected")) {
fromType = "selected";
totype = "available";
}
else {
fromType = "available";
totype = "selected";
}
// Update class names
li.addClassName(toType + '-item').removeClassName(fromType + '-item');
$(toType + '-list').insert(li);
}
});
It gets even simpler if you ditch the classes on the items (see below):
$('available-list').observe('click', listClick);
$('selected-list').observe('click', listClick);
function listClick(event) {
var targetList, li;
// Get the clicked list item
li = event.findElement('li');
if (li) {
event.stop();
targetList = this.id.startsWith("selected") ? "available-list" : "selected-list";
$(targetList).insert(li);
}
});
Somewhat OT, but you may not need those selected-item and available-item classes at all. With the above, you don't need them to find them anymore, and in your CSS, you can use descendant selectors for styling the elements:
#selected-list li {
/* ...styles for the `li` elements in the `selected-list` ... */
}
#available-list li {
/* ...styles for the `li` elements in the `available-list` ... */
}
If you only want to affect lis that are direct children of the lists, use child selectors instead of descendant selectors (note the >):
#selected-list > li {
/* ...styles for the `li` elements in the `selected-list` ... */
}
#available-list > li {
/* ...styles for the `li` elements in the `available-list` ... */
}