Why do not undeclared props pass to the components's root element? - vue.js

I made a wrapper around Vuetify's 'v-dialog' component named 'Modal' and wanna pass props through it:
<template>
<v-dialog
class="modal"
max-width="600"
v-on="vDialogListeners"
>
<v-card>
<v-card-title class="headline">
<slot></slot>
</v-card-title>
<v-card>
...
</v-dialog>
</template>
I use it like this ('value' prop):
<Modal
:value="showModal"
:confirm="true"
#close="onModalClose"
#click:outside="onModalClose(false)">
Are you sure you'd like to log out?
</Modal>
I know about $attrs and it works if I bind it explicitly, i.e, v-bind="$attrs" within <v-dialog> opening tag.
My question: why doesn't work it by default, that's without explicit v-bind="$attrs", if <v-dialog> is the component's root element and should accept all props undeclared in the component, or I'm wrong and misunderstand this part of documentation?
I used to think that v-bind="$attrs" is only used in case inheritAttrs: false in order to pass udeclared props to a component's not-root element (a nested one).
I have a guess: maybe, it only concerns the components root html element (e.g., input tag) by default.

It seems I figured out the proper usage of it. By default, it adds these $attrs to the DOM element as attributes. By explicit binding, I can pass them to the necessary child component. By setting inheritAttrs = false, I cancel the default behavior of adding attributes to the DOM element. Thus, I can combine these options to get the suitable behavior.

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

Vue3: Using v-for with keep-alive

My Problem
I have a variable number of Tab components; there can be 1 or 10, but only one is going to be displayed at a time. However, I want to cache them between switches. I thought I could put a v-for loop inside a <keep-alive> but according to the docs: https://v3.vuejs.org/api/built-in-components.html#keep-alive:
Note, <keep-alive> is designed for the case where it has one direct child component that is being toggled. It does not work if you have v-for inside it. When there are multiple conditional children, as above, <keep-alive> requires that only one child is rendered at a time.
Question
This seems like a pretty standard use-case, so I'm wondering if there's an easier way about this that I'm missing. Is there a best practice to rendering a variable number of components inside the <keep-alive> component?
Update: Kind of an answer
I was able to separate the Tab logic from the v-for, which means the Tabs get generated elsewhere, while the TabContent is the only thing inside <keep-alive>. Kind of like so:
<keep-alive>
<TabContent tab-name="name" />
</keep-alive>
Then internally, TabContent uses the tab-name prop to grab the data it needs.
Admittedly it feels like a good solution but I'm open to other ways to solve this.
Update 2.0: For Dynamic Components, use :key
The last thing I figured out; my Tab titles are dependent on filenames, and the TabContent is generated from the file, so it takes a filename props. My content was dynamic.
You still can't use a v-for inside the <keep-alive>, but you can use keys still:
<keep-alive>
<template>
<component
:is="'TabContent'"
:key="currentTabTitle"
v-bind="{
filename: currentTabTitle
}"
/>
</template>
</keep-alive>
Take a look at Dynamic Components with keep-alive
<div id="dynamic-component-demo" class="demo">
<button
v-for="tab in tabs"
:key="tab"
:class="['tab-button', { active: currentTab === tab }]"
#click="currentTab = tab"
>
{{ tab }}
</button>
<!-- Inactive components will be cached! -->
<keep-alive>
<component :is="currentTabComponent"> </component>
</keep-alive>
</div>

How can I get a hight of v-card-title vuetify element?

I have the following code and I would like to get the height of v-card title element?
<v-card-title class="purple lighten-2">
<v-icon dark size="42" class="mr-4"> fas fa-egg </v-icon>
<h3 class="white--text font-weight-medium flex-nowrap">
{{ dishes[dishesIndexList[0]].dish_name }}
</h3>
</v-card-title>
How can I do it? I tried to add ref="cardTitleHeight" to v-card title and then when the elements are mounted I can get this.$refs and the cardTitleHeight ref I added is listed as part of $refs objects but when I try to get it using this.$refs.cardTitleHeight I get undefined (I need to get this element first to get its hight).
I suppose that it is because v-card-title is an external component.
How is it possible to get v-card-title height? I would be grateful for advice.
You have the answer in your question
when the elements are mounted
The height of this element will be defined after the component has been mounted.
in your script you can try :
mounted() {
console.log(this.$refs.cardTitleHeight); //.style.height or lineHeight
},
Note that mounted does not guarantee that all child components have also been mounted. If you want to wait until the entire view has been rendered, you can use vm.$nextTick inside of mounted.
More about the mounted life cycle hook.

When to use prop modifier in vue?

When to use prop modifier in vue?
In vue document,I find the prop modifier in v-bind here: https://v2.vuejs.org/v2/api/#v-bind
my question is this:
https://v2.vuejs.org/v2/api/#v-bind
From the docs:
Modifiers:
.prop - Bind as a DOM property instead of an attribute (what’s the difference?). If the tag is a component then .prop will set the property on the component’s $el.
This is useful, because some HTML inputs can't receive a value as attribute, but need to be passed on the ref itself.
See for example the indeterminate state of a checkbox. Normally you'd need to do
<template>
<!-- this doesn't work, because there's no indeterminate prop on the checkbox, it only exists on the DOM element -->
<input type="checkbox" :indeterminate="indeterminateProp" />
</template>
<script>
beforeUpdate() {
//set indeterminate directly on the dom element object
// this is what you'd always have to do if v-bind.prop didn't exist
this.$refs.myCheckbox.indeterminate = this.indeterminateProp;
}
</script>
and keep track of it manually outside of vue's reactivity system.
But thanks to .prop, you can just do
<input type="checkbox" :indeterminate.prop="indeterminateProp"/>
Without having to play with lifecycle hooks.
So .prop basically tells vue "apply this value on the DOM node itself (the one you'd normally get from $refs) instead of trying to apply it as an attribute or property"
You can use this modifier to pass a property to a component.
<myComponent v-bind:<PropName></myComponend> is the same as <myComponent :<PropName>></myComponend>
Checkout this link here: https://v2.vuejs.org/v2/guide/components-props.html.

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>