Vue.js single file component 'name' not honored in consumer
Asked Answered
E

1

17

Please pardon my syntax, I'm new to vue.js and may not be getting the terms correct.

I've got a single file component (SFC) named CreateTodo.vue. I've given it the name 'create-todo-item' (in the name property). When I import it in my app.vue file, I can only use the component if I use the markup <create-todo>. If I use <create-todo-item>, the component won't render on the page.

I've since learned that I can do what I want if I list the component in my app.vue in the format components: { 'create-todo-item': CreateTodo } instead of components: { CreateTodo }.

My question is this: is there any point to giving the component a name in the name property? It's not being honored in the consumer, and if I leave it empty, the app runs without error.

Also, am I correct in my belief that vue-loader is assigning the kebab-case element name for template use based on the PascalCase import statement?

Bad - component name property

Here's the code where I try to name the SFC (CreateTodo.vue)

<script>
  export default {
    name: 'create-todo-item',
    data() {
      return {
        titleText: '',
        projectText: '',
        isCreating: false,
      };
    },
};
</script>

The name as listed in the component is ignored by my App.vue. The html renders fine even though I have the element <create-todo> instead of <create-todo-item>:

<template>
  <div>
    <!--Render the TodoList component-->
    <!--TodoList becomes-->
    <todo-list v-bind:todos="todos"></todo-list>
    <create-todo v-on:make-todo="addTodo"></create-todo>
  </div>
</template>

<script>
  import TodoList from './components/TodoList.vue'
  import CreateTodo from './components/CreateTodo.vue'

  export default {
    name: 'app',
    components: {
      TodoList,
      CreateTodo,
    },
    // data function avails data to the template
    data() {
      return {
      };
    },
    methods: {
      addTodo(todo) {
        this.todos.push({
          title: todo.title,
          project: todo.project,
          done: false,
        });
      },
    }
  };
</script>

Good - don't use component name property at all

Here's my CreateTodo.vue without using the name property:

<script>
  export default {
    data() {
      return {
        titleText: '',
        projectText: '',
        isCreating: false,
      };
    },
};
</script>

And here's my App.vue using the changed component:

<template>
  <div>
    <!--Render the TodoList component-->
    <!--TodoList becomes-->
    <todo-list v-bind:todos="todos"></todo-list>
    <create-todo-item v-on:make-todo="addTodo"></create-todo-item>
  </div>
</template>

<script>
  import TodoList from './components/TodoList.vue'
  import CreateTodo from './components/CreateTodo.vue'

  export default {
    name: 'app',
    components: {
      TodoList,
      'create-todo-item': CreateTodo,
    },
    // data function avails data to the template
    data() {
      return {
      };
    },
    methods: {
      addTodo(todo) {
        this.todos.push({
          title: todo.title,
          project: todo.project,
          done: false,
        });
      },
    }
  };
</script>
Epicurus answered 21/5, 2018 at 23:5 Comment(1)
The documentation outlines everything you need to know. See vuejs.org/v2/api/#name and vuejs.org/v2/guide/components-registration.html#Component-NamesShowthrough
N
26

First note that the .name property in a SFC module is mostly just a convenience for debugging. (It's also helpful for recursion.) Other than that, it doesn't really matter when you locally register the component in parent components.

As to the specific details, in the first example, you're using an ES2015 shorthand notation

components: {
    TodoList,
    CreateTodo,
},

is equivalent to

components: {
  'TodoList': TodoList,
  'CreateTodo': CreateTodo
},

so that the component that is imported as CreateTodo is given the name 'CreateTodo' which is equivalent to <create-todo>.

In the second example, you give the name explicitly by forgoing the shorthand notation

components: {
  TodoList,
  'create-todo-item': CreateTodo,
},

That's equivalent, btw to

components: {
  TodoList,
  'CreateTodoItem': CreateTodo,
},

So you can see, in that case, that you're giving the component the name 'CreateTodoItem' or, equivalently, <create-todo-item>

Nena answered 22/5, 2018 at 0:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.