Vue: Using input value in function - vue.js

I am using Single File Components and I have a modal component that has an
input box but I can't get the value of the input in a function below using the v-modal name. It keeps coming back as 'name is not defined'. Am I using the v-model attribute incorrectly?
<template>
<input v-model="name" class="name"></input>
</template>
<script>
export default {
methods: {
applyName() {
let nameData = {{name}}
}
}
}
</script>

You're right, you're using the v-model property incorrectly.
First off you need to define a piece of state in your component, using data:
export default {
data: () => ({
name: '',
}),
methods: {
log() {
console.log(this.name);
}
}
}
You can then bind this piece of data in your component using v-model="name", just like you did. However, if you want to access this piece of state in your method, you should be using this.name in your applyName() method.
Your {{name}} syntax is used to get access to the data in your template, like so:
<template>
<span>
My name is: {{name}}!
</span>
</template>

You have to use this pointer to access the model:
<template>
<input v-model="inputName" class="name"></input>
</template>
<script>
export default {
data() {
return {
inputName: '',
}
},
methods: {
applyName() {
// Notice the use of this pointer
let nameData = { name: this.inputName };
}
}
}
</script>

Look at the doc https://v2.vuejs.org/v2/guide/forms.html#v-model-with-Components
In the template, you are referring by name to data, computed or methods. In this case, it refers to data. When the input changes the name then the data is updated.
It is possible to use in a function referring to this.
<template>
<input v-model="name" class="name"></input>
</template>
<script>
export default {
data() {
return { name: '' }
},
methods: {
applyName() {
let nameData = this.name
}
}
}
</script>

Related

Vue pass data from compontent 1 to a method in component 2

I have a parent component and a childcomponent.
In my parent component I call a simple childcomponent-method to save an email to the email variable. But the variable email does not change.
My Parentcomponent:
import ChildComponent from "./ChildComponent";
export default {
components: {ChildComponent},
methods: {
openDocument(d) {
ChildComponent.methods.saveEmail('new#example.com');
}
}
My Childcomponent:
<template>
<div>
Email: {{ email }}
</div>
</template>
<script>
export default {
data: function () {
return {
email: ''
}
},
methods: {
saveEmail(email) {
this.email = email; // this does NOT change my email variable
}
}
}
</script>
Why my email variable does not change? How can I change this variable?
In vue it is not work like that. You have to use Probs:
Parent :
<template>
<div class="container">
<child-component :email ="email"></child-component> // NEW HERE
</div>
</template>
<script>
import ChildComponent from "./ChildComponent";
module.exports = {
data: function () {
return {
email:''
}
},
methods: {
openDocument(d) {
this.email = "example#gmil.com"
}
},
}
</script>
Child component:
<template>
<div class="container">
<h1>Profile Form Component</h1>
</div>
</template>
<script>
module.exports = {
module.exports = {
props: ['email'], //NEW HERE
created: function () {
console.log(this.email) //prints out an empty string
}
}
</script>
ATTENTION
As you I added 2 comment NEW HERE in the code , these 2 lines are really important for what you wanna do.
The code that I giving you is an example (not a complete answer) , Probs is the solution of what you asked for.
Hope it Helps <3.
The ChildComponent variable only holds the recipe for creating components of this type - but it does not hold your actual component. Your actual component lives inside your template - you have to add a ref attribute to it (e.g. <custom-component ref="custom" ... />) and then reference it like this.$refs.custom.saveEmail()

How to change vue.js components data outside scope

I want to change vue.js data outside the default export statement. Given the example below, how would I go about doing that?
<template>
<div>
<h6 class="font-weight-normal mb-3">{{ name }}</h6>
</div>
</template>
<script>
export default {
data() {
return {
name: ""
}
}
}
let changeName = (name) => {
//How do I change the name data property here
}
</script>
If you assign the component to a variable/constant, you should be able to simply trigger the proxy setter of the data object or with component-level methods.
const component = new Vue({
data() {
return {
name: "Initial value."
}
},
methods: {
changeName(newName) {
this.name = newName;
}
}
});
// Mount it to an element (for demo purposes)
component.$mount('#app');
document.getElementById('btn-setter').onclick = function() {
component.name = 'Changed with SETTER';
};
document.getElementById('btn-method').onclick = function() {
component.changeName('Changed with METHOD');
};
// Uncomment this to start exporting it.
// export default component;
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<h6 class="font-weight-normal mb-3">{{ name }}</h6>
<button id="btn-setter">Change with setter</button>
<button id="btn-method">Change with method</button>
</div>
You can write any function you want in the page outside of the component (or export statement) but you would need to invoke it in your methods section or somewhere in the component. I use this for functions that create default values, instead of importing them from outside just write a function initVal = () => someVal then in the data or computed or somewhere reference initVal (no this).

Properly alert prop value in parent component?

I am new to Vue and have been very confused on how to approach my design. I want my component FileCreator to take optionally take the prop fileId. If it's not given a new resource will be created in the backend and the fileId will be given back. So FileCreator acts as both an editor for a new file and a creator for a new file.
App.vue
<template>
<div id="app">
<FileCreator/>
</div>
</template>
<script>
import FileCreator from './components/FileCreator.vue'
export default {
name: 'app',
components: {
FileCreator
}
}
</script>
FileCreator.vue
<template>
<div>
<FileUploader :uploadUrl="uploadUrl"/>
</div>
</template>
<script>
import FileUploader from './FileUploader.vue'
export default {
name: 'FileCreator',
components: {
FileUploader
},
props: {
fileId: Number,
},
data() {
return {
uploadUrl: null
}
},
created(){
if (!this.fileId) {
this.fileId = 5 // GETTING WARNING HERE
}
this.uploadUrl = 'http://localhost:8080/files/' + this.fileId
}
}
</script>
FileUploader.vue
<template>
<div>
<p>URL: {{ uploadUrl }}</p>
</div>
</template>
<script>
export default {
name: 'FileUploader',
props: {
uploadUrl: {type: String, required: true}
},
mounted(){
alert('Upload URL: ' + this.uploadUrl)
}
}
</script>
All this works fine but I get the warning below
Avoid mutating a prop directly since the value will be overwritten
whenever the parent component re-renders. Instead, use a data or
computed property based on the prop's value. Prop being mutated:
"fileId"
What is the proper way to do this? I guess in my situation I want the prop to be given at initialization but later be changed if needed.
OK, so short answer is that the easiest is to have the prop and data name different and pass the prop to the data like below.
export default {
name: 'FileCreator',
components: {
FileUploader
},
props: {
fileId: Number,
},
data() {
return {
fileId_: this.fileId, // HERE WE COPY prop -> data
uploadUrl: null,
}
},
created(){
if (!this.fileId_){
this.fileId_ = 45
}
this.uploadUrl = 'http://localhost:8080/files/' + this.fileId_
}
}
Unfortunately we can't use underscore as prefix for a variable name so we use it as suffix.

Get input values from child components in Vue

I would like to retrieve all input values from my child components (client and advice, seen below), but not sure how to proceed.
client.vue
<template>
<div id="client">
<input type="text" v-model="client.name" />
<input type="text" v-model="client.code" />
</div>
</template>
<script>
export default {
data() {
return {
client: {
name: '',
code: '',
}
}
}
}
</script>
advice.vue
<template>
<div id="advice">
<input type="text" v-model="advice.foo" />
<input type="text" v-model="advice.bar" />
<div v-for="index in 2" :key="index">
<input type="text" v-model="advice.amount[index]" />
</div>
</div>
</template>
<script>
export default {
data() {
return {
advice: {
foo: '',
bar: '',
amount:[]
}
}
}
}
</script>
Each component has more fields than the above example.
My home page (parent) looks as simple as:
<template>
<form id="app" #submit="printForm">
<clientInfo />
<advice />
<input type="submit" value="Print" class="btn" />
</form>
</template>
<script>
import clientInfo from "#/components/clientInfo.vue";
import advice from "#/components/advice.vue";
export default {
components: {
clientInfo,
advice
},
methods: {
printForm() {}
}
}
</script>
My first idea was to $emit, but not sure how to do that efficiently with more than 20 fields without attaching a #emitMethod="parentEmitMethod" to every single field.
My second idea was to have a Vuex store (as seen below), but I don't know how to save all the states at once and not sure if I should.
new Vuex.Store({
state: {
client: {
name:'',
code:''
},
advice: {
foo:'',
bar:'',
amount:[]
}
}
})
You could use FormData to get the values of the form's <input>s or <textarea>s that have a name attribute (anonymous ones are ignored). This works even if the form has nested Vue components that contain <input>s.
export default {
methods: {
printForm(e) {
const form = e.target
const formData = new FormData(form) // get all named inputs in form
for (const [inputName, value] of formData) {
console.log({ inputName, value })
}
}
}
}
demo
You could use v-model with your custom components. Let's say you want to use them like this:
<advice v-model="adviceData"/>
For this, you would need to watch for value changes on your input elements inside your advice component and then emit an input event with the values. This will update the adviceData binded property. One generic way to do this could be including a watcher inside your advice component, like this:
export default {
data() {
return {
advice: {
foo: '',
bar: '',
amount:[]
}
}
},
watch: {
advice: {
handler: function(newValue, oldValue) {
this.$emit('input', newValue);
},
deep: true,
}
},
}
This way you will not have to add a handler for each input field. The deep option must be included if we need to detect changes on nested data in the advice object.
I think you can achieve what you want is when the user writes something using#change this will trigger a method when the input value is changed, you could use a button instead or anything you want, like this:
The child component
<input type="text" v-model="advice.amount[index]" #change="emitCurrStateToParent ()"/>
You gotta add #change="emitCurrStateToParent ()" in every input you have.
emitCurrStateToParent () {
this.$emit("emitCurrStateToParent", this.advice)
}
Then in you parent component
<child-component v-on:emitCurrStateToParent="reciveDataFromChild ($event)"></child-component>
reciveDataFromChild (recivedData) {
// Do something with the data
}
I would use a button instead of #change, like a "Save" button idk, the same goes for vuex, you can use the #change event
saveDataAdviceInStore () {
this.$store.commit("saveAdvice", this.advice)
}
Then in the store
mutations: {
saveAdvice (state, advice) {
state.advice = advice
}
}

Using v-model with a prop on VUE.JS

I'm trying to use a data coming from a prop with v-model, the following code works, but with a warning.
<template>
<div>
<b-form-input v-model="value" #change="postPost()"></b-form-input>
</div>
</template>
<script>
import axios from 'axios';
export default {
props: {
value: String
},
methods: {
postPost() {
axios.put('/trajectory/inclination', {
body: this.value
})
.then(response => {
})
.catch(e => {
this.errors.push(e)
})
}
}
}
</script>
The warning says:
"Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "value"
So I changed and now I'm using a data as the warning says.
<template>
<div>
<b-form-input v-model="_value" #change="postPost()"></b-form-input>
</div>
</template>
<script>
import axios from 'axios';
export default {
props: {
value: String
},
data() {
return {
_value: this.value
}
},
methods: {
postPost() {
axios.put('/trajectory/inclination', {
body: this._value
})
.then(response => {
})
.catch(e => {
this.errors.push(e)
})
}
}
}
So now the code it's not working and the warning says:
"Property or method "_value" is not defined on the instance but referenced during render. Make sure to declare reactive data properties in the data option"
Any idea how to fix the first code to suppress the warning? (or some idea on how to fix the second code?)
Obs.: b-form-input it's not my componente, this is the Textual Input from Boostrap-Vue (Doc for b-form-input)
Answer is from https://github.com/vuejs/vue/issues/7434
Props are read-only, but you are trying to change its value with v-model. In this case, if you change the input value, the prop is not modified and the value is restored on the next update.
Use a data property or a computed setter instead:
computed: {
propModel: {
get () { return this.prop },
set (value) { this.$emit('update:prop', value) },
},
},
https://v2.vuejs.org/v2/guide/computed.html#Computed-Setter
Bert addresses your direct issue, but I think you should also know that your approach is a bit off. Since ultimately you are sending the new value to postPost, you don't really need to modify your local copy. Use the event object that is sent to the change handler to get the current value from the input.
Instead of v-model, just use :value, and don't include the invocation parentheses when specifying the change handler.
<template>
<div>
<b-form-input :value="value" #change="postPost"></b-form-input>
</div>
</template>
<script>
import axios from 'axios';
export default {
props: {
value: String
},
methods: {
postPost(event) {
axios.put('/trajectory/inclination', {
body: event.target.value
})
.then(response => {
})
.catch(e => {
this.errors.push(e)
})
}
}
}
</script>
_ prefixed properties are reserved for Vue's internal properties.
Properties that start with _ or $ will not be proxied on the Vue
instance because they may conflict with Vue’s internal properties and
API methods.
Try changing _value to something that doesn't start with an underscore.
One general workaround is to introduce a data-variable and watch the props to update-variable. This is quite subtle and so easy to get wrong so here's an example with a Vuetify modal using v-model (the same technique, in theory, should work with <input> and others):
<template>
<v-dialog v-model="isVisible" max-width="500px" persistent>
</v-dialog>
</template>
<script>
export default {
name: 'Blablabla',
props: {
visible: { type: Boolean, required: true }
},
data() {
isVisible: false
},
watch: {
// `visible(value) => this.isVisible = value` could work too
visible() {
this.isVisible = this.$props.visible
}
}
}
</script>
The official Vue docs shows how to use v-model on a custom component: https://v2.vuejs.org/v2/guide/components.html#Using-v-model-on-Components
TL;DR:
You simply need to have a specifically named value prop, and emit an input event which the v-model when you instantiate the component maps for you.
More info on how this works on the link above.
<template>
<input
type="text"
:value="value"
#input="$emit('input', $event.target.value)"
/>
</template>
<script>
export default {
name: "Input",
props: {
value: String,
},
};
</script>
<Input v-model="searchText"></Input>
Point your input v-model directive to a data property named value_ (or any other name not starting with prefixes _ or $ which are reserved by Vue). Set the data property's default value to null. Then, add a method getValue() which will set property value_ based on your value prop's value. Finally, call getValue() in Vue's created() lifecycle hook. Like so:
<template>
<div>
<b-form-input v-model="value_" #change="postPost()">
</b-form-input>
</div>
</template>
<script>
import axios from 'axios';
export default {
data: () => ({
value_: null
}),
props: {
value: String
},
methods: {
postPost() {
axios.put('/trajectory/inclination', {
body: this.value_
})
.then(response => {
})
.catch(e => {
this.errors.push(e)
})
},
getValue() {
this.value_ = this.value;
}
},
created() {
this.getValue()
}
}
</script>
You can use a data like below.
<template>
<input type="text" v-bind:value="value" v-on:input="dValue= $event.target.value" />
</template>
<script>
export default {
props: ["value"],
data: function () {
return {
dValue: this.value,
};
},
methods: {
alertValue() {
alert("Current Value" + this.dValue);
},
},
};
</script>