Attribute "id" is ignored on component - vue.js

I persistently getting this warning on my vuejs app, dint know where and why:
build.js:9371 [Vue warn]: Attribute "id" is ignored on component <div> because the component is a fragment instance
I am using vue-router, with index.html:
<body>
<div id="app"></div>
</body>

Just to add to what #Roy J has said. Look through your components. Make sure that all your components have one wrapping dom element around them, like a single parent. The best thing to always do is wrap all elements in your components in one parent div.
Something like this:
<div>
<div>Some content</div>
<div> some more content </div>
</div>
That way, Vue know how to mount your component on the parent app. If your component is fragmented, you'll get the error you are talking about. Vue sometimes doesn't tell you which component exactly so you'll have to skim through all your components.

If your component does not have a single containing DOM element, it is a fragment instance and can't have an id. That is, if it expands to
<div></div>
<div></div>
<div></div>
there's no correct place to put the id.

Related

Is there a way to pass elements to a vue component?

when I need to pass some information between child and parent element I use props. But is there a way to pass elements to the component, for example like this
<MyComponent>
<router-link to="/oneOfTheList">OneOfTheList</router-link>
</MyComponent>
Router-Link seems to do it somehow...
How can I specify where the elements will be placed in my component
This is called slot
ComponentA.vue
<div>
<slot></slot>
</div>
ComponentB.vue
<component-a>
<span>test</span> // this part will be shown inside component A's slot tags
</component-a>
Here you go

vue passing props to sub component will generate html attributes to wrapper root

So I have this component PageWrapper that has a title props.
<div id="page-wrapper">
<h1>{{title}}</h1>
<slot />
</div>
And I have a wrapper component that forwards most props to its child:
<PageWrapper v-bind="[$attrs]">
<slot name="default"/>
</PageWrapper>
It works as expected, except that my page wrapper root has an extra title html attribute that I don't want to be there.
<div id="page-wrapper" title="My Title">
<h1>My title</h1>
<!-- rest of the page -->
</div>
I have the feeling there is a confusion between html attributes and vue properties when forwarding to sub-component.
I thought this had to do with the difference between $props and $attrs but apparently not as it doesn't work in any case.
Can someone clarify this for me? How can I avoid this html-attributes behavior?
Cheers
you do not want to bind the attributes to the PageWrapper Component.
Instead just bind the title property.
<PageWrapper :title="title">
<slot name="default"/>
</PageWrapper>
EDIT:
Might also try to bind the attributes without the square brackets v-bind="$attrs"

how can i pass registered vue component as prop to a component

Need to pass component to child component, using props or you have better way to solve this problem
I registered component needed to pass globally or just registered this component locally. But these solutions can't solve my problem.
Here is my code to register component needed to pass locally:
a.vue html
<dropdown :icon="UserIcon"></dropdown>
a.vue js
components: {'dropdown', Dropdown, 'icon-user': UserIcon}
dropdown.vue html
<div class="dropdown"><icon></icon></div>
dropdown.vue js
props: ['icon']
UserIcon.vue
<i class="user-icon"></i>
the browser reminds me that icon is unknown custom element. It seems like vue does not support this way to use component, doesn't it?
I solve this problem using slot.
and there is another question comes...
a.vue
<dropdown><template v-slot:icon><icon-user></icon-user></template></dropdown>
dropdown.vue
<div class="dropdown"><slot name="icon"></slot></div>
But icon-user component didn't show...
and I did this work, cuz I remove the name attribute of slot.
a.vue
<dropdown><template><icon-user></icon-user></template></dropdown>
dropdown.vue
<div class="dropdown"><slot></slot></div>

vue.js Mount component to app root

I have a modal.vue component as follows:
<template>
<transition name="modal-transition">
<div class="modal-body" v-if="displayed">
<div class="modal-overlay" #click="displayed = false"></div>
<div class="modal-content">
<slot/>
</div>
</div>
</transition>
</template>
How do I mount this component to the applications root element rather than in place?
For crude inaccurate example:
<body>
<div id="app">
<div class="header"></div>
<div class="nav"></div>
<div class="stage">
<div class="sub-nav"></div>
<div class="content">
<modal :display.sync="display">MY MODAL</modal> <-- Don't mount here...
</div>
</div>
<-- Mount here instead...
</div>
</body>
The current issue is that my sites header and navigation is layered on top of my modal and it's darkened full screen overlay instead of layered behind the modal overlay.
Update for Vue 3
There is now a built in feature called teleport which allows mounting parts of your component template to any DOM element.
The example from the OP would look like something like this
<!-- MyModal.vue -->
<template>
<transition name="modal-transition">
<div class="modal-body" v-if="displayed">
<div class="modal-overlay" #click="displayed = false"></div>
<div class="modal-content">
<slot/>
</div>
</div>
</transition>
</template>
<!-- SomeDeeplyNestedComponent.vue -->
<template>
<teleport to="#app">
<!-- Can still receive props from parent -->
<MyModal :my-prop="foo">
<!-- slot content -->
</MyModal>
</teleport>
</template>
Vue 2
Move the elements own self to the element of applications root may be achieved in two ways, Using a portal as a preferred solution or using an append.
Using a Portal (Preferred Method)
PortalVue is a set of two components that allow you to render a
component's template (or a part of it) anywhere in the document - even
outside the part controlled by your Vue App!
https://portal-vue.linusb.org/
Using an Append (Not best practice)
If adding a portal library is too heavy, using an append is allowed but lightly discouraged officially in the VUE docs.
Typically this particular mount position will satisfy a z-index overlay for your own modal or dialog popup that you require to render over the top of the entire app. You can always substitute this.$root.$el in this example for a different element target using standard getElementBy or querySelector functions.
Here the element is being moved not destroyed and re-added, all reactive functionality will remain in tact.
<script>
export default {
name: 'modal',
...
mounted: function() {
this.$root.$el.append(this.$el);
},
destroyed: function() {
this.$el.parentNode.removeChild(this.$el);
}
}
</script>
On mounted the element is moved inside of where the top level VUE app instance is mounted.
On destroyed removes the placeholder DOM comment for the migrated component from the new parent to prevent orphaned duplication each time the component remounts it's self.
VUE officially states not to destroy an element outside of VUE so this is not to be confused with that statement, here the component has already been destroyed.
This DOM comment duplication will typically happen when for example switching views with vue-router as this mechanism mounts and dismounts all components in a router view each time vue-router view state changes.
This behaviour is a bug cause by vue-router, the object is destroyed properly by VUE render manager but an index reference remains by mistake, using a portal package resolves this issue.
Here is the result:

How to make Vue.js + Vuetify.js page elements to display only with CSS ready?

I'm creating a website with Vue.js + Vuetify.js
If I simulate "3G" in developer tools I can see all the elements of the App.vue page (toolbar, drawer,elements of routed pages) displaying without CSS during loading.
I preview it with webpack/localhost hot reload npm run dev
I want the spinner to load first and then the rest of the elements (with CSS). How do I do it properly?
I tried v-cloak and it isn't working. Looks like It's for hiding the {{ }}.
project structure
index.html |
<div id="app"></div>
App.vue |
<v-app>
<loader></loader>
<div :v-show="false">
...
<v-toolbar>...</v-toolbar>
<router-view></router-view>
</div>
</v-app>
these methods on the App.vue page doesn't seem to solve the problem:
created: function () {show: true}
mounted: function () {show: true}
P.S. I'm a newbie, so it's possible that I'm missing some small detail preventing it from working properly.
Question:
Could someone please show a proper way of doing it?
Try this way:
<v-app>
<loader></loader>
<div v-show="false">
...
<v-toolbar>...</v-toolbar>
<router-view></router-view>
</div>
</v-app>
I think the v-show didn't work, bacause you use colon before, it's like passing a dynamic prop to the component instead of using v-show directive :)