Can't access $route.params in TS class

AndrewBogdanovTSS
69
AndrewBogdanovTSS
commented 2 years ago

I've created a dynamically routed page _id.vue inside of my pages folder and I want to have access to that id property inside of my TS class. I can access it in my template by writing {{$route.params.id}} but when I try to reference $route inside of the class I get an error:
error TS2304: Cannot find name '$route'.
I've tried to reference it using this like so
this.$route.params
but then I get TS precompile error:
error TS2339: Property '$route' does not exist on type 'default'.
I also tried to reference it without a $ sign like so
this.route.params
but still got the same error.
How can I access route params?

0
qm3ster
383
qm3ster
commented 2 years ago

You can define a class that includes everything you usually inject.

import {Route} from 'vue-router'

class VueWithRoute extends Vue {
    $route: Route
}

@Component
export default class MyComp extends VueWithRoute {
    click() {console.log(this.$route)}
}

You can define an interface and also reuse it between components.

import {Route} from 'vue-router'

interface WithRoute /* can also extend Vue to make sure nothing is colliding */ {
    $route: Route
}

@Component
export default class MyComp extends Vue implements WithRoute {
    click() {console.log(this.$route)}
}

You can define in the specific component.

import {Route} from 'vue-router'

@Component
export default class MyComp extends Vue {
    $route: Route
    click() {console.log(this.$route)}
}

I basically never end up using the last one because inline definitions are usually less specific than classes and interfaces. eg:

type VueRefs = Vue['$refs']
interface MyRefs extends VueRefs {
    input: HTMLInputElement
}

but inline I could only do

@Component
export default class MyComp extends Vue {
    $refs: Vue['$refs'] & {
        input: HTMLInputElement
    }
}
0
AndrewBogdanovTSS
69
AndrewBogdanovTSS
commented 2 years ago

@qm3ster thanks for such a broad set of examples, but I have one additional use case I can't figure out. I want to filter values from my store based on id param I'm getting inside $route.params.
So basically it looks like this:
@State(state => state.houses.filter(h => h._id === this.$route.params.id)) house
but this.$route isn't defined although available in mounted hook for example. So my question is how can I get it when I define a property in my class?
Full example

import Vue from "vue"
  import Component from "nuxt-class-component"
  import {Route} from "vue-router"
  import {State, Action, Getter, namespace} from "vuex-class"

  interface WithRoute{
    $route: Route
  }

  @Component
  export default class extends Vue implements WithRoute{
    @State(state => state.houses.filter(h => h._id === this.$route.params.id)) house // Not working here
    mounted(){
      console.log("params:", this.$route.params.id) // Works here
    }
  }
0
hartmut-co-uk
20
hartmut-co-uk
commented 2 years ago

this in decorator?
Maybe try to do the filtering via a computed property based on the unfiltered @State houses ?

0
AndrewBogdanovTSS
69
AndrewBogdanovTSS
commented 2 years ago

@hartmut-co-uk you mean smth. like this?

get house(){
      return this.houses.filter(h => h._id === this.$route.params.id)[0];
    }
0
hartmut-co-uk
20
hartmut-co-uk
commented 2 years ago

yes, looks good to me - is it working?

0
AndrewBogdanovTSS
69
AndrewBogdanovTSS
commented 2 years ago

yes, it is :) That's the solution I've stopped on after I've logged this issue)

0
AndySham
0
AndySham
commented 7 months ago

To anyone coming across this thread, a much better solution is:

import { Vue } from 'vue-property-decorator'
import 'vue-router/types/vue'

@Component
export default class MyComp extends Vue {
    click() {console.log(this.$route)}
}

No need to import any runtime classes or declare your own types, you just need to manually import the default vue-router typings.
I had the same issue for the $store property injected by Vuex, and it can be solved in the same way

0
Informations
Question โ€ข Unresolved
#c16 - Created 2 years ago