Vue3 - Ref in component? - javascript

I'm making input component for my login form instead of creating input tag every time that I need it. However, I want to save the input value at #input event, thing that's I've made before (when I didn't have component) thanks to refs (by writing ref.value.value)
But now, I can't just add ref on my input because they'are component and not an html tag. How can I fix it ? :( I need their value for regExp test
there's before / after of my input
before
after
Thanks for your help

You can try this way (I used Vue3 Composition API + script setup):
Check out the playground I have set up here!
Parent component:
<template>
<Comp v-model="myData.field" />
<br />
{{ myData.field }}
</template>
<script setup>
import { ref } from 'vue'
import Comp from './Comp.vue'
const myData = ref({
field: 'something',
})
</script>
Custom input child component:
<template>
<input
type="text"
#input="$emit('update:modelValue', $event.target.value)"
:value="modelValue"
/>
</template>
<script setup>
defineProps(['modelValue'])
defineEmits(['update:modelValue'])
</script>
Related docs:
https://vuejs.org/guide/components/props.html
https://vuejs.org/api/options-state.html#emits

Pass the ref as a prop and in the input tag put ref.
<InputComponent refProp="email" />
<input :ref="refProp" >

Related

How to use #heroicons/vue in Nuxt3?

i want to import #heroicons/vue in Nuxt 3 but my icon not appear in frontend.
my setup:
import { HomeIcon, FilmIcon, PlusIcon } from "#heroicons/vue/solid"
my html:
<template v-for="(profileItem, i) in accountSetFields" :key="i">
<ProfileItems :user="user" :item="profileItem" />
<template v-slot:icon>
<component :is="profileItem.icon"></component>
</template>
</ProfileItems>
</template>
the variable profile.Item.icon has a string value of "HomeIcon"
I have tried to pass the value directly to the child component "ProfileItem.vue" but i receive the same error message.
When i pass the value directly as string ("HomeIcon" instead of profile.Item.icon) than it works because it mentioned the attribute from import { HomeIcon, FilmIcon, PlusIcon } from "#heroicons/vue/solid
<component :is="HomeIcon"></component>
Did anyone know how to load the icons dynamically?
That one works well
<script setup>
import { HomeIcon, FilmIcon, PlusIcon } from "#heroicons/vue/24/solid"
const icons = reactive({
home: HomeIcon,
film: FilmIcon,
plus: PlusIcon,
})
</script>
<template>
<component :is="icons.home"></component>
</template>
as explained here, you need the 24 in your import (for the size).
Not sure but this may also help maybe, didn't have to use that myself: https://github.com/tailwindlabs/heroicons/issues/564
Or you can forget about worrying about various icons configuration and fallback to that one (configured once and for all): https://stackoverflow.com/a/72055404/8816585
You can also use it without <component/> and register the icon as a component. Should also work with the composition api.
<template>
<CheckCircleIcon />
</template>
<script>
import { CheckCircleIcon } from "#heroicons/vue/24/solid";
export default {
components: {
CheckCircleIcon,
}
}
</script>

vuejs how to access a ref inside a child component?

I am new to vuejs and not very experienced in JavaScript. I use Vue3 in Laravel
I have a child component which exposes a ref on an input like this
<input
v-model="raw_input"
ref="raw"
#input="checkLength(limit)"
#keydown="enterNumbers($event)"
type="number"
/>
const raw = ref('');
defineExpose({
raw
})
In the parent
<template lang="">
<PageComponent title="Dashboard">
<SmartVolumeInputVue ref="svi" />
<div class="mt-16 border h-8">
{{ val }}
</div>
</PageComponent>
</template>
<script setup>
import PageComponent from "../components/PageComponent.vue"
import SmartVolumeInputVue from "../components/customInputs/SmartVolumeInput.vue";import { computed, ref } from "vue";
const svi = ref(null)
//let val=svi
//let val=svi.raw
let val=svi.raw.value
</script>
At the bottom of the script there are 3 lines (I only uncomment one at a time)
The first displays this in the template
{ "raw": "[object HTMLInputElement]" }
The second displays nothing
And the third reports an error
Uncaught (in promise) TypeError: svi.raw is undefined
I need some help to get the value of the referenced input in the child component.
Do you need the ref on the element? Or only the value?
If not, just expose the value like this: Live example
// App.vue
<script setup>
import { ref } from 'vue'
import SmartVolumeInputVue from './SmartVolumeInput.vue'
const svi = ref()
</script>
<template>
<SmartVolumeInputVue ref="svi" />
<div>
{{svi?.raw_input}}
</div>
</template>
// SmartVolumeInput.vue
<script setup>
import { ref, defineExpose } from 'vue'
const raw_input = ref(123)
defineExpose({
raw_input
})
</script>
<template>
<input v-model.number="raw_input" type="number" />
</template>

Svelte keep default prop value of a child component

I have component1 that takes let text as a prop and then component2 that does almost the same thing, but I'd like to keep component1 separate for better reusability.
So I wrapped the comp1 (Child.svelte) with comp2 (Wrapper.svelte). But how do I keep the default prop value of the Child component without writing it again?
here is an example:
//Wrapper.svelte
<script lang="ts">
import Child from "./Child.svelte";
export let text = 'hello world'; //need to type the default value again
</script>
<Child text={text} />
//Child.svelte
<script lang="ts">
export let text = 'hello world';
</script>
<p>{text}</p>
Thank you #hackape and #Stephane Vanraes for your answers!
the answer from #hackape seems like the answer I was looking for, but It still throws this typescript error: Property 'text' is missing in type '{}' but required in type '{ text: string; }'.ts(2322) when I don't provide any value to Wrapper comp. from the outside.
I should have realised this earlier, but I combined both answers and came up with this:
//Wrapper.svelte
<script lang="ts">
import Child from "./Child.svelte";
export let text: string = undefined;
</script>
<Child bind:text />
also works with <Child text={text}/>
I am relatively new to Stack Overflow, should I accept my or #hackapes answer?
Use bind:prop to create a two way binding. Docs: https://svelte.dev/tutorial/component-bindings
//Wrapper.svelte
<script lang="ts">
import Child from "./Child.svelte";
export let text: string
</script>
<Child bind:text />

How to assign `value` prop and `v-model` prop to custom Vue component?

I want to create a custom Vue component for a "radio div" -- a div (with a slot for including any content I want) that acts like a radio button so you can select it and only one can be selected among multiple with the same name.
In general radio buttons in VueJS look like so:
<input type="radio" name="name" value="value" v-model="variable" />
So I wanted a similar API:
<div-radio name="name" value="value" v-model="variable" />
However when I looked up how to add v-model support to custom component the first link I found on Google claimed:
For input elements, you might use v-model like this:
<input v-model="email" />
v-model translates to this:
<input :value="email" #input="e => email = e.target.value" />
If v-model translates to :value and #input then it doesn't seem possible to have a prop called "value" at the same time as "v-model" - despite the fact this is how normal VueJS radio buttons work
Am I misunderstanding how v-model works? Or is there an alternate solution? Or is what I want just not possible?
Vue allows configuring v-model's prop name and event name through the component's model option:
model
New in 2.2.0
Type: { prop?: string, event?: string }
Details:
Allows a custom component to customize the prop and event used when it’s used with v-model. By default, v-model on a component uses value as the prop and input as the event, but some input types such as checkboxes and radio buttons may want to use the value prop for a different purpose. Using the model option can avoid the conflict in such cases.
Example:
Vue.component('my-checkbox', {
model: {
prop: 'checked',
event: 'change'
},
props: {
// this allows using the `value` prop for a different purpose
value: String,
// use `checked` as the prop which take the place of `value`
checked: {
type: Number,
default: 0
}
},
// ...
})
<my-checkbox v-model="foo" value="some value"></my-checkbox>
The above will be equivalent to:
<my-checkbox
:checked="foo"
#change="val => { foo = val }"
value="some value">
</my-checkbox>
To use v-model you need to handle value and #input manually:
<template>
<div>
<input type="radio" :name="name" :value="value" #input="$emit('input', $event)" />
</div
</template>
<script>
export default {
name: 'div-radio',
props:{
value: Boolean,
name: String
}
}
</script>
In a host component, treat it as a normal component:
...
<div-radio name="name" v-model="variable1" />
<div-radio name="name" v-model="variable2" />
...

Use prop value as a variable in VueJS

I have a problem about using prop value as a variable in VueJS. I have a component which I tranmit prop:
This is parent component:
<template>
<div class="a">
<UploadAvatarModal
apiurl="upload_avatar"
id="UploadAvatarModal"
/>
</div>
</template>
This is script of UploadAvatarModal component:
<template>
<div class="a">
...
</div>
</template>
<script>
export default {
props: {
id: String,
apiurl: String
},
methods: {
def: function () {
this.$refs.id.hide()
}
}
}
</script>
In this line: this.$refs.id.hide() How can I call methods according to prop id. Example: this.$refs.UploadAvatarModal.hide() or this.$refs.UploadAvatarModal2.hide() changed by props value??
You can access props doing :
this.propName
To access id prop you need to do :
this.id
So the line you wrote this.$refs.id.hide() should be written :
this.$refs[this.id].hide()
But it will probably do nothing as .hide() is a jquery function.
In plain javascript you would need to do :
this.$refs[this.id].style.display = 'none'
That said, it's might not be a good idea to do so.
Using vue, the best way to show/hide a component is probably to use v-if or v-show

Categories