Comments (30)
[UPDATED for @vue/composition-api
>= v1.0.0-beta.22
]
I don't know if that's still relevant to anyone but I ended up making my own (very simple) composable function:
import Vue from 'vue'
import { getCurrentInstance } from '@vue/composition-api'
import { NavigationGuard } from 'vue-router'
import { ComponentOptions } from 'vue/types/umd'
export function onHook(
name: keyof ComponentOptions<Vue>,
callback: (...args: any) => void
) {
const vm = getCurrentInstance()
const merge = Vue.config.optionMergeStrategies[name]
if (vm && merge) {
const prototype = Object.getPrototypeOf(vm.proxy.$options)
prototype[name] = merge(vm.proxy.$options[name], callback)
}
}
export function onBeforeRouteUpdate(callback: NavigationGuard<Vue>) {
return onHook('beforeRouteUpdate', callback)
}
export function onBeforeRouteLeave(callback: NavigationGuard<Vue>) {
return onHook('beforeRouteLeave', callback)
}
You can then simply use it as a regular "composable" hook:
import { onBeforeRouteUpdate } from '@/composables/router'
export default {
setup() {
onBeforeRouteUpdate((to, from, next) => {
// your logic
next()
})
}
}
from composition-api.
Any progress about this kind of support in @vue/composition-api? Maybe supporting some kind of onBeforeRouteUpdate()
/ onBeforeRouteLeave()
hooks inside setup()
?
from composition-api.
Well, I found a work around:
beforeRouteLeave(to: any, from: any, next: any) {
from.matched[0].instances.default.doFunction();
next();
},
Although, this doesn't really seem like the ideal solution.
If anyone knows a better way then let me know.
PS. You need to make sure that the function is in the return of the setup() function.
from composition-api.
@melenaos that composition function is a workaround for Vue 2. Vue Router Next should support this natively https://next.router.vuejs.org/guide/advanced/composition-api.html#navigation-guards in Vue 3
from composition-api.
@yassipad It appears that the hooks are not cleaned up properly. I'm using beforeRouteLeave
, the first time I leave the route the hook fires once, the second time I leave the hooks it fires twice and so on. Any idea how to cleanup the hook when leaving?
from composition-api.
@bcronje I believe I came up with a simple fix to clean up the hooks. When I log out the prototype[name] object I get an ever-increasing array of functions where each function is the hook defined in my component. Clearing out the value if something is already defined for prototype[name] fixes the issue. Hook function is below:
export function onHook(
name: keyof ComponentOptions<Vue>,
callback: (...args: any) => void
) {
const vm = getCurrentInstance()
const merge = Vue.config.optionMergeStrategies[name]
if (vm && merge) {
const prototype = Object.getPrototypeOf(vm.proxy.$options)
if (prototype[name]) {
delete prototype[name];
}
prototype[name] = merge(vm.proxy.$options[name], callback)
}
}
from composition-api.
export function onHook( name: keyof ComponentOptions<Vue>, callback: (...args: any) => void ) { const vm = getCurrentInstance() const merge = Vue.config.optionMergeStrategies[name] if (vm && merge) { const prototype = Object.getPrototypeOf(vm.$options) prototype[name] = merge(vm.$options[name], callback) } }
I've had to change
const prototype = Object.getPrototypeOf(vm.$options);
prototype[name] = merge(vm.$options[name], callback);
to
const prototype = Object.getPrototypeOf(vm.proxy.$options);
prototype[name] = merge(vm.proxy.$options[name], callback);
from composition-api.
I edited my initial comment, thanks for the update 👍
from composition-api.
I don't think beforeRouteEnter
is possible as it's executed before a view component is mounted. Once the setup
function is called, the navigation has already been confirmed
from composition-api.
How are you working around this? Watchers on props?
from composition-api.
@timshannon for the beforeRouteEnter
guard, I suppose a possible workaround is using beforeEnter
guard (defined directly in router, not in component) instead. For the other guards, one needs to deliver proper hooks like onBeforeRouteUpdate
and onBeforeRouteLeave
for Composition API.
What I'm doing in the moment is just not using Compostion API at all for components that need navigation guards.
from composition-api.
The beforeRouteEnter is working for me. Looks like it was added in v0.3.2.
from composition-api.
A couple of notes that I found when using beforeRouteEnter:
any data that you pass back to the component like
next(vm => {
vm.foo = 'bar';
});
Won't be available in the setup() method initially. It will work in your template as long as you pass it through the return{}, but if you need to access the data in the setup method you will need to do 2 things.
- Access after a tick like
context.root.$nextTick(() => { console.log(foo);});
- The variable has to be declared in the return{} even if you don't plan on using it in the template. I am not sure why this is the case. This just might be a bug with the plugin and will get resolved with Vue 3, but I will keep track of the issue #184.
from composition-api.
Navigation guards only seem to work when accessing the vm in the next() function.
However, I can't get them to work otherwise.
example:
export default createComponent({
beforeRouteLeave() {
doFunction();
}
setup() {
function doFunction() {
// Do Stuff
}
return {
doFunction
};
}
}
How can I call a function from beforeRouteLeave that is in the setup() function without using the next(vm => {});
In the Options API you would use this.doFunction();
So what is the equivalent in the new Composition API?
from composition-api.
Well, now I need to use beforeRouteUpdate and running next() seems to re-run setup(). Which in turn overwrites any data I set using "from.matched[0].instances.default". I tried using a setTimeout or NextTick, but the data does not get updated. So it seems that beforeRouteEnter
works has you have access to the callback and beforeRouteLeave
works sort of with "from.matched[0].instances.default". But beforeRouteUpdate
doesn't seem to work as you lose context after next() runs.
The issue I am facing is switching routes within path/:id
so switching from path/12 to path/13 doesn't allow me to swap out the item.
from composition-api.
Any new on this? I've got a similar problem. I want to call a function from beforeRouteLeave()
. The function is defined inside of setup()
in order to have access to the refs that are defined there.
So my code looks a bit like this (abbreviated):
setup() {
const titleEditor = ref(null);
const textEditor = ref(null);
function flushEditors() {
if (textEditor.value) {
textEditor.value.flushEvents();
}
if (titleEditor.value) {
titleEditor.value.flushEvents();
}
}
return { flushEditors };
},
beforeRouteLeave(_to: Route, _from: Route, next: NavigationGuardNext) {
this.flushEditors();
next();
}
This works, but TypeScript is throwing errors because there is no typing for flushEditors()
on this
. Also, I have a feeling that this won't work in Vue 3. Any ideas or hints?
from composition-api.
The composable function of @yassipad doesn't work in Vue3 because of Vue.config.optionMergeStrategies
.
Is there anyone that could point me to the right direction to make this work in Vue3?
Also the beforeRouteLeave isn't triggered in Vue3. Maybe it's removed as suspected by @sseeland.
from composition-api.
from composition-api.
@yassipad hello, thank you for the solution. Unfortunately with vue2 composition api it does not work for me
export const Navbar = defineComponent({
setup() {
onBeforeRouteUpdate((to, from, next) => {
console.log([to, from]);
next();
});
nothing happens when I switch route. maybe because we use children routes?
the main route always remains /
and only children routes will change on navigation.
what would be a solution in this case?
from composition-api.
this is what I ended up with
export const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes,
});
const observableRoute: {route: Route | {}} = {
route: {}
};
const routeData = Vue.observable(observableRoute);
router.afterEach(route => {
routeData.route = route;
});
export function useCurrentRoute() {
return computed(() => routeData.route as Route);
}
and usage
setup() {
const currentRoute = useCurrentRoute();
from composition-api.
@seyfer Hi, I just made a very quick test using Vue2+VueComposition API and it seems to be working fine (https://codepen.io/yassipad/pen/gOMjzOe). What do you mean when you say you're using children routes?
@melenaos The hooks are indeed already available in VueRouter Next. Also, Vue.config.optionMergeStrategies
is still accessible but it is now context specific: vm.root.appContext.config.optionMergeStrategies
.
from composition-api.
@bcronje I'm assuming you're using Vue 3 (since you're using "proxy"), in which case you shouldn't have to use my helper functions as those are already included in vue-router
https://next.router.vuejs.org/guide/advanced/composition-api.html#navigation-guards
from composition-api.
@yassipad no Vue 2 with latest composition API. vm.$options is undefined for me. getCurrentInstance
returns ComponentInternalInstance
that does not have $options
defined, it is however defined on ComponentInstance
which is available under proxy
. Unless I'm doing something wrong.
from composition-api.
@bcronje Sorry, you're absolutely right, I didn't see that was changed since:
https://github.com/vuejs/composition-api/releases/tag/v1.0.0-beta.22
from composition-api.
I edited my initial comment, thanks for the update 👍
Thank you for the code, saved me quite some time to figure it out by myself!
from composition-api.
@bcronje I believe I came up with a simple fix to clean up the hooks. When I log out the prototype[name] object I get an ever-increasing array of functions where each function is the hook defined in my component. Clearing out the value if something is already defined for prototype[name] fixes the issue. Hook function is below:
export function onHook( name: keyof ComponentOptions<Vue>, callback: (...args: any) => void ) { const vm = getCurrentInstance() const merge = Vue.config.optionMergeStrategies[name] if (vm && merge) { const prototype = Object.getPrototypeOf(vm.proxy.$options) if (prototype[name]) { delete prototype[name]; } prototype[name] = merge(vm.proxy.$options[name], callback) } }
@Genoe I ended doing something very similar, basically return an unregister hook that does the same delete:
export function onHook(name: keyof ComponentOptions<Vue>, callback: (...args: any) => void): () => void {
const vm = getCurrentInstance();
const merge = Vue.config.optionMergeStrategies[name];
if (vm && merge) {
const prototype = Object.getPrototypeOf(vm.proxy.$options);
prototype[name] = merge(vm.proxy.$options[name], callback);
return () => {
delete prototype[name];
};
}
// eslint-disable-next-line @typescript-eslint/no-empty-function
return () => {};
}
Then using the hooks I can unregister before leaving e.g.
const unregisterRouteLeave = onBeforeRouteLeave(async (_to, _from, next) => {
if (await confirmUnsavedForm(originalModel.value, model.value)) {
unregisterRouteLeave();
next();
} else {
next(false);
}
});
from composition-api.
Stale issue message
from composition-api.
@seyfer Hi, I just made a very quick test using Vue2+VueComposition API and it seems to be working fine (https://codepen.io/yassipad/pen/gOMjzOe). What do you mean when you say you're using children routes?
@yassilah When you have index.ts, and then another index with routes for each section, like f.e. todo-index.ts and post-index.ts
Then we can define index routes
import todoRoutes from `todo-index.ts`;
import postRoutes from `post-index.ts`;
const routes: RouteConfigSingleView[] = [
{
path: '/todos',
name: 'todos',
component: TodosLayout,
children: todoRoutes,
},
{
path: '/'posts,
component: PostsLayout,
children: postsRoutes,
},
And in the children routes we have
export const todoRoutes: RouteConfigSingleView[] = [
{
path: '/add',
name: 'add-todo',
component: AddTodoPage,
},
export const postRoutes: RouteConfigSingleView[] = [
{
path: '/edit',
name: 'edit-post',
component: EditPostPage,
},
this is an example of when it does not work.
from composition-api.
export default createComponent({
beforeRouteLeave() {
doFunction();
}
setup() {
}
}
"@vue/composition-api": "1.0.5"
Like this, I write it in page view. It run normally!
from composition-api.
export function onHook( name: keyof ComponentOptions<Vue>, callback: (...args: any) => void ) { const vm = getCurrentInstance() const merge = Vue.config.optionMergeStrategies[name] if (vm && merge) { const prototype = Object.getPrototypeOf(vm.$options) prototype[name] = merge(vm.$options[name], callback) } }I've had to change
const prototype = Object.getPrototypeOf(vm.$options); prototype[name] = merge(vm.$options[name], callback);to
const prototype = Object.getPrototypeOf(vm.proxy.$options); prototype[name] = merge(vm.proxy.$options[name], callback);
It worked for me in Vue 2.7
and Vue Router ^3.4.9
from composition-api.
Related Issues (20)
- Typing component refs HOT 2
- onMounted is called when there is no active component instance to be associated with HOT 7
- Variables created with ref in <templete>,do not automatically expand value HOT 4
- why setup run twice in vue2 HOT 8
- setup function provide a wrong prop type,when use type: Function HOT 3
- not work nice in web component, no error HOT 2
- How to avoid duplicate register composition-api ? HOT 1
- It doesn't work with nuxt 2 HOT 2
- watch 的回调如果发生错误,会一直触发调用 HOT 1
- ComponentRenderProxy类型与Vue不兼容,导致Ts编译报错 HOT 2
- vue2项目, 怎么在option API的基础上, 混用composition API? HOT 1
- render 函数中使用 web components 自定义标签,移除了HTML中原生的 slot 属性 HOT 3
- No support for Vue >= 2.7
- cdn方式引入导致vue devtools调试数据丢失 HOT 2
- 客户端使用vuecli 打包出来的commonjs模式的库,出现“Error: [vue-composition-api] must call Vue.use(VueCompositionAPI) before using any functio” HOT 2
- setup返回的data在development环境下会被expose到全局mixin的data中 HOT 2
- 是否有提供withDefaults?
- 安装时,报vue版本范围错误 HOT 2
- 【Bug】Memory Leak cause by toVue3ComponentInstance HOT 1
- 【BUG】watch() 传入reactive类型的数据,vue3.4与3.3表现不一致 HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from composition-api.