Upgrade from 1.x to 2.0
2.0 rebuilds registration, invalidation and events, unifies naming and removes vue-demi. Most pages need only a few changes. Projects that cannot upgrade can consult the 1.x documentation.
Upgrade steps
- Use Vue 2.7 or later (Vue 3 is unaffected).
- Run
pnpm add vuepg@^2. - Apply the replacements below.
- Enable
debug: trueand check the main pages' focus behavior.
Environment
| 1.x | 2.0 |
|---|---|
Vue 2.6 with @vue/composition-api | Minimum Vue 2.7 |
| Depends on vue-demi | Zero runtime dependencies |
| ESNext output | ES2015 output, compatible with webpack 4 |
addEventListener keyboard listener on import | Listener on plugin installation |
Installation and configuration
| 1.x | 2.0 |
|---|---|
app.use(vuEPG) then setConfig | app.use(VuEPG, config); setConfig remains available |
defBackHandler | backHandler |
tempBackHandler | Removed internal state; use onBack |
inject("epg") | Removed; use useVuEPG() or $epg |
| — | New global property $epg |
// 1.x
const epg = useVuEPG();
epg.setConfig({ defBackHandler: () => router.back() });
app.use(vuEPG);
// 2.0
app.use(VuEPG, { backHandler: () => router.back() });Directives
| 1.x | 2.0 |
|---|---|
v-epg-item="{ class: 'x' }" | v-epg-item="{ focusClass: 'x' }" |
| — | disabled on items and groups |
Events
Events are native CustomEvents with the epg- prefix, avoiding collisions with native focus and blur events from buttons and links. See Events.
| 1.x | 2.0 |
|---|---|
@focus / @blur | @epg-focus / @epg-blur |
@up / @down / @left / @right | @epg-up / @epg-down / @epg-left / @epg-right |
Group @enter | @epg-enter whenever focus enters from outside (1.x only fired when entering a nested group) |
Group @leave (not implemented) | @epg-leave |
Item @enter on focus | Removed; use @epg-focus |
@up="" blocks default movement whenever a listener exists | @epg-up.prevent explicitly cancels; observing alone does not block |
@up="epg.move(top)" | @epg-up="epg.move(top)"; changing focus skips default movement |
Handler receives (item, next) | Event object with event.detail of { node, direction } |
| Checks only the innermost group's direction event | Checks each group being exited |
Group direction events also fire for epg.move("up") | Fire for user directional input |
<!-- 1.x -->
<div v-epg-item @focus="onFocus" @up="">...</div>
<!-- 2.0 -->
<div v-epg-item @epg-focus="onFocus" @epg-up.prevent>...</div>Behavior changes
| Scenario | 1.x | 2.0 |
|---|---|---|
| Direction key with no focus | Moves from the first registered item | Selects the page entry (default first) |
| Focus hidden or cached by KeepAlive | Input stops responding | Recovers at the page entry |
| Move to an empty group | No movement or result | Returns false; empty groups are not targets |
Focused element re-renders, e.g. :class changes | Focus class may disappear | Restores the class |
Nested components register onBack | Overwrite each other; unmounting clears the parent's handler | Active nested handler takes priority and restores after unmount |
| Return value of movement methods | None | Boolean indicating successful movement |
API replacements
| 1.x | 2.0 |
|---|---|
getFoucsClass() | getFocusClass() |
getTargetByDirection(direction) | findTarget(direction) |
getItemByHTMLElement(el) | getNodeByElement(el) + isEPGItem() |
getGroupByHTMLElement(el) | getNodeByElement(el) + isEPGGroup() |
getChild(el) | getNodeByElement(el) |
isEPGItem(el) / isEPGGroup(el) take elements | Type guards take nodes; for an element use isEPGItem(getNodeByElement(el)) |
getGroupByItem(item) | getParentGroup(item) |
getParentGroupByHTMLElement(el) | getParentGroup(el) |
getGroupChildrenByHTMLElement(el) | getChildren(group) |
getGlobalGroupChildren() | getChildren() |
group.children | getChildren(group) |
getItemsByGroup(group) returns elements | getItemsInGroup(group) returns EPGItems |
getParentsByHTMLElement(el) | Removed; use DOM APIs |
item.isFocus | getCurrentItem() === item |
Internal dataContainer, currentConfig, keyActions, registerItem, etc. | Removed |
Key API replacements
| 1.x | 2.0 |
|---|---|
getCurrentKeyActions() | getKeyActions() (read-only snapshot) |
setAction(name, codes, callback, preventDefault) | setKeyAction(name, { codes, callback, preventDefault }) |
removeAction(name) | removeKeyAction(name); removing built-ins throws |
setActionCallback(name, callback) | updateKeyAction(name, { callback }) |
setActionPreventDefault(name, value) | updateKeyAction(name, { preventDefault: value }) |
addCodeToAction(name, codes) | addKeyCodes(name, codes) |
removeCodeFromAction(name, codes) | removeKeyCodes(name, codes) |
Nonexistent action logs console.error | Throws |
PAGEACTION | PAGE |
Callback (code) | (code, event) |
// 1.x
epg.setAction("ALERT", ["KeyK", 75], () => alert("K"), false);
epg.setActionPreventDefault("ALERT", true);
// 2.0
epg.setKeyAction("ALERT", { codes: ["KeyK", 75], callback: () => alert("K") });
epg.updateKeyAction("ALERT", { preventDefault: true });Dialogs and native Back input
2.x rejects targets that have not rendered. After changing v-show or mounting a dialog, wait for nextTick() before moving focus:
show.value = true;
await nextTick();
epg.move(cancel.value);Replace empty direction listeners with explicit cancellation such as @epg-left.prevent. When closing a dialog, check that the original target is still mounted and available before restoring focus; otherwise select an application entry.
Android Back callbacks can call epg.back(); directions use epg.navigate(). See the complete example and native input.