when element is removed, then reposition/animate each next element jQuery - javascript

Actually I have dynamic notification ".noti", and all has
position:fixed;
bottom:0;
width:250px;
right://adjusted via jQuery bcz they are dynamically added
var s = $('body').find('.noti').size();
xxxxx.css({right:s*250});
Now what I want to do is that, when I removed a element, then each next element must reposition/adjust their "right:xxx" property.
for example I have 5 div :
|_ _ _ _ _|
and I removed the right most div
|_ _ _ _ |
then all other divs must reposition as
| _ _ _ _|
I tried ".next":
var next = $(this).closest('.noti').next('.noti');
if(next.length > 0){
var nextright = next.css('right');
nextright = nextright.split('px').join('');
next.animate({right:nextright-250},300);
}
but it'll only reposition the next div.
So can somebody tell me that how can I use ".each()" or ".nextAll()" or a "for loop" to reposition all next elements.
Thanks & regards
UPDATE:
Now I tried :
var parent = $(this).closest('.noti'),next = parent.next('.noti');
var df = parent.attr('data-for');
if(next.length > 0){
$('.noti').each(function(){
if(df != $(this).attr('data-for')){
var t=$(this),pos = t.css('right');
pos = pos.split('px').join('');
t.animate({right:pos-250});
}
});
}
Its works good only when I want to remove the right most element. but if I removed any element from the middle, than each ".noti" reposition their "right" property. But I want that only the "nextAll" elements must reposition.
UPDATE : SOLUTION
Finally this problem is solved {solution is based on Tandon's answer} http://jsfiddle.net/7f2aU/5/
Thanks

DEMO Click on div to remove it
var width = $('#container div').width();
$('#container div').each(function(index){
// set css property `right` to the width * index (zero-based) + 30 (random number)
$(this).css("right", ((width * index) + 30));
});
$("#container div").click(function(){
var thisIndex = $(this).index(); // current element's index
// console.log(thisIndex); a check
$(this).siblings("div").each(function(index){
// to make sure the element `$(this)` (the sibling) is to the left of the element clicked on
if((index + 1) > thisIndex){
var css = parseInt($(this).css("right"), 10); // parse the property
$(this).css("right", css - width); // set it shifted to right by an offset equal to width
// console.log($(this).css("right")); a check
}
});
$(this).remove(); // finally, remove it
});

Related

Slick.js Custom Paging hook and CSS

I'm currently building a slider using Slick.JS alongside some SVG illustrations and I was wondering what the process would be to get the elements of the SVG to change fill colour when the relevant slide is active.
JS Fiddle below should show where I am at the moment:
http://jsfiddle.net/twqvchj6/5/
$('.tugslider').on('afterChange', function() {
var dataId = $(this).slick('slickCurrentSlide');
var slideno = $('a[data-slide]').data('slide');
if(dataId == slideno + 1){
}else{
};
});
Currently I have a blank IF statement that I believe is the correct foundation, but I cannot figure out how to target each of the segment elements individually based on their data-slide number. I had a fill change in here previously changing CSS but it only changed the first segment.
Any help appreciated
Cheers!
You are on the right track, only a few points should be adjusted:
1 - Using slick afterChange event inner declaration, you can receive the currentSlide param;
2 - You can use $("[data-slide='" + dataId + "']") to get the element referenced with index that you have (currentSlide), with this, create a control that manipulates your svg based on a class:
var dataId = currentSlide;
var svgs = $('a[data-slide]');
var slideno = $("[data-slide='" + dataId + "']");
svgs.find('.active').removeClass('active');
slideno.find('path').addClass('active');
3 - Slides index start in 0, update your HTML data-slide;
4 - Also, your HTML is not closing </ul> tag.
Final findle: http://jsfiddle.net/sparhawk_odin/u8vfgosp/

How is the active class added to the correct nav item inside scroll my event?

So I have a single page where the active menu item gets highlighted when you scroll to its corresponding section.
My code works, but I don't understand why, specifically this part:
document.querySelector('nav a[href="' + anchorID + '"]').classList.add("active");
On window.onscroll the for loop collects all the anchors (nav a) from the menu
Then I get access to individual anchorIDs (hrefs) with:
var anchorID = anchorsArray[i].getAttribute("href");
What I don't understand, is how the .activeclass gets added to the correct anchorID based on the current section inside the viewport — when no comparison is made between the section id and the corresponding anchor href. E.g. the href & section id:
Section 2
<section id="section-2"></section>
..are never compared on scroll.
DEMO: https://jsfiddle.net/zgpzrvns/
All the JS
(function() {
var anchorsArray = document.querySelectorAll("nav a");
var sections = document.querySelectorAll("section");
var sectionsArray = [];
// Collect all sections and push to sectionsArray
for (var i = 0; i < sections.length; i++) {
var section = sections[i];
sectionsArray.push(section);
}
window.onscroll = function() {
var scrollPosition = window.pageYOffset;
for (var i = 0; i < anchorsArray.length; i++) {
// Get hrefs from each anchor
var anchorID = anchorsArray[i].getAttribute("href");
var sectionHeight = sectionsArray[i].offsetHeight;
var sectionTop = sectionsArray[i].offsetTop;
if (
scrollPosition >= sectionTop &&
scrollPosition < sectionTop + sectionHeight
) {
/**
* I don't understand how querySelector finds & adds the active
* class to the correct anchor, when no comparison is made between the
* section ID (that is inside current section in viewport) and the
* anchors ID from anchorsArray
*/
document
.querySelector('nav a[href="' + anchorID + '"]')
.classList.add("active");
} else {
document
.querySelector('nav a[href="' + anchorID + '"]')
.classList.remove("active");
}
}
};
})();
In summary: how is the active class added to correct anchor ID, when the corresponding section ID inside the viewport on scroll (when section ID is never detected inside the scroll event?)
I'm so confused about this, and I bet it's something silly I'm overlooking!
Would greatly appreciate some input! :-)
In short:
It doesn't need to compare any ids, because on scroll you loop over all anchors in your navigation. For each you check, if the section at the same index is in the viewport. If so, you add the active class.
If you switch the positions of your navigation items, you'll see that it will add the active class to the wrong item, because it just checks the index.
If you need some more explanation, tell me. Going to edit the answer then.
Edit index explanation:
You have your navigation anchors in an array, and also your sections.
var anchorsArray = document.querySelectorAll("nav a");
var sections = document.querySelectorAll("section");
You are looping your anchors array
for (var i = 0; i < anchorsArray.length; i++) {
and then you get the height and top position of your section at the same index as your anchor (variable i)
var sectionHeight = sectionsArray[i].offsetHeight;
var sectionTop = sectionsArray[i].offsetTop;
if (
scrollPosition >= sectionTop &&
scrollPosition < sectionTop + sectionHeight
) {
and then you set the active class if its true, or remove it, if its false.
So on each scroll your code does the following:
Get anchor one -> check if section one is in range -> If yes -> add active -> else remove active
Get anchor two -> check if section two is in range -> If yes -> add active -> else remove active
Get anchor three -> ... and so one

Infinite loop clone node append twice

I've got a problem with a script that fires 2 times and it clone some columns and append twice.
My goal is to clone the element, which is not in the viewport, and append it at the end, then delete the element from front.
It seems like the element goes of the viewport and enter twice in the condition, where I check if left of the element is greater than its width.
That means I got two clone of the same element and appended twice at the end, which is not good.
Strange thing is that the delete of the element fire once.
here's some code:
var moving = false,
$holder = $('#carousel');
$holder.on('transitionend', function (){
moving = false; // era true
});
offset = 600;
function getPosition() {
wrapper = document.getElementById('carousel');
wrapper_length = wrapper.childElementCount;
width_of_elements = wrapper.children[0].getBoundingClientRect().width;
current_left = wrapper.children[0].getBoundingClientRect().left;
positive_current_left = current_left * -1;
if(Math.round(positive_current_left) > Math.round(width_of_elements)){
// clone + set left after the last one
clone = wrapper.children[0].cloneNode(true);
clone.style.left = wrapper.children[wrapper_length - 1].getBoundingClientRect().left + (offset * 2.6) + "px";
console.log(clone);
// append child cloned
wrapper.appendChild(clone);
// delete element cloned
wrapper.removeChild(wrapper.childNodes[0]);
}
if (!moving) {
window.requestAnimationFrame(getPosition);
}
}
window.requestAnimationFrame(getPosition);
Am I wrong somewhere?
here's a fiddle to see it in action:
fiddle
If all you want to do is to move an element to the end, you can "re"-appendChild. Looks a bit wonky when it starts to come around, but that you can fix. ;)
if (Math.round(positive_current_left) > Math.round(width_of_elements)) {
// clone + set left after the last one
moveMe = wrapper.children[0];
moveMe.style.left = wrapper.children[wrapper_length - 1].getBoundingClientRect().left + (offset * 2.6) + "px";
// append child cloned
wrapper.appendChild(moveMe);
}
fiddle

Remove a child from parent and add it as Sibling to Parent

I have a Bullet Region like
HelloHowareyou
No i am selecting are and changing to Number Bullet.
so my list should change like
HelloHowareyou
want to end the Disc bullet after second child.
want to add Third child as sibling to parent.
Want to again make Disc bullet to fourth child and add it as sibling to parent.
How can i do this.
This is actually a non-trivial and very interesting problem. However, you need to first know a couple of things:
The bullets on a list item are determined by its list; ul is for unordered lists (ie. disk bullets), and ol is for ordered lists (ie. numbered bullets).
You cannot have an li without its parent being either ul or ol.
You cannot have a ul be a direct child of a ol or vice versa (they can be children of an li though, but then they'll be sublists)
This means that every time you switch a list, you need to make sure that the item you're switching has a parent of the correct (and opposite) type, and the items before and after it are also in (separate) lists of the correct type. You will in many cases need to create those lists (or delete them, when they become empty).
Anyway, words are worthless, here's the code (I'm using jQuery, but the idea should be the same regardless of what you use):
$('li').on('click', function () {
var $listItem = $(this);
var $list = $(this).parent();
var $items = $list.children();
var itemIndex = $items.index($listItem);
var numItems = $items.length;
var curType = $list.is('ul') ? 'ul' : 'ol';
var newType = curType === 'ul' ? 'ol' : 'ul';
var $prev = $list.prev();
var $next = $list.next();
if (itemIndex === 0) {
// The item we're switching is the first Item in the list
if (!$prev.is(newType)) {
$prev = $('<' + newType + '/>');
$prev.insertBefore($list);
}
$prev.append($listItem);
} else if (itemIndex === numItems - 1) {
// The item we're switching is the last Item in the list
if (!$next.is(newType)) {
$next = $('<' + newType + '/>');
$next.insertAfter($list);
}
$next.prepend($listItem);
} else {
// The item is in the middle, we need to split the current list into 3.
$tailList = $('<' + curType + '/>');
$tailList.append($listItem.nextAll());
$tailList.insertAfter($list);
$middleList = $('<' + newType + '/>');
$middleList.append($listItem);
$middleList.insertAfter($list);
}
if (numItems === 1) {
// list used to have only one Item, so it's now empty, and should be removed.
$list.remove();
if ($prev.is(newType) && $next.is(newType)) {
// The two surrounding lists are of the same type and should be merged.
$prev.append($next.children());
$next.remove();
}
}
});
I'm using the click event on a list item to switch a list item. Here's a jsFiddle link for you to play around with the implementation and validate that everything works as expected: http://jsfiddle.net/8Z9rf/
The code can definitely be optimized for speed/performance, but I was aiming for simplicity and clarity, I hope I managed to accomplish this.

JQuery .each() callback function doesn't run on each iteration/loop

Here's what should happen.
1. Get the rel attribute of the clicked link
2. For every div with class 'entry':
(i)Get its 'left' position
(ii) Calculate its outer height
(iii)Loop through all instances of 'a.tag_filter'. If it finds the same string in the 'rel' as the one oringinally clicked on then add 1 to 'V' and break out of the loop.
(iv)If 'V' is equal to 0 after the loop we know the same tag isn't present within that '.entry' so fade it out.
(v)Once the fadeout has finished loop through all the '.entry' after the faded out one and get their 'left' values.
(vi)If the left value of the faded entry = the left value of the current '.entry' then reposition it to the new 'top' value.
What is currently happening.
It runs through and fades out all the correct '.entry' elements and only after all of them have faded out does it reposition them remaining '.entry' elements.
After each element is faded out I would like the repositioning loop to run so it essentially positions the remaining elements one at a time rather than all at once.
Heres my code EDIT:
$('a.tag_filter').click(function(e){
e.preventDefault();
var selectTag = $(this).attr('rel');
$('div.spotlight_entry_container_grid').each(function(i){
var $entry = $(this);
var tagArray = [];
$('a.tag_filter', this).each(function(){
tagArray.push ($(this).attr('rel'));
});
if($.inArray(selectTag,tagArray) == -1){
var leftPos = $entry.css("left");
var topPos = $entry.css("top");
$entry.fadeOut(1000, function(){
var nextLeftPos;
var nextTopPos;
$('div.spotlight_entry_container_grid:gt('+i+')').each(function(j) {
var $laterEntry = $(this);
nextLeftPos = $laterEntry.css("left");
nextTopPos = $laterEntry.css("top");
//we need to keep the entries in their columns.
//matching left values will do it. No need to animate left values.
if(leftPos == nextLeftPos){
$laterEntry.animate({ top: topPos});
}
});
});
}
});
});
Hopefully that makes sense
Any help would be appreciated!
I'm probably doing something crazy but I just can't spot it.
Thanks
in here
$('a.tag_filter', this).each(function(){
var curTag = $(this).attr('rel');
if(curTag == selectTag){
v++;
return false;
}
});
returning false inside of $().each() breaks the looping through each element in the wrapped set.
From the documentation
Returning 'false' from within the each
function completely stops the loop
through all of the elements (this is
like using a 'break' with a normal
loop). Returning 'true' from within
the loop skips to the next iteration
(this is like using a 'continue' with
a normal loop).
Also, I would recommend caching $(this) inside of each each() in a local variable for performance instead of referencing it several times.
EDIT:
After looking at the code further, I think the following should do it
$('a.tag_filter').click(function(e){
// prevent the default anchor behaviour
e.preventDefault();
var selectTag = $(this).attr('rel');
$('div.entry').each(function(i){
var $entry = $(this);
// get an array of the anchor tag rel attributes
var tagArray = [];
$('a.tag_filter', this).each(function() {
tagArray.push ($(this).attr('rel'));
});
// if we can't find the selected tag in the entries tags
if ($.inArray(selectTag,tagArray) == -1) {
var leftPos = $entry.css("left");
var topPos = $entry.css("top");
$entry.fadeOut(1000, function(){
var nextLeftPos;
var nextTopPos;
$('div.entry:gt('+i+')').each(function(j) {
var $laterEntry = $(this);
nextLeftPos = $laterEntry.css("left");
nextTopPos = $laterEntry.css("top");
// for the first element, set top and left to the faded out element values
if (j == 0) {
$laterEntry.animate({ top: topPos, left: leftPos });
}
// for later elements in the loop, ste the values to the previous element values
else {
$laterEntry.animate({ top: nextTopPos, left: nextLeftPos });
}
});
});
}
});
});
You don't need to cache $(this), jQuery auto caches the this selector for function callbacks.

Categories

Resources