JavaScript Sortable do function on list changes? - javascript

How can I make a function fire when a sortable list changes?
I have looked for some examples but they are making the lists different to how I am and I cant see how to do it with how my sortable lists are generated. Perhaps I am using a different Sortable version or something?
This is how I make my lists...
<script>
Sortable.create(plansList, {
animation: 100,
group: 'list-1',
draggable: '.recipe',
handle: '.handle',
sort: true,
filter: '.sortable-disabled',
chosenClass: 'active'
});
Sortable.create(suggestionsList, {
animation: 100,
group: 'list-1',
draggable: '.recipe',
handle: '.handle',
sort: true,
filter: '.sortable-disabled',
chosenClass: 'active'
});
</script>
As you can see I have 2 lists. I want both to fire the same function when they change, but if both lists change (because an item was moved from one list to the other) I don't want the function to fire twice.
Can anyone help?
Thanks,
Chris

Event onEnd will only fire once, as requested. But it will fire if also no change has been made. So you might need to compare old index to new index.
var example2Left = document.querySelector("#example2-left");
var example2Right = document.querySelector("#example2-right");
new Sortable(example2Left, {
group: 'shared', // set both lists to same group
animation: 150,
onEnd: foo
});
new Sortable(example2Right, {
group: 'shared',
animation: 150,
onEnd: foo
});
function foo(ev) {
var to = ev.to;
var from = ev.from;
var oldIndex = ev.oldIndex;
var newIndex = ev.newIndex;
if (to != from || oldIndex != newIndex) {
singleOnChange(ev)
}
}
function singleOnChange(ev) {
console.log("list(s) changed")
}
.col {
width: 50%;
float: left;
}
.list-group-item {
padding: 10px;
margin: 2px;
background: blue;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/Sortable/1.15.0/Sortable.min.js" integrity="sha512-Eezs+g9Lq4TCCq0wae01s9PuNWzHYoCMkE97e2qdkYthpI0pzC3UGB03lgEHn2XM85hDOUF6qgqqszs+iXU4UA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<div id="example2-left" class="list-group col">
<div class="list-group-item">Item 1</div>
<div class="list-group-item">Item 2</div>
<div class="list-group-item">Item 3</div>
<div class="list-group-item">Item 4</div>
<div class="list-group-item">Item 5</div>
<div class="list-group-item">Item 6</div>
</div>
<div id="example2-right" class="list-group col">
<div class="list-group-item">Item 1</div>
<div class="list-group-item">Item 2</div>
<div class="list-group-item">Item 3</div>
<div class="list-group-item">Item 4</div>
<div class="list-group-item">Item 5</div>
<div class="list-group-item">Item 6</div>
</div>

Related

jQuery: alternate switching of classes in several div blocks

I have 2 identical div blocks on the page, inside of which there are several div blocks with different texts. It looks something like this:
<div class="dynamic_titles">
<div class="dynamic_title active">text 1</div>
<div class="dynamic_title inactive">text 2</div>
<div class="dynamic_title inactive">text 3</div>
<div class="dynamic_title inactive">text 4</div>
<div class="dynamic_title inactive">text 5</div>
</div>
<div class="dynamic_titles">
<div class="dynamic_title active">text 6</div>
<div class="dynamic_title inactive">text 7</div>
<div class="dynamic_title inactive">text 8</div>
<div class="dynamic_title inactive">text 9</div>
<div class="dynamic_title inactive">text 10</div>
</div>
I need to change classes from inactive to active in each dynamic_title block in turn. That is, the next one takes active, and the previous one with active in inactive and so on in a circle.
When I have one dynamic_titles block, everything works fine, but 2 interfere with each other, break. I'm trying not to make 2 functions for each block separately, I want to make one universal one that would be applied to each block separately.
Now I have such a code, but it does not work as expected. It runs once and goes no further. If done without .each, it works, but again not as expected and eventually breaks. What is my mistake?
$('.dynamic_titles').each(function () {
var index = 1,
max = $(this).find('.dynamic_title').length;
function setActiveHeadline() {
setTimeout(function () {
$(this).find('.active').removeClass('active').addClass('inactive');
index++;
if (index > max) {
index = 1;
}
$(this).find('.dynamic_title:nth-of-type(' + index + ')').addClass('active').removeClass('inactive');
setActiveHeadline();
}, 3000);
}
setActiveHeadline();
widthTitle = $(this).find('.dynamic_title.active').width();
$(this).css({
'width': widthTitle,
});
function setWidthHeadlines() {
setTimeout(function () {
widthTitle = $(this).find('.dynamic_title.active').width();
$(this).css({
'width': widthTitle,
});
setWidthHeadlines();
}, 3000);
}
setWidthHeadlines();
})
Thank you for your help!
I think you could simplify this into one function that uses setInterval, please see the following snippet:
$(function(){
//use setInterval to continue the changes
setInterval(() => {
//iterate the blocks
$('div.dynamic_titles').each(function() {
//get the children
const $children = $(this).find('div.dynamic_title');
//get the number of children
const numofchildren = $children.length;
//index for switching active in children
let activeindex = 0;
//iterate children to find the active one
$children.each(function(i, el) {
//if active, remove active and add inactive classNames
//store the index
//break the each loop
if($(el).hasClass('active')){
$(el).removeClass('active').addClass('inactive');
activeindex = i + 1;
return false;
}
});
//if index has reached the last child, reset to zero
if(activeindex > numofchildren - 1){
activeindex = 0;
}
//set the next child to active and remove inactive className
$children[activeindex].classList.add('active');
$children[activeindex].classList.remove('inactive');
});
}, 3000);
})
.active {
color:green;
}
.inactive {
color:grey;
}
<div class="dynamic_titles">
<div class="dynamic_title active">text 1</div>
<div class="dynamic_title inactive">text 2</div>
<div class="dynamic_title inactive">text 3</div>
<div class="dynamic_title inactive">text 4</div>
<div class="dynamic_title inactive">text 5</div>
</div>
<div class="dynamic_titles">
<div class="dynamic_title active">text 6</div>
<div class="dynamic_title inactive">text 7</div>
<div class="dynamic_title inactive">text 8</div>
<div class="dynamic_title inactive">text 9</div>
<div class="dynamic_title inactive">text 10</div>
</div>
<script
src="https://code.jquery.com/jquery-3.6.1.js"
integrity="sha256-3zlB5s2uwoUzrXK3BT7AX3FyvojsraNFxCc2vC/7pNI="
crossorigin="anonymous"></script>

How to call function after javascript .scroll()

Description
I want to call a function after the javascript .scroll() function has finished.
Code
The interesting part is the javascript:
const vertScroll = document.getElementById('boxSlider');
$("#btnLeft").on("click", () => {
vertScroll.scroll({
left: vertScroll.scrollLeft - 120,
behavior: "smooth"
});
//This should print out the new value of
//vertScroll but instead always prints the value
//before scroll()
console.log(vertScroll.scrollLeft);
});
$("#btnRight").on("click", () => {
vertScroll.scroll({
left: vertScroll.scrollLeft + 120,
behavior: "smooth"
});
//same as above
console.log(vertScroll.scrollLeft);
});
.boxSlider {
width: 100%;
overflow-x: auto;
white-space: nowrap;
display: inline-block;
}
.box {
display: inline-block;
background-color: cyan;
width: 100px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="boxSlider" class="boxSlider">
<div class="box">Box 1</div>
<div class="box">Box 2</div>
<div class="box">Box 3</div>
<div class="box">Box 4</div>
<div class="box">Box 5</div>
<div class="box">Box 6</div>
<div class="box">Box 7</div>
<div class="box">Box 8</div>
<div class="box">Box 9</div>
<div class="box">Box 10</div>
</div>
<input id="btnLeft" type="Button" value="Scroll left"/>
<input id="btnRight" type="Button" value="Scroll right" />
Expected Behaviour
console.log(...) should output the scroll value after the scroll() function has completed.
Not the answer
Don't just do console.log(scrollLeft - 120) (or +120) since I want to implement more complex code there and the console.log() is just for better understanding.
What I've tried
I've looked at the scroll() docs (mozilla scroll()) and it doesn't seem to have a callback function.
Question
How can I achieve the expected behaviour?
TIA

The Swiper Slider doesn't update the slide active state while playing the slider

For some reason, I have to use Swiper Slider V4.5.3. I set up a carousel and the content slider, but when clicking the carousel slide item, it should change the active state of the current item, but it doesn't. The active state is always stopped at the first item.
I tried many ways to fix it, but no luck. Even add slideChange event to output the activeIndex value, it always shows 0.
Hope anyone can give me the right direction. Thanks!
var Nav = new Swiper('#nav', {
spaceBetween: 0,
slidesPerView: 4,
watchSlidesVisibility: true,
watchSlidesProgress: true
});
var NavContent = new Swiper('#content', {
spaceBetween: 20,
thumbs: {
swiper: Nav
}
});
.swiper-slide-active {
color: #f00;
}
.swiper-slide {
cursor: pointer;
}
#content {
margin-top: 2em;
}
<script src="https://nybilu.com/sources/swiper.min.js"></script>
<link href="https://nybilu.com/sources/swiper.min.css" rel="stylesheet" />
<div id="nav" class="swiper-container">
<div class="swiper-wrapper">
<div class="swiper-slide">Nav 1</div>
<div class="swiper-slide">Nav 2</div>
<div class="swiper-slide">Nav 3</div>
<div class="swiper-slide">Nav 4</div>
<div class="swiper-slide">Nav 5</div>
</div>
</div>
<div id="content" class="swiper-container">
<div class="swiper-wrapper">
<div class="swiper-slide">Content 1</div>
<div class="swiper-slide">content 2</div>
<div class="swiper-slide">content 3</div>
<div class="swiper-slide">content 4</div>
<div class="swiper-slide">content 5</div>
</div>
</div>

Access the data-id of both the element dragged and the element replaced using SortableJS

I can access the id of the element dragged (see the code below) but not sure how to also grab the id of the element replaced.
the JS:
Sortable.create(selection, {
handle: '.bars-move',
animation: 150,
onStart: function (/**Event*/evt) {
var itemEl = evt.item;
var data_id = itemEl.getAttribute("data-id");
},
});
Any ideas please?
On onStart save the current list of ids, and on onEnd refer to this list using evt.newIndex.
var originalList;
var sortable = new Sortable(document.getElementById('items'), {
onStart: function(evt) {
originalList = [...document.querySelectorAll("#items > div")].map(el => el.id);
},
onEnd: function(evt) {
console.log("Dragged id: " + evt.item.id +
" - Replaced id: " + originalList[evt.newIndex]);
}
});
.list-group-item { font-size: 10px; padding: 1px 5px!important; width: 150px }
<script src="https://cdnjs.cloudflare.com/ajax/libs/Sortable/1.10.1/Sortable.min.js"></script>
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet" />
<div id="items" class="list-group col">
<div id="item1" class="list-group-item">Item 1</div>
<div id="item2" class="list-group-item">Item 2</div>
<div id="item3" class="list-group-item">Item 3</div>
<div id="item4" class="list-group-item">Item 4</div>
<div id="item5" class="list-group-item">Item 5</div>
<div id="item6" class="list-group-item">Item 6</div>
</div>

Onclick scroll to next div with a specific ID

$('.mark').click(function(){
var id = $(this).attr('id');
var next = (Number(id) + 1);
window.scrollTo($('#'+next));
})
.mark {
height: 500px;
color: white;
background: black;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class='marker'>
<div class='mark' id='1'>Mark 1</div>
<div class='mark' id='2'>Mark 2</div>
<div class='mark' id='3'>Mark 3</div>
<div class='mark' id='4'>Mark 4</div>
<div class='mark' id='5'>Mark 5</div>
</div>
Right here, I'm trying to make my window scroll to the next div with an id numbered with current id + 1.
I've tried window.scrollTo($('#'+next));.
But didn't work, then tried window.scrollTo($('#'+next), 500);.
But always returns to first div + 500px.
What is the proper way to handle that?
window.scrollTo(xpos, ypos) takes two parameters. The first one is coordinate along x-axis and second is along y-axis. So you can use 0 for first parameter and $('#'+next).offset().top for second parameter
$('.mark').click(function(){
var id = $(this).attr('id');
var next = (Number(id) + 1);
//window.scrollTo(0, $('#'+next).offset().top);
$('html, body').animate({scrollTop : $('#'+next).offset().top}, 2000);
})
.mark {
height: 500px;
color: white;
background: black;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class='marker'>
<div class='mark' id='1'>Mark 1</div>
<div class='mark' id='2'>Mark 2</div>
<div class='mark' id='3'>Mark 3</div>
<div class='mark' id='4'>Mark 4</div>
<div class='mark' id='5'>Mark 5</div>
</div>
I have done something like this which maybe helpfull for you check out.
HTML
<div class='marker'>
<div class='mark' id='1'>Mark 1</div>
<div class='mark' id='2'>Mark 2</div>
<div class='mark' id='3'>Mark 3</div>
<div class='mark' id='4'>Mark 4</div>
<div class='mark' id='5'>Mark 5</div>
</div>
CSS
.mark {
height: 500px;
color: white;
background: black;
}
JS
$(document).ready(function(){
$('.mark').click(function(){;
var y = $(this).outerHeight();
var z =$(window).scrollTop();
$('body').animate({scrollTop:z+y},800);
});
});
You can check the demo here
$('.mark').click(function(){
var id = $(this).attr('id');
var next = (Number(id) + 1);
location.href="#"+next;
});
.mark {
height: 500px;
color: white;
background: black;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class='marker'>
<div class='mark' id='1'>Mark 1</div>
<div class='mark' id='2'>Mark 2</div>
<div class='mark' id='3'>Mark 3</div>
<div class='mark' id='4'>Mark 4</div>
<div class='mark' id='5'>Mark 5</div>
</div>
This is the solution when you use data-number.
Actually, it's not perfect solution.
But I hope it help you.
$('.mark').click(function(){
var id = $(this).attr('data-number');
var next = (Number(id) + 1);
window.scrollTo(0, $(`.mark[data-number=${next}]`).offset().top);
});
.mark {
height: 500px;
color: white;
background: black;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class='marker'>
<div class='mark' data-number='1'>Mark 1</div>
<div class='mark' data-number='2'>Mark 2</div>
<div class='mark' data-number='3'>Mark 3</div>
<div class='mark' data-number='4'>Mark 4</div>
<div class='mark' data-number='5'>Mark 5</div>
</div>

Categories

Resources