Infinite loop and dynamic content on slides [duplicate] - ionic-framework

Hi I'm using ngFor to create an set of 3 slides while starting in the middle so I'm guaranteed to be able to slide to left or right on start.
When I slide right I can simple listen to the reachedEnd and push another slide to the array i'm looping.
but I have a problem with adding a slide to the beginning. If I do the same as above and use e.g. array.unshift() or spread to add an item to the beginning, the view think it's on position 0 and snaps the view to the new slide.
The code below would work but it animates the slide change back to index 1.
slide = [0,1,2] //example to loop
slideChanged(event) {
if(this.slides.isBeginning()){
this.slide = [this.slide[0]-1, ...this.slide];
this.slides.update();
this.slides.slideTo(1)
}
}
<ion-slides [initialSlide]="1" (ionSlideDidChange)="slideChanged($event)">
<ion-slide *ngFor="let item of slide">
<h1>Slide {{item}}</h1>
</ion-slide>
</ion-slides>
Any help is appreciated!

You can do that by using the ionSlideNextEnd and ionSlidePrevEnd events from the Slides. Please take a look at this working plunker
The view
<ion-header>
<ion-navbar>
<ion-title>Dynamic slides Demo</ion-title>
</ion-navbar>
</ion-header>
<ion-content>
<ion-slides #slider (ionSlideNextEnd)="loadNext()" (ionSlidePrevEnd)="loadPrev()" [initialSlide]="1">
<ion-slide *ngFor="let n of numbers">
<h2>Current slide: {{n}}</h2>
</ion-slide>
</ion-slides>
</ion-content>
The component
#Component({...})
export class HomePage {
#ViewChild('slider') private slider: Slides;
numbers = [0,1,2];
firstLoad = true;
constructor() {}
loadPrev() {
console.log('Prev');
let newIndex = this.slider.getActiveIndex();
newIndex++;
this.numbers.unshift(this.numbers[0] - 1);
this.numbers.pop();
// Workaround to make it work: breaks the animation
this.slider.slideTo(newIndex, 0, false);
console.log(`New status: ${this.numbers}`);
}
loadNext() {
if(this.firstLoad) {
// Since the initial slide is 1, prevent the first
// movement to modify the slides
this.firstLoad = false;
return;
}
console.log('Next');
let newIndex = this.slider.getActiveIndex();
newIndex--;
this.numbers.push(this.numbers[this.numbers.length - 1] + 1);
this.numbers.shift();
// Workaround to make it work: breaks the animation
this.slider.slideTo(newIndex, 0, false);
console.log(`New status: ${this.numbers}`);
}
}

For you who wonder why this not works on Ionic 4, just add little bit changes on typescript component
This code below works on IONIC 4 :
ionSlideNextEnd(){
if(this.firstLoad) {
// Since the initial slide is 1, prevent the first
// movement to modify the slides
this.firstLoad = false;
return;
}
console.log('Next');
this.daySlider.getActiveIndex().then(idx=>{
let newIndex=idx
console.log(newIndex)
newIndex--;
this.numbers.push(this.numbers[this.numbers.length - 1] + 1);
this.numbers.shift();
// Workaround to make it work: breaks the animation
this.daySlider.slideTo(newIndex, 0, false);
console.log(`New status: ${this.numbers}`);
});
}
ionSlidePrevEnd(){
console.log('Prev');
this.daySlider.getActiveIndex().then(idx=>{
let newIndex=idx
console.log(newIndex)
newIndex++;
this.numbers.unshift(this.numbers[0] - 1);
this.numbers.pop();
// Workaround to make it work: breaks the animation
this.daySlider.slideTo(newIndex, 0, false);
console.log(`New status: ${this.numbers}`);
});
}
Or Much more simpler you can remove getter for Active Index, use below code for Ionic 4:
ionSlideNextEnd(){
if(this.firstLoad) {
this.firstLoad = false;
return;
}else{
this.numbers.push(this.numbers[this.numbers.length - 1] + 1);
this.numbers.shift();
// Workaround to make it work: breaks the animation
this.daySlider.slideTo(1,0,false);
this.monthViewData.selectedTime=new Date(this.monthViewData.selectedTime.setDate(this.monthViewData.selectedTime.getDate()+1));
this.eventSource = this.tmp_events.filter((item)=>{
if(item.startTime >= this.monthViewData.selectedTime.setHours(0,0,0,0) && item.endTime < this.monthViewData.selectedTime.getTime()){
return item;
}
});
}
}
ionSlidePrevEnd(){
this.numbers.unshift(this.numbers[0] - 1);
this.numbers.pop();
this.daySlider.slideTo(1,0,false);
this.monthViewData.selectedTime=new Date(this.monthViewData.selectedTime.setDate(this.monthViewData.selectedTime.getDate()-1));
this.eventSource = this.tmp_events.filter((item)=>{
if(item.startTime >= this.monthViewData.selectedTime.setHours(0,0,0,0) && item.endTime <= this.monthViewData.selectedTime.getTime()){
return item;
}
});
}

Related

Ion-Content Scroll horizontally with mousewheel

I have a ion content with an horizontal scrollbar
<ion-content [fullscreen]="true" [scrollX]="true" (wheel)="onWheel($event)">
The scrollbar works well but the mouse wheel does not.
I would like to use mouse wheel to scroll horizontally
Here is my try :
onWheel(event: WheelEvent): void {
console.log(event.deltaY);
const element: HTMLElement = event.currentTarget as HTMLElement;
element.scrollLeft += event.deltaY;
event.preventDefault();
}
The console log show +100 or -100, but the scroll does not make it.
The scroll is on a element under the ion-content.
This works :
onWheel(event: WheelEvent): void {
const element: IonContent = event.currentTarget as unknown as IonContent;
element.getScrollElement().then((scroll) => {
scroll.scrollLeft += event.deltaY;
});
event.preventDefault();
}

How to use autocomplete on search bar on Ionic 4?

I'm looking for some example but cannot see anyone googling it, just what i want is to hardcode 2 or 3 words, thank you so much. Do i have to look for on ionic 3? or in angular2 better?
In your html file:
<ion-searchbar type="text" debounce="500" (ionChange)="getItems($event)"></ion-searchbar>
<ion-list *ngIf="isItemAvailable">
<ion-item *ngFor="let item of items">{{ item }}</ion-item>
</ion-list>
in your ts file:
// Declare the variable (in this case and initialize it with false)
isItemAvailable = false;
items = [];
initializeItems(){
this.items = ["Ram","gopi", "dravid"];
}
getItems(ev: any) {
// Reset items back to all of the items
this.initializeItems();
// set val to the value of the searchbar
const val = ev.target.value;
// if the value is an empty string don't filter the items
if (val && val.trim() !== '') {
this.isItemAvailable = true;
this.items = this.items.filter((item) => {
return (item.toLowerCase().indexOf(val.toLowerCase()) > -1);
})
} else {
this.isItemAvailable = false;
}
}
Mohan Gopi's answer is complete, but in order to make use of the debounce attribute, you have to use the ionChange event instead of the ionInput event.
<ion-searchbar type="text" debounce="500" (ionChange)="getItems($event)"></ion-searchbar>
...
...
That way the event will trigger after the user stops typing (after 500 milliseconds have passed since his last key press), instead of whenever a key is pressed.
Just wanted to share something I tried myself. I have implemented the autocomplete from Angulars material design (https://material.angular.io/components/autocomplete/overview)
But it did not look exactly as the rest of the ionic input components. I also tried the ion-searchbar but I did not like the search input, I wanted a normal ion-input So I did this:
html:
<ion-list>
<ion-item>
<ion-label position="floating">Supplier*</ion-label>
<ion-input (ionChange)="onSearchChange($event)" [(ngModel)]="supplier"></ion-input>
</ion-item>
<ion-item *ngIf="resultsAvailable">
<ion-list style="width: 100%; max-height: 200px; overflow-y: scroll;">
<ion-item *ngFor="let result of results" (click)="supplierSelected(result)" button>
<ion-label>{{result}}</ion-label>
</ion-item>
</ion-list>
</ion-item>
</ion-list>
in component.ts:
resultsAvailable: boolean = false;
results: string[] = [];
ignoreNextChange: boolean = false;
onSearchChange(event: any) {
const substring = event.target.value;
if (this.ignoreNextChange) {
this.ignoreNextChange = false;
return;
}
this.dataService.getStrings(substring).subscribe((result) => {
this.results = result;
if (this.results.length > 0) {
this.resultsAvailable = true;
} else {
this.resultsAvailable = false;
}
});
}
supplierSelected(selected: string) :void {
this.supplier = selected;
this.results = [];
this.resultsAvailable = false;
this.ignoreNextChange = true;
}
Granted the question was about ion-searchbar but maybe somebody out there also wants to use a normal ion-input like me. There is no clear icon but I can live with that, or just add one next to the ion-input. Could be that there is a way to turn the ion-searchbar into a normal ion-input style? Can't find it though in the docs.

(Ionic 2) Keep auto play in slides when the slide is swiped

i have the slider like this:
<ion-slides #promoSlider [options]="homeOptions" (change)="onPromoSlideChanged()" >
<ion-slide *ngFor="let promo of promos">
<img *ngIf="promo" src="{{promo.image}}" style="width:300px;height:300px;margin:auto;display:block" >
</ion-slide>
</ion-slides>
I have use this options to keep my slide playing using auto play:
homeOptions = {
initialSlide: 0,
loop: true,
autoplay:2000
};
But the problem is when i swipe the slider the auto play is stopped and the slider is not sliding again. How to keep the slider playing even i swipe the slider. I have try this code:
onPromoSlideChanged() {
alert('ABC');
this.promoSlider.options = this.homeOptions;
this.promoSlider.rapidUpdate();
//What should i do in this method?
};
What event i need to keep the slider slide again (keep playing) when i swipe the slider ? Thanks...
You can find your answer here => https://forum.ionicframework.com/t/how-to-keep-slides-auto-play-when-the-slides-is-swiped/54025/6
The official docs reference the component Swiper as the base of the ion-slides component, so the API should be the same as the one described in http://idangero.us/swiper/api/11.
You could use the option autoplayDisableOnInteraction to avoid disabling auto play after the user interaction.
Your options array should be:
homeOptions = {
initialSlide: 0,
loop: true,
autoplay:2000,
autoplayDisableOnInteraction: false
};
Hope it helps.
$scope.images = {"status":true,"msg":"2 record(s) found","sliders":[{"title":"slider 1","content":"test
value","weblink":null,"image":"http:\/\/192.168.8.54\/test\/media\/mbimages\/a\/m\/test.jpg"},{"title":"Slider
2","content":null,"weblink":null,"image":"http:\/\/192.168.8.54\/test\/media\/mbimages\/
a\/m\/test.png"}]}
<ion-slide-box delegate-handle="img-viewer" options="options" does-continue="true" loop="true" auto-play="true" slide-interval="5000" >
<ion-slide ng-repeat="nt in images" ng-if="nt.slider_position == '1'" >
<div class="box"><img ng-src="{{nt.image}}" style="width:400px;height:200px;margin:auto;display:block"/></div>
</ion-slide>
</ion-slide-box>
**Controller**
$scope.counter = 0;
$interval(function ()
{
if($scope.counter == $ionicSlideBoxDelegate.$getByHandle('img-viewer').currentIndex() + 1)
{
$ionicSlideBoxDelegate.$getByHandle('img-viewer').slide(0);
}
else{
$ionicSlideBoxDelegate.$getByHandle('img-viewer').update();
}
}, 2000);
angular.forEach($scope.images, function(value, key){
if(value.slider_position == "1")
{
$scope.counter++;
}
Using Observable works for your scenario. You can use it as -
import {Observable} from 'Rxjs/rx';
// in class -
#ViewChild(Slides) slides: Slides;
ionViewDidEnter() {
//you get slider data from any web service
this.sliderObservable = Observable.interval(3000).subscribe(x => {
this.autoPlaySlider();
// or you can do this, it will start autoplay at every 3 seconds
// this.slides.startAutoplay();
});
}
autoPlaySlider(){
var slider_index = this.slides.getActiveIndex();
if(slider_index < this.sliderData.length){
this.slides.slideTo(slider_index+1);
}
else{
this.slides.slideTo(0);
}
}
ionViewDidLeave(){
this.sliderObservable.unsubscribe();
}
You can find more reference Here

how to add, remove a tile when the slider has finish moving form a tile to another?

I would like 3 tiles: previous, current, next.
For instance, when the user move from current to next, I would like a new next tile to be added and the old previous tile to be removed.
Is there any specific javascript function which could be used ?
Or in which function should it be implemented ? (OnPark?)
Any idea, how to implement it ?
Thanks
Thanks Jssor. It works fine. For information, this is my "do something treatment"
if (slideIndex > -1 && fromIndex > -1) {
// filter first access to keep only slide changement
var difference=slideIndex-fromIndex;
if (difference === 1 || difference === -2){
//next tile was just requested
var replaceIndex=(slideIndex+1)%3;
replaceImage(replaceIndex, nextImageUrl);
} else {
//previous tile was just requested
var replaceIndex=(2+slideIndex)%3;
replaceImage(replaceIndex, previousImageUrl);
}
}
function replaceImage(index,url){
// I have add the attributes class="tilei" where i = 0,1 or 2
// inside the tags <img u="image" ...
$('.tile'+index).attr("src",url).load(function(){
var fillHeight=this.height*720/this.width;
var top=(1130-fillHeight)/2;
$('.tile'+index).attr("style","width: 720px; height: "+fillHeight+
"px; top: "+top+"px; left: 0px; position: absolute;");
});
}
Would you do this image replacement in another way to avoid duplication code with the Jssor API, or to block any interaction during image loading ? Sincerely, Didier
You can use your own 'prev' and 'next' buttons.
You can call $Prev or $Next method when a button is clicked.
For example,
jssor_slider1.$Prev();
jssor_slider1.$Next();
And you can display/hide/alter any button when the slider parks.
<script>
jQuery(document).ready(function ($) {
var options = {
$AutoPlay: true, //[Optional] Whether to auto play, to enable slideshow, this option must be set to true, default value is false
$DragOrientation: 3 //[Optional] Orientation to drag slide, 0 no drag, 1 horizental, 2 vertical, 3 either, default value is 1 (Note that the $DragOrientation should be the same as $PlayOrientation when $DisplayPieces is greater than 1, or parking position is not 0)
};
var jssor_slider1 = new $JssorSlider$("slider1_container", options);
function SlideParkEventHandler(slideIndex, fromIndex) {
//do something to display/hide/alter any button
}
jssor_slider1.$On($JssorSlider$.$EVT_PARK, SlideParkEventHandler);
});
</script>

backstretch next & previous buttons

I'm using the backstretch jquery to cycle images on my website. I can get the images to cycle fine, but I'm trying to add "next" and "previous" buttons, and I can't get them to work.
When I click on the next button, nothing happens.
My next button looks like this:
<a id="next" href="#"><img src="/images/arrow-right.png">
And I'm putting all my jquery code at the bottom of the page before the body close tag.
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script type="text/javascript" src="/js/jquery.backstretch.js"></script>
<script>
var images = [
"/images/backgrounds/Image01.jpg",
"/images/backgrounds/Image02.jpg",
"/images/backgrounds/Image03.jpg"
];
$(images).each(function() {
$('<img/>')[0].src = this;
});
// The index variable will keep track of which image is currently showing
var index = 0;
$.backstretch(images[index], {speed: 500});
$('#next').click(function(x) {
x.preventDefault();
$('body').data('backstretch').next();
});
$('#prev').click(function(x) {
x.preventDefault();
$('body').data('backstretch').prev();
});
</script >
Using firebug to debug, I get this:
TypeError: $(...).data(...) is undefined
$('body').data('backstretch').next();
The backstretch call was wrong.
Instead of this:
$.backstretch(images[index], {speed: 500});
I wanted this:
$.backstretch(images, {speed: 500});
$('body').data('backstretch').pause();
It's not that the next/prev buttons weren't working, it's that the initial call was passing the first image, not the set of images.
The second line (w/ pause in it) is there so the images don't change automatically, they only change when I hit the next/prev buttons.
Try this instead:
$('body').backstretch(images[index], {speed: 500});
$('#next').click(function(x) {
x.preventDefault();
$('body').data('backstretch').next();
});
$('#prev').click(function(x) {
x.preventDefault();
$('body').data('backstretch').prev();
});
I'm trying to fix this same problem of yours...
var rootUrl = "http://www.sagmeisterwalsh.com";
var images = [
rootUrl+"/images/u_work/Aizone-11.jpg",
rootUrl+"/images/u_work/Aizone-12.jpg",
rootUrl+"/images/u_work/Aizone-13.jpg"
];
$(images).each(function() {
$('<img/>')[0].src = this;
});
var index = 0;
var i = 1;
$.backstretch(images[index], {
fade: 750,
duration: 4000
});
$('#next').click(function(x) {
x.preventDefault();
$.backstretch(images[i++], {
fade: 750,
duration: 4000
});
$('#output').html(function(i, val) { return val*1+1 });
});
$('#prev').click(function(x) {
x.preventDefault();
$.backstretch(images[i--], {
fade: 750,
duration: 4000
});
$('#output').html(function(i, val) { return val*1-1 });
});
Try this:
http://jsfiddle.net/XejZV/