How do I fit the value of one v-model into another v-model? - vue.js

In this example, I'm trying to fit the value from div id="message" into textarea using the Vue v-model construct, but this not work
<template>
<div>
<textarea v-model="text"></textarea>
</div>
<div>
<div id="message" v-model="text2">{{ comment.message }}</div>
<button #click="update(text2);">
Edit
</button>
</div>
</template>
<script>
export default {
data() {
return {
text: [],
text2: null
}
},
methods: {
/* not work */
update(text2) {
this.text = text2;
}
}
<script>
How do I make sure that when I click on the "edit" button, the value of v-model="text2" insert into v-model="text" ?

You cannot use v-model on a <div> because it isn't an input element.
It seems what you want to do is set text to the comment message when you click the edit button so that it can be edited by the textarea. All you have to do is pass comment.message as the argument:
<button #click="update(comment.message)">
A couple of other things:
You cannot have multiple root elements in your template (you have two root <div> elements). You can just wrap everything in a single <div>.
text has initial value [] which isn't compatible with a textarea's v-model; did you mean ''?

Related

How to pass #blur into child component Vuejs

I created a custom Input component.
I needed pass #blur from vee-validate form to my custom input component.
It works great in normal html input tag. I no idea how could we pass the #blur into custom Input component.
Example 1 work correctly, it triggered the validation after blur the input.
<template>
<form #submit="onSubmit">
<input #blur="emailBlur" v-model="email" type="text" autocomplete="off" name="email" placeholder="email">
<button type="submit" :disabled="isSubmitting">Submit</button>
</form>
</template>
Example 2 with My custom Input Component:
// src/components/Input.vue
<template>
<div class="mt-2">
<label :for="name" class="h5">Name</label>
<input
:type="type"
:value="modelValue"
#change="$emit('update:modelValue', $event.target.value)"
:id="name"
:placeholder="placeholder"
/>
</div>
</template>
<script>
export default {
name: 'Input',
props: ["modelValue", 'name', 'type', 'placeholder'],
setup(props) {
console.log('props :>> ', props); // not receive the #blur
}
}
</script>
Parent Component (App.vue):
<template>
<form>
<Input #blur="emailBlur" v-model="email" type="text" name="email" placeholder="Custom input email" />
<button type="submit" :disabled="isSubmitting">Submit</button>
</form>
</template>
export default {
name: 'App',
components: {
Input
},
setup() {
// the vee validation values v-model to template
}
}
Sending the handler as props from the parent is not a good practice instead need to trigger the handler(present in the parent) from the child component. By doing so you will have an advantage where you can bind different blur handlers based on your requirement inside different parent components
To do so you can follow the below approach
Custom Input Component
// src/components/Input.vue
<template>
<div class="mt-2">
<label :for="name" class="h5">Name</label>
<input
:type="type"
:value="modelValue"
#change="$emit('update:modelValue', $event.target.value)"
:id="name"
:placeholder="placeholder"
#blur="$emit('blur')" //Change added
/>
</div>
</template>
<script>
export default {
name: 'Input',
props: ["modelValue", 'name', 'type', 'placeholder'],
emits: ['blur', 'update:modelValue'], // change added
}
</script>
Note:
for all v-models without arguments, make sure to change props and events name to modelValue and update:modelValue respectively
For Example:
Parent.vue
<ChildComponent v-model="pageTitle" />
and in Child.vue it should be like
export default {
props: {
modelValue: String // previously was `value: String`
},
emits: ['update:modelValue'],
methods: {
changePageTitle(title) {
this.$emit('update:modelValue', title) // previously was `this.$emit('input', title)`
}
}
}
What you are creating is usually called "transparent wrapper" component. What you want from this wrapper is to behave in almost every way as normal input component so the users of the component can work with it as it was normal input (but it is not)
In your case, you want to attach #blur event listener to your wrapper. But the problem is that blur is native browser event i.e. not a Vue event.
When you place event listener on a component for an event not specified in emits option (or v-bind an attribute that is not specified in component's props), Vue will treat it as Non-Prop Attribute. This means it take all such event listeners and non-prop attributes and place it on the root node of the component (div in your case)
But luckily there is a way to tell Vue "Hey, don't place those automatically on root, I know where to put it"
Use inheritAttrs: false option on your component
Put all non-prop attributes (including the event listeners) on the element you want - input in this case - using v-bind="$attrs"
Now you can even remove some props - for example placeholder (if you want), because if you use it directly on your component, Vue place it on input, which is what you want...
Also handling #change event is not optimal - you component allows to specify a type and different input types has different events. Nice trick around it is not to pass value and bind event explicitly, but instead use v-model with computed (see example below)
const app = Vue.createApp({
data() {
return {
text: ""
}
},
methods: {
onBlur() {
console.log("Blur!")
}
}
})
app.component('custom-input', {
inheritAttrs: false,
props: ["modelValue", 'name', 'type'],
emits: ['update:modelValue'],
computed: {
model: {
get() { return this.modelValue },
set(newValue) { this.$emit('update:modelValue', newValue) }
}
},
template: `
<div class="mt-2">
<label :for="name" class="h5">{{ name }}:</label>
<input
:type="type"
v-model="model"
:id="name"
v-bind="$attrs"
/>
</div>
`
})
app.mount("#app")
<script src="https://unpkg.com/vue#3.2.19/dist/vue.global.js"></script>
<div id='app'>
<custom-input type="text" name="email" v-model="text" placeholder="Type something..." #blur="onBlur"></custom-input>
<pre>{{ text }}</pre>
</div>

How to get the value of one input field in a "v-for" of multiple inputs

I have multiple text inputs generated in v-for directive which i have attached to one v-model variable as show below. I have a button by the respective inputs which prints the value of the current working input. Ultimately I want to extract value of the selected input without affecting the other inputs.
But apparent any change make in one input affect all the input. I super confused as to how I will achieve this. Any help will be much appreciated.
My attempted code is shown below.
<template>
<div id="app">
<div v-for="i in 5" :key="i">
<input v-model="text" type="text" :key="i" />
<button #click="printText">print</button> <span>{{ text }}</span>
</div>
</div>
</template>
<script>
export default {
data() {
return {
text: "",
};
},
methods: {
printText() {
console.log(this.text);
},
},
};
</script>
Take an array instead of simple variable when you use v-model in v-for
And on click pass the index with function call
Try to use
<template>
<div id="app">
<div v-for="i in 5" :key="i">
<input v-model="text[i]" type="text"/>
<button #click="printText(i)">print</button> <span>{{ text[i] }}</span>
</div>
</div>
</template>
<script>
export default {
data() {
return {
text: [],
};
},
methods: {
printText(index) {
console.log(this.text[index]);
},
},
};
</script>

Trix editor not rendering stored content

I am using the Trix editor and trying to render some stored content inside the box, but nothing is showing.
My Trix editor component wrapper:
<template>
<div>
<input type="hidden" :id="id" :name="name" :value="storedContent ? storedContent : 'blank'" />
<trix-editor :input="id"></trix-editor>
</div>
</template>
<script>
import Trix from "trix";
export default {
props: ["id", "name", "storedContent"]
};
</script>
The editor on the page doesn't render anything, regardless if I provide the stored-content prop.
It just shows an empty editor.
However, on inspection the hidden input does show the stored-content (or 'blank') on the page.
<input id="job-full-desc" type="hidden" name="full_description" value="blank">
The 'blank' value gets overwritten as soon as I write anything in the box.
Any thoughts?
I tried the following , when the component created I manually add the value to trix innerHTML
hoppefully can assist you thaks
<template>
<div>
<input :id="id" type="hidden" :name="name" :value="value">
<trix-editor ref="trix" :input="id" :placeholder="placeholder" style="min-height:300px"></trix-editor>
</div>
</template>
<script>
import Trix from 'trix';
import 'trix/dist/trix.css';
export default {
props: ['name', 'value', 'placeholder', 'shouldClear' , 'id'],
mounted () {
this.$refs.trix.innerHTML = this.value;
console.log(this.$refs.trix.innerHTML);
}
};
</script>

v-show not working with props

I am trying to hide or show button using props.
Here is the code
View (Blade)
<product-form-component savebutton="false" updatebutton="false"></product-form-component>
Component template
<template>
<div class="form-actions text-right col-md-12">
<button v-show="showsavebutton" class="btn btn-primary">Save</button>
<button v-show="updatemode && showupdatebutton" class="btn btn- primary">Update</button>
</div>
</template>
Javascript
export default {
props: ['showupdatebutton', 'showsavebutton', 'modalid']
}
Two points:
The props you are passing don't work the way you think they do; and
You have to create data variables (or props) in the component with the names you are using in the v-show.
Passing props
When you pass like:
<product-form-component savebutton="false" updatebutton="false"></product-form-component>
inside the component, the savebutton and updatebutton properties will be strings. In the example above, they won't be the boolean false, they will be the string "false".
To bind them to different values, use v-bind:propname or its shorthand :propname:
<product-form-component :savebutton="false" :updatebutton="false"></product-form-component>
That way, inside the component, those properties will really have the value false.
Variables inside component and v-show
The variables you use in the v-shows:
<button v-show="showsavebutton" ...
<button v-show="updatemode && showupdatebutton" ...
Don't exist in your component. You have to create data variables (or props) in the component with the names you are using in the v-show.
Considering you already have some props declared, here's an example of declaring those v-show variables in the data() using the props as initial value:
Vue.component('product-form-component', {
template: "#pfc",
props: ['updatebutton', 'savebutton', 'modalid'],
data() {
return {
updatemode: this.updatebutton, // initialized using props
showupdatebutton: this.updatebutton,
showsavebutton: this.savebutton
}
}
})
new Vue({
el: '#app',
data: {
message: 'Hello Vue.js!'
}
})
<script src="https://unpkg.com/vue"></script>
<template id="pfc">
<div class="form-actions text-right col-md-12">
<button v-show="showsavebutton" class="btn btn-primary">Save</button>
<button v-show="updatemode && showupdatebutton" class="btn btn- primary">Update</button>
</div>
</template>
<div id="app">
<p>{{ message }}</p>
<product-form-component :savebutton="true" :updatebutton="true"></product-form-component>
</div>
Props as passed down to child with the bind syntax :, so in your case you forgot to add it:
try:
<product-form-component :savebutton="false" :updatebutton="false"></product-form-component>

Display value emitted from Vue component

I created two separated Vue components and I able to emit a message thru a bus.
How can I render/display the message in the component that receives the message.
Example of the Vue component that receives the message:
<template>
<div v-model="cars">
Car model: {{ model }}
<input type="button" #click="display" value="example" />
</div>
</template>
<script>
export default {
data() {
return {
cars: null
}
},
mounted() {
bus.$on('CARS_LOADED', (cars) => {
this.cars = cars;
});
},
methods: {
display()
{
console.log(this.cars);
}
}
}
</script>
I can successfully emit and received the message, however the car model is not updated. I checked the message received and it contains the "model" key with a right value.
I cannot see any error in the Vue console and however if I replace "{{ model }}" by "{{ cars }}" I can see the full message object updated.
I am using Vue 2.x.
Update:
I enclose an example:
https://jsfiddle.net/kvzvxk4f/1/
As you can see in the example I cannot render an specific field from the object, however I can render the object as string.
I think that you are misunderstanding some parts of the vue syntax.
How to access properties of an object:
You just need to write {{ car.model }} to access a property of an object.
How to iterate through an array in a template:
If you want to display all the cars in your template, you should write:
<div v-for="car in cars">
{{ car }}
</div>
As you see, the v-for directive allows you to iterate through an array.
What is v-model?
v-model is used to bind a variable to an input or a component.
<template>
<div>
<input type="text" v-model="foo" />
</div>
</template>
<script>
export default {
data () {
return {
foo: 'bar'
}
}
}
</script>
In that case, the foo property will be bound to the input text.
Last point:
In your case, to make it work, you also need to create a root element for your template, because a template can't have multiple root elements:
<template>
<div>
<div v-for="car in cars">
{{ car }}
</div>
</div>
</div>
I found the answer.
I just have to type property separated by ".". Like for example {{cars.model}}.
<template id="compo2">
<div>
<div>
{{ field.name }}
</div>
<div>
Received: {{ field }}
</div>
</div>
</template>
Example:
https://jsfiddle.net/zuhb7s8q/3/