4
votes

I have this code:
App.vue

<template>
  <v-container>
    <div>
      <schedule-table
      v-if = "schedule.length > 0"
      :exercises="schedule[0].exercises"
      />
    </div>
  </v-container>
</template>
<script lang="ts">

import Vue from "vue";
import { Component } from "vue-property-decorator";
import ScheduleTable from '@/components/ScheduleTable.vue'

@Component({
  components: {
    ScheduleTable,
  }
})
</script>

ScheduleTable.vue

<template>
  <v-container>
    <schedule-week
    :exercises="exercises"
    />
  </v-container>
</template>
<script lang="ts">
import Vue from "vue";
import { Component, Prop } from "vue-property-decorator";
import { IExercise } from "@/interfaces"
import ScheduleWeek from '@/components/ScheduleWeek.vue'

@Component({
  name: 'ScheduleWeek',
  components: {
    ScheduleWeek,
  }
})

@Component
export default class ScheduleTable extends Vue {
  @Prop( {required: true, type: Array } ) readonly exercises!: IExercise;
}
</script>

ScheduleWeek.vue

<template>
  <v-container
  :ex="exercises"
  >
    here is tables (but this tables dosn't show and any other text dosn't show)
  </v-container>
</template>
<script lang="ts">
import Vue from "vue";
import { Component, Prop } from "vue-property-decorator";
import { IExercise } from "@/interfaces"


@Component
export default class ScheduleWeek extends Vue {
  @Prop( {required: true, type: Array } ) readonly exercises!: IExercise;
}
</script>

And have vue warn:

Unknown custom element: < schedule-week > - did you register the component correctly? For recursive components, make sure to provide the "name" option.

How to fix this problem? How to register component correctly?

2

2 Answers

12
votes

There are multiple ways to declare a vue-component when you use typescript. The class-based SFC approach (the one you are using) needs to follow a slightly different syntax. You used the typescript decorator twice in your schedule-week component

App.vue

<v-container>
    <div>
      <schedule-table
      v-if = "schedule.length > 0"
      :exercises="schedule[0].exercises"
      />
    </div>
  </v-container>
</template>
<script lang="ts">

import { Component, Vue } from "vue-property-decorator"; // you can import vue here
import ScheduleTable from '@/components/ScheduleTable.vue'

@Component({
  components: {
    ScheduleTable,
  }
})
export default class App extends Vue {} // the @Component() decorator needs to be followed by the exported class

Correspondingly your other components:

ScheduleTable.vue

<template>
  <v-container>
    <schedule-week
    :exercises="exercises"
    />
  </v-container>
</template>
<script lang="ts">
import { Component, Vue, Prop } from "vue-property-decorator"; // see above
import { IExercise } from "@/interfaces"
import ScheduleWeek from '@/components/ScheduleWeek.vue'

@Component({
  name: 'ScheduleTable',
  components: {
    ScheduleWeek,
  }
}) // >>>don't use the decorator twice<<<
export default class ScheduleTable extends Vue {
  @Prop( {required: true, type: Array } ) readonly exercises!: IExercise;
}
</script>

ScheduleWeek.vue

<template>
  <v-container
  :ex="exercises"
  >
    here is tables (but this tables dosn't show and any other text dosn't show)
  </v-container>
</template>
<script lang="ts">
import { Component, Vue, Prop } from "vue-property-decorator"; // see above
import { IExercise } from "@/interfaces"


@Component
export default class ScheduleWeek extends Vue {
  @Prop( {required: true, type: Array } ) readonly exercises!: IExercise;
}
</script>

##EDIT:

From the officiel TypeScript Documentation:

With the introduction of Classes in TypeScript and ES6, there now exist certain scenarios that require additional features to support annotating or modifying classes and class members. Decorators provide a way to add both annotations and a meta-programming syntax for class declarations and members.

Decorators are basically TypeScript(JavaScript) functions which are used to add additional information to the following class (your component) or class members. This also means a decorator cannot stand alone. The @Component() decorator takes an Object as parameter which is 'as-is' translated into component-options.

1
votes

TL;DR

To register the components SubOne and SubTwo in MyComponent, pass it to the @Component decorator:

import { Component, Vue } from "vue-property-decorator";

@Component({
  components: {
    SubOne,
    SubTwo,
  }
}) 
export default class MyComponent extends Vue {
  …
}

And make sure you also decorate the SubComponents like so;

import { Component, Vue } from "vue-property-decorator";

@Component
export default class SubOne extends Vue {
  …
}

Error in @MarcRo's answer

Setup and resulting Error

In the Component ScheduleTable.vue, the decorator @Component gets the parameter name set to the Component it is about to import. This leads to a recursive call of said Component and hence an Error.

Fix

Set name: 'ScheduleTable' - or even drop it. The class name seems to be used (which is what we are doing).

Aside

I could not find a doc on what can actually passed to the decorator, but it's used like this in @MarcRo's answer in App.vue as well as here. (The link in the comments there seems to be old).

I don't have enought reputation to comment and a fixing edit got rejected, so sorry for the extra post.

Thank you @MarcRo for teaching me how to use this and the facepalm moment after solving the recursion error after a way too long time ;)