How expose child element v-model as the vue component v-model - vue.js

I Was using a simple text area in my vue component.:
<input v-model="someRootProperty"/>
I would like to encapsulate this input inside another component, for instance
<template>
<div>
<div>...</div>
<input v-model="???"/>
</div>
</template>
I would like to use
<my-component v-model="someRootProperty" />
instead and them bypass this to the input inside the component.
What should I do inside the component to expose its input v-model as the component v-model?

<input v-model="someRootProperty"/>
Is the same as (syntactic sugar):
<input :value="someRootProperty" #input="someRootProperty = $event.target.value"/>
That means that you could accept value as a prop in the component and emit input to achieve the same thing.
MyComponent.vue
<template>
<input :value="value" #input="$emit('input', $event.target.value)>
</template>
<script>
export default {
props: ['value']
}
And then use it like this.
<MyComponent v-model="someRootProperty"/>

Related

Is it possible to use a prop as a v-model value?

Is it possible to use the value of a prop as the input's v-model?
I normally do the following when creating an input:
<template>
<form>
<input v-model="form.email" type="email"/>
</form>
</template>
<script>
export default {
data() {
return {
form: {
email: '',
}
}
}
}
</script>
But now I'm trying to achieve the following where this.myProp is used within the v-model without being displayed as a string on the input:
<template>
<form>
<input v-model="this.myProp" type="email"/>
</form>
</template>
<script>
export default {
props: ['myProp'] // myProp = form.email for example (to be handled in a parent component)
}
</script>
Yes, but while using it in parent component. In child component you need to extract value and #input instead of using v-model (v-model is shortcut for value="" and #input) Here is an example of input with label, error and hint in Vue 3 composition API.
BaseInput.vue
<template>
<div class="flex flex-col">
<label>{{ label }}</label>
<input v-bind="$attrs" :placeholder="label" :value="modelValue" #input="$emit('update:modelValue', $event.target.value)">
<span v-for="item of errors" class="text-red-400">{{ item.value }}</span>
<span v-if="hint" class="text-sm">{{ hint }}</span>
</div>
</template>
<script setup>
defineProps({ label: String, modelValue: String | Number, errors: Array, hint: String })
defineEmits(['update:modelValue'])
</script>
Using v-bind="$attrs" you target where attributes like type="email" need to be applied in child component. If you don't do it, it will be added to the top level DOM element. In above scenario <div>.
ParentComponent.vue
<BaseInput type="email" v-model="formData.email" :label="Email" :errors="formErrors.email"/>

Passing a HTML tag in vue js

I have a component which has a <p> tag inside, but would like it to be a <h1> tag sometimes, how to pass the prop ?
<template>
<p>Hello world</p>
</template>
Pass it as prop then use component to render it :
<template>
<component :is="tag">Hello world</component >
</template>
<script>
export default{
name:'MyComponent',
props:['tag']
}
</script
then use the component like <MyComponent tag="h1" />
You could make MyComponent more dynamic accepting any content by using slots :
<template>
<component :is="tag">{{msg}}</component >
</template>
<script>
export default{
name:'MyComponent',
props:['tag','msg']
}
</script
then use it like <MyComponent tag="h1" >hello world</MyComponent>
Would recommend using slot for that component, which will be something like this
<template>
<slot name="content"></slot>
</template>
When you use your component you can just do this
<Component>
<template #content>
Your content here, whatever you like
<template/>
<Component/>

How can i pass a parameter to a Vue component?

I just got started to Vue and i'm trying to understand some basic concepts such as conditional rendering and how to pass data from where i load the app to a component. Suppose i'm rendering a Vue component like this:
<div id="app">
<myComponent></myComponent>
</div>
Suppose myComponent looks like this:
<template>
<div>
<h1>First block</h1>
</h1>Second block</h1>
</div>
</template>
I want to be able to render First block or Second block when i load the Vue app according to a parameter i pass to the component, like:
<div id="app">
<myComponent id="first"></myComponent>
</div>
In this case i should see First block, whereas if instead of id="first" there was id="second" the output was supposed to be Second block. How can i do this?
I know it's a very basic question, but most of the sources i found explained how to do the opposite. Any kind of advice is appreciated!
In vue you could pass props (parameters) to component which defines this ones in its script like :
<template>
<div>
<h1 v-if="block==='first'">First block</h1>
</h1 v-else>Second block</h1>
</div>
</template>
<script>
export default{
props:{
block:{
type:String,
default:'first'
}
}
}
</script>
in parent component pass the prop like :
<div id="app">
<myComponent block="first"></myComponent>
</div>
or
<div id="app">
<myComponent block="second"></myComponent>
</div>

How to use Vue I18n translation in component attribute/property

How do I translate the passed-in attribute/property of a component? For instance, I have a card component with a title and description prop defined like this.
<!-- my-card component -->
<template>
<div>
<h2>{{title}}</h2>
<span>{{description}}</span>
</div>
</template>
<script>
export default {
props: {
title: String,
descritpion: String
}
}
</script>
Then using the my-card component in another page/component like this
<template>
<div>
<header>Page header</header>
<my-card :title="the best card title" :description="the best description" />
<footer>Page footer</footer>
</div>
</template>
How do I us vue I18n to translate the component props?
<template>
<div>
<header>Page header</header>
<my-card :title="{{ $t('myCard.title')}}" :description="{{$t('myCard.description')}}" />
<footer>Page footer</footer>
</div>
</template>
I can't seem to get the translation to work with passed-in props.
PS: I know I could add the translation in the place I defined my-card component but the issue here is that the components are third-party components from NPM library.
I know some packages in React.js has this feature.
Just bind the translation without using {{}} :
<my-card :title="$t('myCard.title')" :description="$t('myCard.description')" />
You can use I18n translation in component props like this.
<my-card
:title="$t('myCard.title')"
:description="$t('myCard.description')"
/>

How to execute a method of a nested component

I have the component with form and I have the nested component with input['file']. Nested component have a method 'removeFile'. How can I execute this method when submit form?
// form
<form>
<input type="text">
<file-input></file-input>
</form>
// component "file-input"
<script>
export default {
methods: {
removeFile() {
// ***
}
}
};
</script>
<template>
<div>
<label>
<div>
<span #click="removeFile"></span>
</div>
<input type="file">
</label>
</div>
</template>
In most cases you want to avoid doing this if possible. Data should flow down and events should be emitted up.
That being said you can access by adding a ref to the child. In child you add a
<Child ref='foo'></>
Then in your parent you access the component vie 'this.$refs.foo' which will have all the normal method and data stuff on the child.
https://v2.vuejs.org/v2/guide/components.html#Child-Component-Refs