Animating new additions to a generated list with CSS - javascript

I have a <ul> of elements like this:
<ul id="task-list">
<li class="task"></li>
<li class="task"></li>
<li class="task"></li>
<li class="task"></li>
</ul>
Every time a .task is changed, added, or removed, I generate the entire <ul> again through a Handlebars template and display it with .html():
function addHTML(allTasks) {
var tasks = compileTemplate(allTasks);
return $('#task-list').html(tasks);
}
function compileTemplate(allTasks) {
var source = $('#task-template').html();
var template = Handlebars.compile(source);
return template({
tasks: allTasks
});
}
The list uses Slip.js for reordering, and new items are added at the top of the list. The height of each item could be anything.
Is it possible to have a CSS animation for new additions where the list "slides down" to pop in the new task, or will I need to change my logic to add each task to an existing list, instead of generating the whole <ul> each time?

You can solve this with some simple jquery functions, although AngularJS would look much cleaner. A little example for adding and removing elements with JSFiddle example.
HTML
<ul id="task-list">
<li class="task"><button class="remove">remove</button>Lorem</li>
<li class="task"><button class="remove">remove</button>Ipsum</li>
<li class="task"><button class="remove">remove</button>Dilor</li>
<li class="task"><button class="remove">remove</button>Test</li>
</ul>
<li class="task" id="hidden-task"><button class="remove">remove</button>Test</li>
<button class="add">add last Child</button>
jQuery
//.remove is class of your remove button, task is the list element
$('.remove', '.task').on('click', function(){
var li = $(this).parent();
li.slideToggle({
'complete':function(){
li.remove()
}
});
})
//use hidden element as dummy
var element = $('#hidden-task');
//cache tasklist
var taskList = $('#task-list');
$('.add').on('click', function(){
//create a deep clone
var clone = element.clone(1,1);
taskList.append(clone);
setTimeout(function(){
clone.slideToggle()
}, 200);
});
var nth = 2;
$('.c2th').on('click', function(){
var clone = element.clone(1,1);
$('li').eq(nth-1).after(clone);
setTimeout(function(){
clone.slideToggle()
}, 200);
});

Related

How to tell Javascript getElementByClassName to get all the element of a ul, instead of repeating the class name in each li?

I'm trying to clean my html/css. How can I get this Javascript to still work, without inserting the class name in each li element from the ul?
How to make the html more pretty and readable?
const ProfileForm = document.getElementsByClassName('profile_container');
const dash = document.getElementsByClassName('dashboard_buttons');
var index;
var array = [];
for (var i = 0; i < dash.length; i++) {
array.push(dash[i]);
dash[i].onclick = function() {
index = array.indexOf(this);
ProfileForm[index].style.display = "block";
var check = ProfileForm[index];
for (var i = 0; i < ProfileForm.length; i++) {
if (ProfileForm[i].style.display == "block" && ProfileForm[i] != check) {
ProfileForm[i].style.display = "none";
}
}
}
}
<ul>
<li class="dashboard_buttons"><i class="far fa-user"></i>Profile</li>
<li class="dashboard_buttons"><i class="far fa-list-alt"></i>My Properties</li>
<li class="dashboard_buttons"><i class="far fa-money-bill-alt"></i>My Offers</li>
<li class="dashboard_buttons"><i class="fas fa-file-contract"></i>My Utilities & Ejari</li>
<li class="dashboard_buttons"><i class="far fa-heart"></i>Favourite Properties</li>
<li class="dashboard_buttons"><i class="far fa-envelope"></i>Messages</li>
<li class="dashboard_buttons"><i class="fas fa-cogs"></i>Settings</li>
</ul>
A simple document.querySelectorAll("ul li") should work. Be careful however, as this will select all the <li> in your whole document. If you want to select a specific <ul>, give it a class or an ID, and select only this one :
<ul id="myList"><li>...<li></ul>
document.querySelectorAll("ul#myList li")
You can use event delegation to notice all events within some "ancestor" element.
(Using event listeners instead of inline event handlers allows this and also promotes separation of concerns between HTML and JavaScript.)
Since I wasn't sure what you wanted to do in your loop, the demo below just "un-highlights" all the list items (and then highlights whichever one was clicked). See the in-code comments for further explanation.
Does this show you how to accomplish what you're trying to do?
// Identifies the `ul` element, and calls `hightlightItem` when user clicks inside it
const list = document.getElementsByClassName("list")[0];
list.addEventListener("click", highlightItem);
// Defines the listener function
function highlightItem(event){ //Listener can access the triggering event
const clickedThing = event.target; // Event's `target` property is useful
// Makes sure the click was on an `li` element before proceeding
if(clickedThing.tagName.toLowerCase() == "li"){
// Collects the list items
const items = list.querySelectorAll("li");
// Loops through the collection
for(let item of items){
// Changes the classList for the current item in the loop
item.classList.remove("highlight");
// Maybe changes it again before continuing to next item in loop
if(item == event.target){ item.classList.add("highlight"); }
}
}
}
.highlight{ background-color: yellow; }
<ul class="list">
<li>Profile</li>
<li>My Properties</li>
<li>My Offers</li>
</ul>
you can do it by query selector
// Get all 'li' elements in the document with class="example"
var x = document.querySelectorAll("li.example");
Instead of using document.getElementByClassName, use document.querySelectorAll

Put Duplicates under Common Element JavaScript/Jquery

I have the following code.Now I am building the list using Jquery. How do I do this using Javascript/JQuery?
Html(raw)after completion should look like this
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
<ul id="listOne">
<li class="columnItem">John</li><!--will be removed and put under CommonLister-->
<li class="columnItem">James</li>
<li class="columnItem">Mary</li><!--will be removed and put under CommonLister-->
</ul>
<ul id="listTwo">
<li class="columnItem">John</li><!--will be removed and put under CommonLister-->
<li class="columnItem">Mark</li>
<li class="columnItem">Mary</li><!--will be removed and put under CommonLister-->
</ul>
<ul id="CommonLister">
<li class="columnItem">John</li>
<li class="columnItem">Mark</li>
</ul>
</div>
Jquery/JavaScrpit
function myFunctioner(){
$(() => {
let names = [];
let nameSet = new Set();
$("li.columnItemer").each((idx, ele) => {
nameSet.add($(ele).html())
});
var $common = $("<ul>").addClass("commmonLister");
nameSet.forEach((name) => {
if ($("li:contains(" + name + ")").length > 1) {
$("li:contains(" + name + ")").remove();
$("<li>").addClass("columnItemer").html(name).appendTo($common);
}
});
$common.appendTo($(".CommonLister"));
});
}
The above code only works if the list already exists on HTML not when dynamically creating the list. I will be building the list by Ajax query. really appreciate in if you guys can show me how to implement the above code dynamically as the list is built on click event.
Here is what I've got. I don't use the new Javascript notation (not really a fan of it), though I'm sure you could transcribe what I've written into ES if you want to keep it consistent in your project.
I took a very similar approach to you, however I did not dynamically create the element. If you know this element will exist on the page anyway, my personal philosophy is just let it exist there and be empty so that you don't have to create it on your own.
If these lists are being loaded dynamically (something I couldn't really test out while using codepen) then put this into a function called after the list elements have been created. Preferably you would simply go through the data when it is loaded and make the applicable DOM changes only once, but sometimes we do what we must
$(function() {
$('#run-code').on('click', function(e) {
e.preventDefault();
//What were you doing? nope.
var currentItems = {}; //Blank object
var $mergeColumn = $('#CommonLister'); //Common list reference
$('.columnItem').each(function(i, el) {
var $el = $(el); //Notation I use to differentiate between the regular HTML Element and jQuery element
if (!currentItems.hasOwnProperty($el.html())) {
//Has this name come up before? if not, create it.
currentItems[$el.html()] = []; //Make it equal to a brand spanking new array
}
currentItems[$el.html()].push(el);
//Add the item to the array
});
$.each(currentItems, function(name, data) {
//Loop through each name. We don't actually use the name variable because we don't care what someone's name is
if (data.length > 1) {
//Do we have more than 1 element in our array? time to move some stuff
$.each(data, function(i, el) {
var $el = $(el); //See note above
if (i == 0) {
//If this is the first element, let's just go ahead and move it to the merge column ul
$el.appendTo($mergeColumn);
} else {
$el.remove(); //Otherwise, we've already got this element so delete this one.
} //end if/else
}); //end $.each(data)
} //end if data.length >1
}); //end $.each(currentItems)
}); //end $.on()
}); //end $()
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="run-code" class="btn btn-success">Click Me</button>
<h4>List 1</h4>
<ul id="listOne">
<li class="columnItem">John</li>
<!--will be removed and put under CommonLister-->
<li class="columnItem">James</li>
<li class="columnItem">Mary</li>
<!--will be removed and put under CommonLister-->
</ul>
<h4>List 2</h4>
<ul id="listTwo">
<li class="columnItem">John</li>
<!--will be removed and put under CommonLister-->
<li class="columnItem">Mark</li>
<li class="columnItem">Mary</li>
<!--will be removed and put under CommonLister-->
</ul>
<h4>Common List</h4>
<ul id="CommonLister">
</ul>

.child() returns 2nd level items

Well i think .child() function is my problem... But im not sure about this.
I have this in html
<div class="tabs" data-name="1st level tabs">
<ul class="nav">
<li>1st level link</li>
<li>1st level link</li>
</ul>
<ul class="content">
<li>
1st TEXT
<div class="tabs" data-name="2st level tabs">
<ul class="nav">
<li>2nd level link</li>
<li>2nd level link</li>
</ul>
<ul class="content">
</ul>
</div>
</li>
<li>1st TEXT</li>
</ul>
</div>
One element with class "tabs" inside another... ok; in JS:
$(function($) {
var Tabs = function(element,options){
self = this;
self.$element = element;
self.testdrive = function (){
console.log(self.$element.attr("data-name"));
}
self.$element.children(".nav").children("li").children("a").click(function(e){
e.preventDefault();
//Returns EVER 2nd level
self.testdrive();
//Triggering directly a Tabs instance returns EVER 2nd level
$(this).closest(".tabs").data("test.tabs").testdrive();
});
}
//JQuery plugin
$.fn.tabs = function () {
return this.each(function () {
var $this = $(this);
var data = $this.data('test.tabs');
//Creating only one instance of Tabs
if(!data){
data = new Tabs($this);
$this.data('test.tabs',data);
}
});
}
//Adding tabs plugin to all ".tabs"
$(function() {
$('.tabs').each(function(){
$(this).tabs();
});
});
}( jQuery ));
When $(element).tabs() called, creates a instance of function Tabs inside a data attribute test.tabs. If test.tabs has been defined only uses an old instance to preserve it.
To test it, i created a function called testdrive, to print in console "data-name" attribute when .tabs>.nav>li>a has been clicked.
The code works but, in console i receive "2st level tabs" if i clicked on 1st level item.
Is a problem with child() function? Something wrong in my code?
Thanks for help.
The problem is the variable declaration for self, since you haven't used var to declare it is created in the global context. So
var self = this;
also you are setting the data using key test.tabs, but is reading it using key simple.tabs
$(this).closest(".tabs").data("test.tabs").testdrive();
Demo: Fiddle
Also I think you can use self.$element.find(" > .nav > li > a").click(function (e) {}); to register the click handler

Access Elements After Append

I need to access DOM elements after JQuery append. Let's say I have this:
<ul id="items">
<li class="item">one</li>
<li class="item">two</li>
</ul>
Then is Javascript:
var addItems = function(html) {
$('#items').append(html);
//How do I access the new items here?
}
Let's say that html is:
<li class="item">three</li>
<li class="item">four</li>
I need to do something to the two new items. This something includes binding events to them. So I cannot simply use $('.item') because that will add double events to the existing items. Once the new items are part of the DOM, there is nothing about them that distinguishes them from the existing items.
What's the best way to do this?
Make a jQuery collection of the html before appending it:
var addItems = function(html) {
var $items = $(html);
$('#items').append($items);
$items.foo();
}
Here's a working example: http://jsfiddle.net/hunter/7UTA2/
var addItems = function(html) {
var $html = $(html);
$('#items').append($html);
$html.text("test");
}
This showcases that you still can manipulate the text (or whatever attribute) of the items since you still have a reference to the collection.

reorder list elements - jQuery? [duplicate]

This question already has answers here:
How may I sort a list alphabetically using jQuery?
(10 answers)
Closed 5 years ago.
Is it possible to reorder <li> elements with JavaScript or pure jQuery. So if I have a silly list like the following:
<ul>
<li>Foo</li>
<li>Bar</li>
<li>Cheese</li>
</ul>
How would I move the list elements around? Like put the list element with Cheese before the list element with Foo or move Foo to after Bar.
Is it possible? If so, how?
var ul = $("ul");
var li = ul.children("li");
li.detach().sort();
ul.append(li);
This is a simple example where <li> nodes are sorted by in some default order. I'm calling detach to avoid removing any data/events associated with the li nodes.
You can pass a function to sort, and use a custom comparator to do the sorting as well.
li.detach().sort(function(a, b) {
// use whatever comparison you want between DOM nodes a and b
});
If someone is looking to reorder elements by moving them up/down some list one step at a time...
//element to move
var $el = $(selector);
//move element down one step
if ($el.not(':last-child'))
$el.next().after($el);
//move element up one step
if ($el.not(':first-child'))
$el.prev().before($el);
//move element to top
$el.parent().prepend($el);
//move element to end
$el.parent().append($el);
One of my favorite things about jQuery is how easy it is to write tiny little add-ons so quickly.
Here, we've created a small add-on which takes an array of selectors, and uses it to order the children of the target elements.
// Create the add-on
$.fn.orderChildren = function(order) {
this.each(function() {
var el = $(this);
for(var i = order.length - 1; i >= 0; i--) {
el.prepend(el.children(order[i]));
}
});
return this;
};
// Call the add-on
$(".user").orderChildren([
".phone",
".email",
".website",
".name",
".address"
]);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="user">
<li class="name">Sandy</li>
<li class="phone">(234) 567-7890</li>
<li class="address">123 Hello World Street</li>
<li class="email">someone#email.com</li>
<li class="website">https://google.com</li>
</ul>
<ul class="user">
<li class="name">Jon</li>
<li class="phone">(574) 555-8777</li>
<li class="address">123 Foobar Street</li>
<li class="email">jon#email.com</li>
<li class="website">https://apple.com</li>
</ul>
<ul class="user">
<li class="name">Sarah</li>
<li class="phone">(432) 555-5477</li>
<li class="address">123 Javascript Street</li>
<li class="email">sarah#email.com</li>
<li class="website">https://microsoft.com</li>
</ul>
The function loops backwards through the array and uses .prepend so that any unselected elements are pushed to the end.
Here is a jQuery plugin to aid with this functionality: http://tinysort.sjeiti.com/
something like this?
​var li = $('ul li').map(function(){
return this;
})​.get();
$('ul').html(li.sort());
demo
I was somewhat lost you may be wanting something like this...
$('ul#list li:first').appendTo('ul#list'); // make the first to be last...
$('ul#list li:first').after('ul#list li:eq(1)'); // make first as 2nd...
$('ul#list li:contains(Foo)').appendTo('ul#list'); // make the li that has Foo to be last...
more of it here1 and here2
Have a look at jquery ui sortable
http://jqueryui.com/demos/sortable/

Categories

Resources