First of all, please be kind. I'm new to VueJS coming from the Angular world where things are different ;-)
I am creating a multi-page website using VueJS for simple things like a floaty header and submission of forms etc. I'd like the markup for my contact form to be in my HTML (rendered by the CMS) and I'd like to have VueJS handle the form submission and replacing the form with a thank-you message. So, a simplified version of the form would look like this.
<contact-form>
<form class="contact-form_form">
...
<input name="emailaddress" type="text" />
...
<button></button>
</form>
<div class="contact-form_thanks">
Thanks for filling in this lovely form
</div>
</contact-form>
So, the obvious thing to do is to create a VueJS component, but I don't want it to introduce a new template, I just want it to submit the form when the button is pressed (using Axios) and hide the form and show the thank you message.
I know how to do all of this in angular using attribute directives and ng-show/hide etc. but can't really see how to do this in VueJS because all the tutorials are geared to wards SPAs and Single file components with templates.
Any kick in the right direction would be appreciated.
Seems like you just want a data item indicating whether the form has been submitted, and v-if and v-else to control what displays in either case.
new Vue({
el: 'contact-form',
components: {
contactForm: {
data() {
return { hasBeenSubmitted: false };
},
methods: {
doSubmit() {
console.log("Some behind-the-scenes submission action...");
this.hasBeenSubmitted = true;
}
}
}
}
});
<script src="//cdnjs.cloudflare.com/ajax/libs/vue/2.3.4/vue.min.js"></script>
<contact-form inline-template>
<div v-if="hasBeenSubmitted" class="contact-form_thanks">
Thanks for filling in this lovely form
</div>
<form v-else class="contact-form_form">
...
<input name="emailaddress" type="text" /> ...
<button #click.prevent="doSubmit">Submit</button>
</form>
</contact-form>
Related
I have a background in Angular. Starting with vue was an okay experience for me until I came across a problem which VueJS developers seem to have shit on and slid under the carpet.
How can we create a form in which user can press enter from an input field to submit the form
This was seriously disappointing.
and please if you know the answer be kind enough to post in the Official vue documentation as well.
*Note:
my workaround: I used v-on:keydown.enter.prevent='loginUser' on every input field.
is there any way to not use it this way ( on every input field).
With button type as submit as well, form gets submitted when Enter key is pressed on any input.
No explicit binding is required on keypress.
new Vue({
el: '#app',
data() {
return {
title: "Vue 2 -Form submission on Enter",
formInput:{
fname:'',
lname:'',
gender:'male'
}
};
},
methods:{
onSubmit(){
console.log('submitted', this.formInput)
}
}
})
.form{
display:flex;
flex-direction:column;
gap:10px;
max-width:200px
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app"><h2>{{title}}</h2>
<form v-on:submit.prevent="onSubmit" class="form">
<input v-model="formInput.fname" #keydown.enter.prevent placeholder="first name"/>
<input v-model="formInput.lname" placeholder="last name"/>
<div>
<input v-model="formInput.gender" name="gender" placeholder="Gender" type="radio" value="male"/>male
<input v-model="formInput.gender" name="gender" placeholder="Gender" type="radio" value="female"/>Female
</div>
<button type="submit">Submit</button>
<pre>{{formInput}}</pre>
</form>
</div>
I'd urge you to check out this page on the VueJS documentation.
It explains how to set events on certain interactions. For example, you can trigger a function call on pressing the Enter key within an input field by doing this:
<input type="text" #keyup.enter="submit">
This will call the submit() method when the Enter key is pressed and released (keyup). On press, you can use keydown instead.'
In fact, the example I've taken is directly from this section in the page I linked above.
EDIT: A pure-HTML way to do this is to set your input type as submit, which will allow Enter to submit the form
You need to wrap your inputs within <form> ... </form> tag
How do I ask the user for a confirmation before changing the option in a radio button using Vue.js?
Something like Are you sure? would be fine.
Assuming you have the following DOM structure:
<div id="app">
<input type="radio"/>
</div>
you can bind a #change directive to the radio button with a method implementing the expected "Are you sure?" confirmation popup. So you can enrich the above mentioned DOM structure like this:
<div id="app">
<input type="radio" #change="showConfirm"/>
</div>
And in the Vue instance you can define the expected confirmation method, for example:
new Vue({
el: '#app',
methods: {
showConfirm: function(event) {
event.preventDefault();
let checkedRadio = window.confirm("Are you sure?");
event.target.checked = checkedRadio;
}
}
})
Here you find the working example.
I have prepared tag input control in Vue with tag grouping. Templates includes:
<script type="text/x-template" id="tem_vtags">
<div class="v-tags">
<ul>
<li v-for="(item, index) in model.items" :key="index" :data-group="getGroupName(item)"><div :data-value="item"><span v-if="typeof model.tagRenderer != 'function'">{{ item }}</span><span v-if="typeof model.tagRenderer == 'function'" v-html="tagRender(item)"></span></div><div data-remove="" #click="remove(index)">x</div></li>
</ul>
<textarea v-model="input" placeholder="type value and hit enter" #keydown="inputKeydown($event,input)"></textarea>
<button v-on:click="add(input)">Apply</button>
</div>
</script>
I have defined component method called .getGroupName() which relays on other function called .qualifier() that can be set over props.
My problem: once I add any tags to collection (.items) when i type anything into textarea for each keydown .getGroupName() seems to be called. It looks like entering anything to textarea results all component rerender?
Do you know how to avoid this behavior? I expect .getGroupName to be called only when new tag is added.
Heres the full code:
https://codepen.io/anon/pen/bKOJjo?editors=1011 (i have placed debugger; to catch when runtime enters .qualifier().
Any help appriciated.
It Man
TL;DR;
You can't, what you can do is optimize to reduce function calls.
the redraws are dynamic, triggered by data change. because you have functions (v-model and #keydown) you will update the data. The issue is that when you call a function: :data-group="getGroupName(item)" it will execute every time, because it makes no assumptions on what data may have changed.
One way of dealing with is is setting groupName as a computed key-val object that you can look up without calling the function. Then you can use :data-group="getGroupName[item]" without calling the function on redraw. The same should be done for v-html="tagRender(item)"
Instead of trying to fight how the framework handles data input events and rendering, instead use it to your advantage:
new Vue({
el: '#app',
template: '#example',
data() {
return {
someInput: '',
someInputStore: []
};
},
methods: {
add() {
if (this.someInputStore.indexOf(this.someInput) === -1) {
this.someInputStore.push(this.someInput);
this.someInput = '';
}
},
}
});
<html>
<body>
<div id="app"></div>
<template id="example">
<div>
<textarea v-model="someInput" #keyup.enter.exact="add" #keyup.shift.enter=""></textarea>
<button #click="add">click to add new input</button>
<div>
{{ someInputStore }}
</div>
</div>
</template>
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.16/dist/vue.js"></script>
</body>
</html>
Event modifiers modifying
In the example, you can see that I am using 4 different event modifiers in order to achieve the desired outcome, but I will focus on the combination of them here:
#keyup.enter.exact - allows control of the exact combination of system modifiers needed to trigger an event. In this case, we are looking for the enter button.
#keyup.shift.enter - this is the interesting bit. Instead of trying to hackily prevent the framework from firing on both events, we can use this (and a blank value) to prevent the event we added into #keyup.enter.exact from firing. I must note that ="" is critical to the whole setup working properly. Without it, you aren't giving vue an alternative to firing the add method, as shown by my example.
I hope this helps!
I am just starting with Vue and Vuex and am wondering how to go about saving an entire form to an API. I have found this and it only seems like a good solution for a single field. Does this imply I would need to do a custom computed attribute with a getter and setter for each field in the form? I understand how data binding works well for local storage (which seems to be what most examples use) but updating a backend service with every keystroke seems like overkill.
What I would like to do is perform a single commit on a form when the user performs an action (like click a save button) and I feel like making a computed property or method for every field is not the right way to go.
Template:
<div v-show="isEditing" class="edit-view">
<form>
<div class="form-group">
<label>Title</label>
<input :value="item.title" type="text" class="form-control" #input="update" />
</div>
<div class="form-group">
<label>Description</label>
<input :value="item.description" type="text" class="form-control" #input="update" />
</div>
</form>
</div>
JS:
export default {
name: 'todo',
props: ['item'],
data() {
return {
isEditing: false
}
},
methods: {
showEdit() {
this.isEditing = true;
},
update() {
// Commit a change to vuex store
}
}
Keep the form data local to your form component. So define all form properties in data(). Apply v-model to all the input elements and your corresponding data properties. When user clicks submit, make a single commit with the form data.
This way, your form component will contain the edited values, and the vuex store will contain the submitted values.
So I'm just starting to play with Vue.js and I would like to know if there is a nice way to initialize the data object with html tags content from the page.
Basically I have a page that displays information and I would like to turn it into a tiny Vue application to avoid having a separated edit page.
So I added the form with 2 way binding which submits the values via ajax.
The thing is I really want to avoid Flash Of Uncompiled Content, but then I feel like I have to duplicate all my data, once in the html tag, once in the data object.
<div id="app">
<span v-text="prop1">This is filled by the backend</span>
<input v-model="prop1" type="text" v-cloak />
</div>
<script>
new Vue({
el: "#app",
data: {prop1: "This is filled by the backend..again"} // << Can I avoid this?
});
</script>
Could I tell Vue to get the data from the html tags since it's already there?
Thanks!
You are looking for props
Your html element would look something like
<custom-element dataToPass="dataFromHtml"></custom-element>.
Then you can access it in your vue instance via this.dataToPass.
Have a read through the documentation, there is a difference if you pass a string or an expression (from another vue instance for example).
In your example:
<div id="app">
<span prop1="{ backendVariable}" v-text="prop1"></span>
<input v-model="prop1" type="text" v-cloak />
</div>
<script>
new Vue({
el: "#app",
props: ['prop1']
});
</script>
```