v-model and modelValue for multiple layers of component in vue3 - vuejs3

Hi I have component(Parent.vue) that has child component that has another child component that has input elemenet.
// Parent.vue
<Child v-model="inputValue"/>
// Child.vue
<script setup>
defineProps(['modelValue'])
defineEmits(['update:modelValue'])
</script>
<template>
<Another-child
v-model="modelValue"
#update:modelValue="$emit('update:modelValue', $event.target.value)"
/>
</template>
// AnotherChild.vue
<script setup>
defineProps(['modelValue'])
defineEmits(['update:modelValue'])
</script>
<template>
<input
:value="modelValue"
#input="$emit('update:modelValue', $event.target.value)"
/>
</template>
My question is if Child component should pass modelValue with v-model, or as value prop or modelValue prop when it wants to pass value to its child component?
// Child.vue
.
.
.
// v-model
<Another-child
v-model="modelValue"
#update:modelValue="$emit('update:modelValue', $event.target.value)"
/>
// or
// as value prop
<Another-child
:value="modelValue"
#update:modelValue="$emit('update:modelValue', $event.target.value)"
/>
// or
// as modelValue prop
<Another-child
:modelValue="modelValue"
#update:modelValue="$emit('update:modelValue', $event.target.value)"
/>
.
.
All of them work and bind value correctly. According to the doc, https://vuejs.org/guide/components/events.html#usage-with-v-model, I think v-model is correct but also have doubt that using prop value for v-model. Also, v-model="modelValue" works in normal app, but it fails in storybook on build.
Thanks for your help!

Related

Vue 3 Internal server error: v-model cannot be used on a prop, because local prop bindings are not writable

I found this error and blocked my webapps.
2:32:22 PM [vite] Internal server error: v-model cannot be used on a prop, because local prop bindings are not writable.
Use a v-bind binding combined with a v-on listener that emits update:x event instead.
Plugin: vite:vue
File: /Users/julapps/web/myapp/src/components/switch/AudienceTimerSlide.vue
I want to make timer data become data model (editable) and its default value from component props. Why this not work? I'm very new in vuejs, how can i solve this problem? Kindly Please Help...
<template>
----
<div class="field-body">
<div class="field">
<div class="control">
<input #keypress.enter="save" v-model="timer" type="number" class="input is-normal">
</div>
</div>
</div>
-----
</template>
<script>
export default {
props:['id', 'timer'],
setup(props, context){
-----
const save = async() => {
// save form
}
return {
}
}
}
</script>
you have to change defineProps(['question', 'choices'])
to
const props=defineProps(['question', 'choices'])
call as props.question in script like
<TextInput :text="props.question" ></TextInput>
Props are read-only One-Way Data Flow
Use an internal data property with timer as initial value. Like this:
data() {
return {
localTimer: timer
}
}
and
<input #keypress.enter="save" v-model="localTimer" type="number" class="input is-normal">
Or replace v-model with v-bind:value & emit an event
#input="$emit('update:modelValue', $event.target.value)"
Like this:
<input #keypress.enter="save" :value="timer" #input="$emit('update:modelValue', $event.target.value)" type="number" class="input is-normal">

Vue 3 v-model on props

I just started using Vue 3 and I noticed that I cannot use v-model on a prop and I read on how to pass data between Parent<-->Child components via props and emits.
Then I noticed something weird. I cannot use v-model on a prop, but I can use it on a field of the prop.
So this wouldn't word:
<!-- parent.vue -->
<template>
<child :obj="obj"></child>
</template>
<script>
//
data() {
return { obj : "test" }
}
</script>
<!-- child.vue -->
<template>
<input type="text" v-model="obj">
</template>
But this would work
<!-- parent.vue -->
<template>
<child :obj="obj"></child>
</template>
<script>
//
data() {
return { obj : { name: "test" } }
}
</script>
<!-- child.vue -->
<template>
<input type="text" v-model="obj.name">
</template>
So what's the real purpose of not using v-model on a prop?

Data Binding between parent and child component in vue3 composition api

I have successfully bound data in a two way format in vue 3 like this :
<template>
<p for="">Year of Incorporation</p>
<input type="text" v-model="input" />
<div>
{{ input }}
</div>
</template>
<script>
export default {
setup() {
let input = ref("")
return {input};
},
};
</script>
What I want to do now is put the input inside a child component like this:
Parent Component:
<template>
<Child v-model="input" />
{{input}}
</template>
Child Component:
<template>
<input type="text" v-model="babyInput" />
</template>
<script>
export default {
setup() {
let babyInput = ref("")
return {babyInput};
},
};
</script>
The Vue.js documentation presents a nice way of handling v-model-directives with custom components:
Bind the value to the child component
Emit an event when the Child's input changes
You can see this example from the docs with the composition when you toggle the switch in the right-top corner (at https://vuejs.org/guide/components/events.html#usage-with-v-model).

How to access slot dynamic component in vue3?

// main.vue
<template>
<window v-for="app in apps">
// `app` is defined by `defineAsyncComponent(()=> import('path/to/app.vue'))`
<component :is="app"></component>
</window>
</template>
//window.vue
<template>
<div class="window" #click="click">
<slot/>
</div>
</template>
<script>
...
methods:{
click (){
// I need to access the `app` dynamic component here!
const app = this.$slots.default()[0];
}
}
...
</script>
I dont know how to access <slot/> component which is dynamic loaded.
In above case,this.$slots.default()[0] will be an object and it hasn't contain the dynamic component,just a AsyncComponentWrapper

How do I apply CSS to redux-form fields?

How do I apply any type of CSS to redux-form Field components? className and class are silently ignored:
<div>
<label>Name</label>
<div>
<Field
className="form-input"
name="formContactName"
component="input"
type="text"
placeholder="Person to contact"
/>
</div>
</div>
I was able to the apply the styles by creating a custom component:
<div>
<label>Name</label>
<div>
<Field
name="formContactName"
component={ customInput }
/>
</div>
</div>
but that's a major PITA and also largely negates the gains of using redux-form in the first place. Am I missing something? Note I added the className assignments directly in the custom component - I realize I can send them through as props in Field.
I tried setting input styles globally but they were ignored as well. The redux-form website docs tell you everything you need to know to use the rig but make no mention of CSS that I can see...
Thanks,
JB
Edit: this is not a duplicate - the answer pointed to uses a custom input component. As stated above, I can get that to work, but then there's really no need for redux-form in the first place.
#Jay: I was able to get this to work with a custom component by grabbing the code from the online docs:
class MyCustomInput extends Component {
render() {
const { input: { value, onChange } } = this.props
return (
<div>
<label htmlFor="formContactName" className="col-sm-2 control-label">Name:</label>
<div className="col-sm-10">
<input
id="formContactName"
placeholder="Person to contact"
className="form-control"
type="text"
/>
</div>
</div>
)
}
}
and then, in the redux-form Form code:
<div>
<label>Name</label>
<div>
<Field
name="formContactName"
component={ MyCustomInput }
/>
</div>
</div>
The bootstrap settings via className worked fine using this method.
All your custom props would be passed to the input component, so you can do
const CustomTextField = props => {
const { input, label, type, meta: { touched, error }, ...other } = props
return (
<TextField
label={label}
type={type}
error={!!(touched && error)}
helperText={touched && error}
{ ...input }
{ ...other }
/>
)
}
And then you can pass any props, including className to the CustomTextField
<Field
name="some"
component={CustomTextField}
className="css-applied"
/>

Resources