I have a custom radio list with hidden input radio fields. Whenever I click on my custom radio button I want the hidden radio button to be checked. My custom radio button has a #click function and in that function I have the following code:
customRadioHandler(key) {
this.$refs[key].checked;
}
The key parameter is the same as the ref in the hidden radio button. This code does not seem to check the hidden radio button. Does anyone know how to fix this?
<template>
<div id="app">
<label>
<input type="radio" #click="handleFirstRadioClick" />
test1
</label>
<label class="radio-2">
<input type="radio" :checked="secondRadioValue" />
test2
</label>
</div>
</template>
<script>
export default {
name: "App",
data() {
return {
secondRadioValue: false,
};
},
methods: {
handleFirstRadioClick() {
return (this.secondRadioValue = true);
},
},
};
</script>
Full example:
https://codesandbox.io/s/amazing-dust-hen6w?file=/src/App.vue
Related
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>
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>
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 ''?
I created a career page which is when user select the title of the position that they apply, it will redirect into application form and it will display the title of the position. If they are interested to apply for the position they will enter some input which is their full name, contact and cv. Once they submitted the application, it will send the data into the server include the position that they already applied.
Header.vue
<template>
<div>
<h1 class="title-wrapper">
Application Form
</h1>
<p class="info-wrapper">
You are applying as
<nuxt-link to="/careers">
<u>{{ title }}</u>
</nuxt-link>
</p>
</div>
</template>
<script>
export default {
name: 'Header',
props: {
title: {
type: String,
default: ''
}
}
};
</script>
Form.vue
<form class="app-form" #submit.prevent="onSubmit">
<InputField
v-model="fullName"
label="Full Name"
firequired
required
placeholder="Your full name"
#handleChange="handleChangeName($event)"
/>
<button type="submit">Submit</button>
</form>
Application.vue (Parent)
<div class="contact-wrapper">
<Intro :title="title" />
<Form />
</div>
The validation for submit the form is inside the Form.vue, how to send the title from Header.vue into Form.vue and send it into the server. This is what I've tried
Form.vue
<script>
export default {
name: 'Submit',
template: '<nuxt-link to="/careers"><u>{{ title }}</u></nuxt-link>',
methods: {
onSubmit() {
this.$axios.post('url', {
position:this.title
})
}
};
</script>
And it returns nothing
Sorry for the title, didn't know how I could better explain it.
I have 3 radio buttons. The output should be the value of whichever radio button is selected. Except, the 3rd radio button has a textarea, and if that radio button is selected, the resulting output should be what is in the textarea. I've also linked the #click of textarea to automatically check the radio button, so if a user clicks on the textarea, that radio button gets checked automatically.
Everything works, if you see the JSFiddle code and click on the 3rd radio button and type text in the textarea, the output should work fine. But if you refresh the page, and instead of clicking the radio button, if you directly click on the textarea (which indirectly checks the radio button), writing in the textarea will not update the output. Which means the compute function is not working.
However if you click on another radio button and then click back on the 3rd radio button, things will start working fine.
Here's the code (JSFiddle here: https://jsfiddle.net/eywraw8t/43651/ )
<div id="app">
Selected option 1: {{ selectedText }}
<BR>
<input type="radio" name="item1" value="" v-model="selected[0]" /> Empty<BR>
<input type="radio" name="item1" value="Hi" v-model="selected[0]" /> Hi<BR>
<input type="radio" name="item1" value="**custom**" v-model="selected[0]" /> <textarea name="textarea0" id="textarea0" cols="30" rows="10" v-model="custom[0]" #click="customClicked"></textarea><BR>
</div>
<script>
new Vue({
el: "#app",
data: {
selected: ['', ''],
custom: ['', ''],
},
computed: {
selectedText: function() {
if (this.selected[0] != '**custom**') return this.selected[0];
return this.custom[0];
}
},
methods: {
customClicked: function(e) {
//$(e.target).prev().prop('checked', true);
this.selected[0] = '**custom**';
this.$forceUpdate();
}
}
})
</script>
You don't need jQuery for this - just bind the values to one array and use #focus event on the textarea:
new Vue({
el: "#app",
data: {
values: ['', 'Hi', ''],
selected: '',
},
computed: {
selectedText: function() {
return this.values[this.selected];
}
}
})
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<div id="app">
Selected option 1: {{ selectedText }}
<BR/>
<input type="radio" name="item1" value="0" v-model="selected" /> Empty
<BR/>
<input type="radio" name="item1" value="1" v-model="selected" /> Hi
<BR />
<input type="radio" name="item1" value="2" v-model="selected" />
<textarea name="textarea0" id="textarea0" cols="30" rows="10" v-model="values[2]" #focus="selected = '2'"></textarea>
</div>
Also the JSFiddle.
Update
As the questioner choose another answer, but i don't think that is the key point.
The reason is $forceUpdate() only force the view to re-render, not the computed properties. See the issue forceUpdate does not update computed fields
And i create a simple jsfiddle to descript it.
Raw Answer
The problem you faced is that vuejs cannot detect array change in some situation. You can see more detail in the doc vuejs list rendering
So the solution is replaced these code
this.selected[0] = '**custom**';
this.$forceUpdate();
with
this.$set(this.selected, 0, '**custom**')
While writing the answer I got an idea and it seems to work. However I still want to know if there is a "right" way of doing things which I'm missing.
The fix was to "click" the radio button instead of "checking" it:
$(e.target).prev().click();