Slideshow with different design per slide

I’m having trouble with a slideshow.

I need a 4 slides slideshow. Each one has 3 apartaments boxes, each one with different details, images etc.

The last slide has only 2 boxes but since it is a slideshow repeater i can’t change the design (hiding or cancelling the last box) from the single slide, but it changes for the all 4

Working in
Wix Studio Editor

1 Like

Hi, @Chiara_Tambone !!

I tried using code like the following, and it might work well.

If you’re unsure how to use it, feel free to ask me again. :innocent:

(Tips) For “targetSlideIndex”, please enter the index of the last slide in your case. Also, make sure to set “slideChangeDuration“ to the same value as the one configured in the Wix Studio editor UI.

$w.onReady(function () {

    $w("#slideshow1").onChange(
        createSlideshowHandler(["#box0", "#box1", "#box2"], 2, 1000, ["#box0"], ["#slideshowButton1", "#slideshowButton2"])
    );

});

function createSlideshowHandler(allElements, targetSlideIndex, slideChangeDuration, targetSlideVisibleElements, slideShowButtons) {
    let isFirstRun = true;

    return (event) => {
        if (isFirstRun) return isFirstRun = false;

        slideShowButtons.forEach(id => $w(id).disable());

        const currentIndex = event.target.currentIndex;
        const fadeDuration = Math.floor(slideChangeDuration / 2);
        const fadeOptions = { duration: fadeDuration };

        allElements.forEach(id => $w(id).hide("fade", fadeOptions));

        const toShow = (currentIndex === targetSlideIndex) ? targetSlideVisibleElements : allElements;

        setTimeout(() => toShow.forEach(id => $w(id).show("fade", fadeOptions)), fadeDuration + 300);
        setTimeout(() => slideShowButtons.forEach(id => $w(id).enable()), slideChangeDuration + 300);

    };

}
2 Likes

I think i did, but again if i cancel the third box in the last slide, it cancel it from the previous slide as well

1 Like

Yes, that’s the expected behavior of the repeater, so I believe the result is correct. :innocent: I also noticed that point while writing the code, so this time I implemented a fade effect during slide transitions to make it less noticeable. In other words, I made all the boxes gently fade out first, and then only the necessary ones fade back in. In my tests, even if, for example, Box 3 from the previous slide also faded out, it didn’t matter because the previous slide itself had already moved off-screen and was no longer visible. Did it not work well on your side? :upside_down_face:

Oh, and if you ran the exact code I suggested, it would end up showing only the first box on the third slide. It seems I had left it in the state I modified during my testing. To meet your requirements, I think the code needs to be adjusted as follows. Could you try running it again with this version?

$w.onReady(function () {

    $w("#slideshow1").onChange(
        createSlideshowHandler(["#box0", "#box1", "#box2"], 2, 1000, ["#box0", "#box1"], ["#slideshowButton1", "#slideshowButton2"])
    );

});
1 Like

i solved with this

// ====== CONFIG ======
const HIDE_ON_LAST = [“#box11”, “#imageX12”];
const SHOW_ALWAYS = [“#box12”, “#box13”, “#image13”, “#image14”];
const LAST_INDEX = 3; // 0-based: 3 = 4ª slide. Cambia se il tuo slideshow ha un numero diverso di slide.

$w.onReady(function () {
// 1) Collega slideshow NON in repeater
const pageSlideshows = $w(‘Slideshow’);
if (Array.isArray(pageSlideshows) && pageSlideshows.length) {
console.log(“[diag] Slideshow trovati a livello pagina:”, pageSlideshows.map(s => s.id));
pageSlideshows.forEach(ss => wireSlideshowPage(ss));
} else {
console.log(“[diag] Nessun Slideshow a livello pagina.”);
}

// 2) Collega slideshow DENTRO i repeater
const reps = $w(‘Repeater’);
if (Array.isArray(reps) && reps.length) {
console.log(“[diag] Repeater trovati:”, reps.map(r => r.id));
reps.forEach(rep => {
rep.onItemReady(($item) => {
const itemSlideshows = $item(‘Slideshow’);
if (Array.isArray(itemSlideshows) && itemSlideshows.length) {
console.log([diag] Slideshow nell'item ${$item('#')?.id || '(no-id)'}:, itemSlideshows.map(s => s.id));
itemSlideshows.forEach(ss => wireSlideshowItem(ss, $item));
}
});
});
} else {
console.log(“[diag] Nessun Repeater trovato.”);
}

// 3) Se non troviamo alcuno Slideshow, stampa elenco tipi per aiutarti a identificare il componente
if ((!pageSlideshows || pageSlideshows.length === 0) && (!reps || reps.length === 0)) {
dumpTypesForDebug();
}
});

/** Collega uno slideshow a livello pagina (non in repeater) */
function wireSlideshowPage($ss) {
console.log(“[wirePage] Collego”, $ss.id, “type:”, $ss.type);
const apply = () => applyRule($w.at($ss.currentSlide), getIndex($ss));

// stato iniziale (un tick dopo)
setTimeout(apply, 0);

// usa eventi se presenti, altrimenti polling
if (typeof $ss.onChange === “function”) {
$ss.onChange(apply);
} else if (typeof $ss.onCurrentIndexChanged === “function”) {
$ss.onCurrentIndexChanged(apply);
} else if (typeof $ss.onItemChanged === “function”) {
// Alcuni componenti “slider” espongono onItemChanged({itemIndex})
$ss.onItemChanged(() => apply);
} else {
startPolling($ss, apply);
}
}

/** Collega uno slideshow dentro un repeater */
function wireSlideshowItem($ss, $item) {
console.log(“[wireItem] Collego”, $ss.id, “inside repeater item”);
const apply = () => applyRule($w.at($ss.currentSlide).at($item), getIndex($ss));

setTimeout(apply, 0);

if (typeof $ss.onChange === “function”) {
$ss.onChange(apply);
} else if (typeof $ss.onCurrentIndexChanged === “function”) {
$ss.onCurrentIndexChanged(apply);
} else if (typeof $ss.onItemChanged === “function”) {
$ss.onItemChanged(() => apply);
} else {
startPolling($ss, apply);
}
}

/** Recupera l’indice corrente in modo robusto */
function getIndex($ss) {
try {
if (typeof $ss.currentIndex === “number”) return $ss.currentIndex;
} catch (_) {}
// Se non c’è currentIndex, rinunciamo all’indice e lasciamo applyRule gestire
return undefined;
}

/** Applica la regola di visibilità alla slide corrente */
function applyRule($scope, idx) {
let isLast = false;
if (typeof idx === “number”) {
isLast = (idx === LAST_INDEX);
console.log(“[apply] idx =”, idx, “isLast =”, isLast);
} else {
// Se l’indice non è disponibile, assumiamo non ultima per non nascondere nulla per errore.
console.warn(“[apply] currentIndex non disponibile; lascio tutto visibile”);
}

if (isLast) {
safeCollapse($scope, HIDE_ON_LAST);
safeExpand($scope, SHOW_ALWAYS);
} else {
// Altre slide: mostra tutto
safeExpand($scope, […HIDE_ON_LAST, …SHOW_ALWAYS]);
}
}

/** Polling leggero come fallback */
function startPolling($ss, applyFn) {
console.warn(“[poll] Nessun evento disponibile su”, $ss.id, “— avvio polling 200ms”);
let last = “init”;
setInterval(() => {
try {
const idx = getIndex($ss);
const sig = String(idx);
if (sig !== last) {
last = sig;
applyFn();
}
} catch (_) {}
}, 200);
}

/** Helpers visibilità */
function safeCollapse($scope, ids) {
ids.forEach((id) => {
try {
const el = $scope(id);
if (!el) return;
if (typeof el.collapse === “function”) el.collapse();
else if (typeof el.hide === “function”) el.hide();
console.log(“[collapse] OK ->”, id);
} catch () {}
});
}
function safeExpand($scope, ids) {
ids.forEach((id) => {
try {
const el = $scope(id);
if (!el) return;
if (typeof el.expand === “function”) el.expand();
else if (typeof el.show === “function”) el.show();
console.log(“[expand] OK ->”, id);
} catch (
) {}
});
}

/** Debug: stampa tutti i tipi di componenti principali della pagina /
function dumpTypesForDebug() {
try {
const all = $w('
');
const summary = {};
all.forEach(el => {
summary[el.type] = (summary[el.type] || 0) + 1;
});
console.log(“[diag] Tipi componenti in pagina:”, summary);
} catch (e) {
console.log(“[diag] dumpTypesForDebug errore”, e);
}
}