Skip to main content

Controlling Flicking

Patterns and best practices for controlling Flicking programmatically, responding to events, and handling errors.

Framework-Specific Guides

For detailed information on accessing methods and handling events in your framework, see:


Method Patterns

Common patterns for controlling Flicking programmatically. See the Flicking API for complete method reference.

Sequential Navigation

// Navigate through panels in sequence
async function autoNavigate() {
for (let i = 0; i < flicking.panelCount; i++) {
await flicking.moveTo(i, 1000);
await new Promise(resolve => setTimeout(resolve, 2000));
}
}

Conditional Navigation

// Only move if not already at the target
async function moveToIfNeeded(targetIndex) {
if (flicking.index !== targetIndex) {
await flicking.moveTo(targetIndex);
}
}

Handling Interruptions

// Handle animation interruptions gracefully
async function safeNext() {
try {
await flicking.next();
console.log("Successfully moved to next panel");
} catch (error) {
if (error.code === ERROR_CODE.ANIMATION_ALREADY_PLAYING) {
console.log("Animation already in progress, skipping");
} else if (error.code === ERROR_CODE.ANIMATION_INTERRUPTED) {
console.log("Animation interrupted by user");
} else {
throw error; // Re-throw unexpected errors
}
}
}

Event Patterns

Understanding Flicking's event system. See Event Interfaces for complete event reference.

Event Timeline

Understanding when events fire is crucial for building responsive UIs. Here's the complete timeline of events during user interaction:

User starts dragging

[holdStart] ← Touch/mouse down

[moveStart] ← Movement begins

[move] ← Continuously fired during movement

[willChange] ← BEFORE panel index changes (cancellable)

[changed] ← AFTER panel index changes

[moveEnd] ← Movement animation ends

[holdEnd] ← Touch/mouse up

Key Events

Panel Change Events

  • willChange - Fired BEFORE panel changes (cancellable with e.stop())
  • changed - Fired AFTER panel changes

Movement Events

User Input Events

Other Events


Event Usage Patterns

Syncing Multiple Flicking Instances

const flicking1 = new Flicking("#carousel1");
const flicking2 = new Flicking("#carousel2");

flicking1.on(EVENTS.CHANGED, (e) => {
flicking2.moveTo(e.index);
});

flicking2.on(EVENTS.CHANGED, (e) => {
flicking1.moveTo(e.index);
});

Progress Tracking

let startPosition = 0;

flicking.on(EVENTS.MOVE_START, (e) => {
startPosition = e.axesEvent.pos.flick;
});

flicking.on(EVENTS.MOVE, (e) => {
const currentPosition = e.axesEvent.pos.flick;
const distance = currentPosition - startPosition;
console.log("Dragged distance:", distance);
});

Conditional Panel Change

flicking.on(EVENTS.WILL_CHANGE, (e) => {
// Require minimum drag distance
if (Math.abs(e.axesEvent.delta.flick) < 50) {
e.stop();
console.log("Drag distance too small, preventing change");
}
});

Error Handling Patterns

Flicking throws FlickingError instances with ERROR_CODE constants. See FlickingError API for complete error reference.

Graceful Degradation

async function safeNavigation(targetIndex) {
try {
await flicking.moveTo(targetIndex);
return true;
} catch (err) {
if (err instanceof FlickingError) {
switch (err.code) {
case ERROR_CODE.ANIMATION_ALREADY_PLAYING:
// Queue the action for later
setTimeout(() => safeNavigation(targetIndex), 300);
return false;

case ERROR_CODE.INDEX_OUT_OF_RANGE:
console.warn("Invalid index, moving to first panel");
await flicking.moveTo(0);
return false;

case ERROR_CODE.ANIMATION_INTERRUPTED:
// User interrupted, that's okay
return false;

default:
throw err;
}
}
throw err;
}
}

Debounced Navigation

let navigationTimeout = null;

function debouncedNext() {
if (navigationTimeout) {
clearTimeout(navigationTimeout);
}

navigationTimeout = setTimeout(async () => {
try {
await flicking.next();
} catch (err) {
if (err instanceof FlickingError &&
err.code === ERROR_CODE.ANIMATION_ALREADY_PLAYING) {
// Retry after animation completes
debouncedNext();
}
}
}, 100);
}

User-Friendly Error Messages

function getUserFriendlyMessage(error) {
if (!(error instanceof FlickingError)) {
return "An unexpected error occurred";
}

switch (error.code) {
case ERROR_CODE.ANIMATION_ALREADY_PLAYING:
return "Please wait for the current animation to complete";

case ERROR_CODE.INDEX_OUT_OF_RANGE:
return "The requested panel does not exist";

case ERROR_CODE.ANIMATION_INTERRUPTED:
return "Navigation was interrupted";

case ERROR_CODE.NO_ACTIVE:
return "No panels available";

default:
return error.message;
}
}

// Usage
try {
await flicking.moveTo(targetIndex);
} catch (err) {
showToast(getUserFriendlyMessage(err));
}