Angular ng-repeat, reordering animation slides - javascript

I have a carousel slider in angular, I have ng-repeat with orderBy:'id' and when i click next slide button, id change it.
Look at my JSFiddle here
I have div with ng-repeat:
<div class="slide" ng-repeat="slide in slides | orderBy:'id*1'">
<p>
{{ slide.value.name }}
</p>
</div>
And I have function to sort new item list:
$scope.nextSlide = () => {
let items = $scope.slides
let countItems = items.length
for (let i = 0; i < countItems; i++) {
let z = items[i].id % countItems;
items[i].id = z + (countItems - 1);
}
}
And my problem:
First occurs animate, then scope new ordering item and blink to new slide. Any ideas? How can I animated reordering in ng-repeat?

Why don't you reorder first, so that the first slides are in the 'normal' order and when you click next, the 'reordered' slides show up...
I just don\t understand why you would reorder on "next()"

I think you are tackling the problem the wrong way, about your animation.
Let's say you have 2 items always visible.
1 | 2 | 3 | 4
When you click next, it should:
- slide on the left (animation)
- THEN, once animation is done, you do:
- reorder items (2 first at the back) AND - at the same time - recenter the list.
I think in your small demo, you just forget to recenter the list.
I guess it all depends on the way you are doing your animation as well.

Related

Slick Carousel - The "slickRemove" method is unable to remove the "slick-cloned" slide/item based on the "click" event or "data-slick-index" attribute

short description of the bug / issue, provide more detail below.
I am building a drag-and-drop quiz app. If a user drags a cloned item ( slick generates cloned items in infinite loop option by default) and drops it at the correct dropzone, I want to remove the dropped item from the carousel based on "data-slick-index" attribute value of the dropped item.
But the "slickRemove" method of Slick Carousel is unable to remove the "slick-cloned" slide + its original slide based on the "click" event on the cloned item or "data-slick-index" attribute value of the cloned item.
====================================================================
[ paste your jsfiddle link here ]
http://jsfiddle.net/anisur5/ehpacfvj/30/
====================================================================
Steps to reproduce the problem
Go to this link: http://jsfiddle.net/anisur5/ehpacfvj/30/
Click on the second dot (•) and Inspect "slide10" which contains
data-slick-index="-1". If you click on it (slide10), Slick js is
unable to delete the clicked item.
It happens whenever I click on
the "slick-cloned" slides.
====================================================================
What is the expected behaviour?
I want slick to remove the clicked item even though it is a "slick-cloned" item.
====================================================================
What is observed behaviour?
Slick's "slickRemove" method can not delete the clicked item if the item is "slick-cloned".
====================================================================
More Details
Which browsers/versions does it happen on? => All
Which jQuery/Slick version are you using? => Latest
Did this work before? => No
Here is the code that slick.js uses to remove slides. I added a comment tag for return false; so that Slick can remove items that come with negetive value in "data-slick-index" attribute( I also tried to remove items based on "data-slick-index" ).
Slick.prototype.removeSlide = Slick.prototype.slickRemove = function(index, removeBefore, removeAll) {
var _ = this;
if (typeof(index) === 'boolean') {
removeBefore = index;
index = removeBefore === true ? 0 : _.slideCount - 1;
} else {
index = removeBefore === true ? --index : index;
}
if (_.slideCount < 1 || index < 0 || index > _.slideCount - 1) {
// return false;
}
_.unload();
if (removeAll === true) {
_.$slideTrack.children().remove();
} else {
_.$slideTrack.children(this.options.slide).eq(index).remove();
}
_.$slides = _.$slideTrack.children(this.options.slide);
_.$slideTrack.children(this.options.slide).detach();
_.$slideTrack.append(_.$slides);
_.$slidesCache = _.$slides;
_.reinit();
};
If you add the count of original slides to the negative data-slick-index of the clones, it should give you the index of the original. Only slick does not appear to update that value correctly - so by using that alone, I ended up removing slides with a higher index than the clicked one, when clicking on an original.
Only workaround I could find on the quick, is to store the reference to the slide, on the slide, before the slider gets initialized - then the clones will still refer to the original. Via that reference, you can then find the index of the original in the list of original slides (exclude the clones), and then use that value to remove the slide.
// before slider initialization:
$('.slider div').each(function(i,e) {
$(e).data('self', e);
});
// slider init here
// ...
//Remove slick item based on click.
$(".slider").on("click", ".slick-slide", function() {
var originalSlide = $(this).data('self')
index = $('.slider .slick-slide:not(.slick-cloned)').index(originalSlide);
$(".slider").slick('slickRemove', index);
});
http://jsfiddle.net/1hx5s39z/2/

Vue how to trigger click on links based on interval

In my vue-app I have a list of links, which I want to be triggered automatically one by one by a default interval, lets say after 3 seconds, the first link gets triggered, then after another 3 seconds, link 2 gets triggered... so its kind of a carousel/autoplay with links I want to achieve, but I don't really know how to solve that.
here is my code:
<li v-for="(slide, index) in slides" :key="index" :class="slideIndex === index ? 'active' : ''" #click="slideIndex = index" ref="slide">
{{ slide.title }}
</li>
and then I thought somethinbg like this:
mounted() {
Object.keys(this.$refs.slide).forEach((el) => {
setInterval(() => {
this.$refs.slide[el].click();
}, 3000);
});
},
but this triggers all links and does not seem to be right at all, but its just a slight idea...
Can someone help me out?
I would not recommend doing this by simulating a click on the link.
How about setting the element you want to be active in your code?
I assume slideIndex is the current selected slide?
You could try something like this:
setInterval(() => {
this.slideIndex = this.slideIndex < this.slides.length - 1 ? (this.slideIndex += 1) : 0;
}, 3000);
So you add +1 every time the interval is triggered and cycle through the slides. If it's at the end slideIndex gets reset and starts at 00

how to counter pagination show in slider

I used the slider where i got bug occur. I wanted to show counter pagination on slider but i was unable to do this. In form of Current Number of Page/ Total number of pages like 1/4,2/4 and so on.
https://codepen.io/anon/pen/WJRqQj
<div id="credit"><br>Slide No.<span id="count">1/4</span><br></div>
You can modify the left and right buttons click functions. Also do not forget to update the automatic slider accordingly. I'm also sure you can get the total index somewhere within so that you don't have to hardcode the "/4" part. Update the below functions:
var leftArrow = $('<div>', {'class': 'jislider__left-arrow'}).click(function () {
animate.control(--animate.index);
document.getElementById("count").textContent = animate.index+"/3";
});
var rightArrow = $('<div>', {'class': 'jislider__right-arrow'}).click(function () {
animate.control(++animate.index);
document.getElementById("count").textContent = animate.index+"/3"
});
This will not be enough, you probably should not hardcode the denominator "/4" part as well. I do not know the library you use, but I guess this is sufficient to give you the overall number of "unique" divs with different source:
var x = Array.prototype.slice.call(document.querySelectorAll(".jislider__img"))
.map(function(d,i){return {node:d,url:getComputedStyle(d).backgroundImage}})
.reduce(function(ac,d,i,a){
!ac.some(function(dd,ii){return dd.url === d.url})
? ac.push(d)
: void(0);
return ac
},[]).map(function(d,i){
return d.node;
})
x.length is 3 in your case. So although you have 5 divs, you have 3 images. You can also see it in the dots below (3 dots are there in your carousel). For the left and right arrow functions above, calculate var l = x.length before hand, and then you can do:
document.getElementById("count").textContent = animate.index+"/" + l;
so you don't have to hardcode it. I had to modify your slider a bit, a working fiddle:
https://jsfiddle.net/ibowankenobi/szwr20ec/5/

Drag and drop lists based on certain conditions

I am using angular-drag-and-drop-lists (https://github.com/marceljuenemann/angular-drag-and-drop-lists) for my AngularJS project to create two lists that allow me to do the following:
Drag items from list A to list B
Drag items from list B to list A
Reorder items in list A
Reorder items in list B
Using a simple example on the library's site (http://marceljuenemann.github.io/angular-drag-and-drop-lists/demo/#/simple) I can see that these four conditions are easily achievable. However, things start to get hairy when I want to introduce slightly more complex behaviour:
When dragging items from list A to list B, I want something to occur (easily achieved with the dnd-drop callback. This currently works for me
When dragging items from list B to list A, I don't want anything to happen other than a regular drop (i.e. the item winds up in list A and nothing fancy happens). This currently works for me
When reordering items in list A, nothing should happen when an item is re-dropped into it's new position in the list (even if it is being dropped back into it's original position) This is where I am having issues - see below for further explanation
When reordering items in list B, nothing should happen when an item is re-dropped into it's new position in the list (even if it is being dropped back into it's original position). This currently works for me
I am largely adapting the sample code used in the example link provided above. The problem I am having is that the action I want to take place when moving items from list A to list B is also occurring when I reorder things in list A.
The current setup/pseudocode I have is the following:
My lists:
$scope.models.lists = {
"A": [],
"B": []
}
I populate these lists with information pulled from a database. Each item in the list also has a property that tracks how many children the item has.
My markup looks like the following:
<ul dnd-list="list"
dnd-allowed-types="['itemType']"
dnd-drop="myCallback(event, index, item, external, type, 'itemType')">
<li ng-repeat="item in list | filter:searchText"
dnd-draggable="item"
dnd-moved="list.splice($index, 1)"
dnd-effect-allowed="move"
dnd-selected="models.selected = item"
dnd-type="'itemType'"
ng-class="{'selected': models.selected === item}"
ng-dblclick="editProperties();">
{{item.label + ' - ' + item.description}}
</li>
</ul>
My callback looks like the following:
$scope.myCallback= function(event, index, item, external, type, allowedType) {
// If the item in question has no children then we don't need to do anything special other than move the item.
if (item.children.length == 0) {
return item;
}
// If moving items around list B then just move them.
for (var i = 0; i < $scope.models.lists.B.length; i++) {
if (item.label === $scope.models.lists.B.[i].label) {
return item;
}
}
// I only want this code to execute if we know we are moving from list A to list B and the item in question has > 0 children.
if (item.children.length > 0) {
// Code that I want to execute only when moving from list A to list B goes here
}
If anyone is able to assist me with this I will be very grateful.
Thanks!
If you're not totally committed to that library (which, btw, doesn't work with a touchscreen) RubaXa's Sortable is the truth: Sortable
The documentation is strong, it's quite performant, and I wish I hadn't wasted my time on other DnD libraries before this one.
Looking at the README, the dnd-drop event fires for any drop - regardless of whether it was within the same list or not.
Going by the script as you have it now, you need to check the event (or pass some additional information into your callback) to determine what list the event is firing on.
hi i have add a dragstartCallback that set variable in event.dataTransfer
for the information of the origin/source of my dragged obj:
$scope.dragstartCallback = function(event){
var id = event.target.id;
var parent = $('#' + event.target.id).closest('ul')[0].id;
var group = $('#' + event.target.id).closest('div')[0].id;
event.dataTransfer.setData("id", id);
event.dataTransfer.setData("parent", parent);
event.dataTransfer.setData("group", group);
return true;
}
And in the dropCallback i just check if is List A or List B
$scope.dropCallback = function(event, index, item, external, type, allowedType) {
$scope.logListEvent('dropped at', event, index, external, type);
var idDivSource = event.dataTransfer.getData("parent");
var idDivDestination = $(event.target).closest('ul')[0].id;
var groupSource = event.dataTransfer.getData("group");
var groupDestination = $('#' + event.target.id).closest('div')[0].id;
if(groupSource == groupDestination){
if(idDivSource != idDivDestination){
if(idDivDestination == 'IDLISTB'){
return item?
}
if(idDivDestination == 'IDLISTA'){
DO Something else
}
DO Something else
}
}
}
Html code:
<div class="associated-drag-and-drop DnD" id="GROUP-MyD&D1" ng-repeat="(listName, list) in models.lists" flex="">
<ul dnd-list="list" id="{{listName}}" dnd-drop="dropCallback(event, index, item, external, type, 'containerType')" flex="">
<md-list-item class="associated-list__item" ng-repeat="item in list | filter:searchFilter" id="{{item.id}}"
dnd-dragover="dragoverCallback(event, index, external, type)"
dnd-dragstart="dragstartCallback(event)"
dnd-draggable="item"
dnd-moved="list.splice($index, 1)"
dnd-effect-allowed="move"
dnd-selected="models.selected = item"
ng-class="{'selected': models.selected === item}"
class="noright associated-list__item"
>
CONTENT
</md-list-item>
</ul>
</div>
Do not use this type of filter "| filter:searchFilter"
But use ng-show="And put here the condition"
Alternative change the reference to $index in dnd-moved="list.splice($index, 1)"
If you dont make this change you will have a problem with the filtered list when drag and drop
Exemple
NOT FILTERED LIST
you will have 2 array in 2 ng-repeat
ListA ListB
index1 of value index2 of value
ng-repeat of list ng-repeat of list
0 aaa 0 ppp
1 bbb 1 qqq
2 ccc 2 www
3 dddaaa 3 eeerrr
4 eeeccc 4 mmmwww
ecc... ecc...
The drag and drop lists work on the index of ng-repeat
FILTERED LIST
Now if we make a filter for 'a' with "| filter:searchFilter" code
angular will make this list
List A List B
0 aaa
1 dddaaa
the index when you drag "dddaaa" will be 1 and not 3
so it will not be removed from listA when dropped in listB
becouse the index is not the same as the non filtered list
instead if you use the ng-show="condition"
it will keep the original index of list not filtered
<md-list-item ng-repeat="item in list"
ng-show="condition">
</md-list-item>
My item list:
$scope.models = {
lists: {
"LISTA": [{1},{2},{3}],
"LISTB": [{1},{2},{3}]
}
};

javascript image gallery query (next image)

This is my first time on stackoverflow, I really hope someone can help. I'm fairly novice at coding, so I hope my query is simple to solve.
I have created a simple javascript image gallery, where if you click on the left or right arrow it loops to show the next image in my array list. I also have quicklinks that jump to the specific images in this list. How can I get my next/back links to then continue on, to show the next image from the one currently selected? E.g if I have jumped to gallery image 3, for it to then show the next image along from it in the list gallery image 4, and not gallery image 2.
Below are samples of my code.
Thanks so much in advance for your help.
Here is my script:
var num=0;
imgArray = [
['../00_assets/gallery/work_00.jpg','Gallery', '1 of 6',],
['../00_assets/gallery/work_01.jpg','Gallery', '2 of 6',],
['../00_assets/gallery/work_02.jpg','Gallery', '3 of 6'],
['../00_assets/gallery/work_03.jpg','Gallery', '4 of 6'],
['../00_assets/gallery/work_04.jpg','Gallery', '5 of 6'],
['../00_assets/gallery/work_05.jpg','Gallery', '6 of 6'],
]
function slideshow(slide_num) {
document.getElementById('mypic').src=imgArray[slide_num][0];
document.getElementById('mypic').alt=imgArray[slide_num][1];
document.getElementById('number').innerHTML=imgArray[slide_num][2];
}
function slideshowUp() {
num++;
num = num % imgArray.length;
slideshow(num);
}
function slideshowBack() {
num--;
if (num < 0) {num=imgArray.length-1;}
num = num % imgArray.length;
slideshow(num);
}
Here is my HTML (I've taken out the bits that do not seem relevant):
<div align="left">
<!-- First image in array list is here -->
<img src="../00_assets/gallery/work_00.jpg" id="mypic" name="mypic" alt="Gallery">
<!-- Previous link is here -->
←
<!-- First image number is here -->
<div id="number">1 of 9</div>
<!-- Next link is here -->
→
<!-- Three quicklinks are link is here -->
Quicklink 1 |
Quicklink 2 |
Quicklink 3 |
Thank you so much.
You should update your num variable whenever you change the current slide.
Then, when a quicklink is clicked, it will have the current slide for the other methods (slideshowUp and slideshowBack) to work with and keep the navigation as expected.
In other words:
function slideshow(slide_num) {
num = slide_num; // add this line
document.getElementById('mypic').src=imgArray[slide_num][0];
document.getElementById('mypic').alt=imgArray[slide_num][1];
document.getElementById('number').innerHTML=imgArray[slide_num][2];
}

Categories

Resources