When to use prop modifier in vue? - vue.js

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.

Related

what does an input event on a component do in Vue.js?

The following piece of code is taken from the Vue documentation:
<ChildComponent v-model="pageTitle" />
<!-- would be shorthand for: -->
<ChildComponent :value="pageTitle" #input="pageTitle = $event" />
There is an input event on a component. I understand what an input event does on an input. But what does the input event do on a component?
The # is short for v-on directive which is used to listen to DOM events emitted/triggered from a specific element. Now most of the native elements will interact with the outside world by emitting their own corresponding events by default. For instance, div element triggers click event, input element triggers input, change, focus and other helpful events.
Unlike native elements, there is absolutely no events triggered BY DEFAULT in a custom component. Therefore, you can only listen to events that are emitted from within the component. Those are custom events, so you can rest assure that none of these event setups below will work unless inside each component emits their own click, input, focus event respectively:
<ComponentA #click="onClickComponentA" />
<ComponentB #input="onInputComponentB" />
<ComponentC #focus="onFocusComponentC" />
In your case, ChildComponent is clearly not a native element so inside this component, it must somewhere emit input event.
It's all about Custom events, just read Docs
Example:
Vue.component('custom-input', {
props: ['value'],
template: `
<input
v-bind:value="value"
v-on:input="$emit('input', $event.target.value)"
>
})
then you can use custom-input like this:
<custom-input :value="pageTitle" #input="pageTitle = $event" />
where $event is a native event of the input

Can I v-model input that is child of child (don't know how to ask)

I have this:
Login.vue has child FormGroup.vue
FormGroup.vue has two children - Input.vue and Label.vue
I have data() in Login.vue and how to v-model data from Input.vue that's inside FormGroup.vue?
You need to use template refs to access data/methods of child component. For example in Login you can access FormGroup by adding a ref attribute and accessing it as:
<form-group ref="FormGroup" />
this.$refs.FormGroup
And then going further down it can be
<label ref="Label" />
<input ref="Input" />
this.$refs.FormGroup.$refs.Input
this.$refs.FormGroup.$refs.Label
But be careful before using $refs the child component must be rendered or else it will be null. It happens when there is a condition v-if on child components or the element is waiting for an API to complete.
Check: https://v3.vuejs.org/guide/component-template-refs.html

Vue - detect component inside slot

I have this slot inside my tile component. I basically need to detect a specific other component which is supposed to be used inside this slot BUT the slot also supports other html tags not just this specific component. Is there a way to detect a special component e.g. <listitem /> inside the slot?
<div class="tile">
<template v-if="$slots['headline']">
<slot name="headline" />
</template>
</div>
Edit
The basic idea is the following
<tile>
<template #headline>
<listitem />
</template>
</tile>
<tile>
<template #headline>
<h1>Some headline</h1>
</template>
</tile>
I have those two options on how you can utelise this header slot. If there is a just a normal html tag e.g. <h1>, I would like to apply the corresponding css styles. If there is the <listitem /> component I need to apply other styles
As content of the slot is passed to the component as an array of VNode's accessible via this.$slots (in case of scoped-slots it is function returning array of VNode's) you can write a function like this:
methods: {
isListitem() {
return this.$slots.headline && this.$slots.headline[0].tag.endsWith('-listitem')
}
}
Main problem is that $slots is not reactive
Docs:
Please note that slots are not reactive. If you need a component to re-render based on changes to data passed to a slot, we suggest considering a different strategy that relies on a reactive instance option, such as props or data
So I don't recommend doing this and follow the Vue documentation suggestion to use props instead...
Maybe you can use a function to try to get this element by js, something like this:
I am not sure if its will works
function checkElement(){
var listitem = document.querySelector("listitem");
if(listitem) {
// if exist do something
}
}

Why do not undeclared props pass to the components's root element?

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.

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>