How to change vue.js components data outside scope - vue.js

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).

Related

How to fix Vue 3 template compilation error : v-model value must be a valid JavaScript member expression?

I am working on a vue project and the vue version is 3.0
And recently I can see these many warnings for some reason.
Template compilation error: v-model value must be a valid JavaScript member expression
I guess it is because I am using long v-model variable name like this.
<textarea v-model="firstVariable.subVariable.subVariableKey" readonly></textarea>
Please let me know if any idea.
Thanks in advance
This is the component and template code.
var myTemplate = Vue.defineComponent({
template: '#myTemplate',
data() {
return {
firstVariable: {}
}
},
mounted() {
loadData();
},
methods:{
loadData() {
axios.get(MY_ROUTES).then(res => {
// let's suppose res.data is going to be {subVariable: {subVariableKey: "val"}}
this.firstVariable = res.data;
})
}
}
});
// template.html
<script type="text/template" id="myTemplate">
<div class="container">
<textarea v-model="firstVariable.subVariable?.subVariableKey"></textarea>
</div>
</script>
In order that your property go reactive you've to define its full schema :
data() {
return {
firstVariable: {
subVariable: {
subVariableKey: ''
}
}
}
},
and use it directly without optional chaining
v-model="firstVariable.subVariable.subVariableKey"
because v-model="firstVariable.subVariable?.subVariableKey" malformed expression like v-model="a+b" like this test
Example
var comp1 = Vue.defineComponent({
name: 'comp1',
template: '#myTemplate',
data() {
return {
firstVariable: {
subVariable: {
subVariableKey: ''
}
}
}
},
mounted() {
this.loadData();
},
methods: {
loadData() {
}
}
});
const {
createApp
} = Vue;
const App = {
components: {
comp1
},
data() {
return {
}
},
mounted() {
}
}
const app = createApp(App)
app.mount('#app')
<script src="https://unpkg.com/vue#3.0.0-rc.11/dist/vue.global.prod.js"></script>
<div id="app" >
vue 3 app
<comp1 />
</div>
<script type="text/template" id="myTemplate">
<div class="container">
<textarea v-model="firstVariable.subVariable.subVariableKey"></textarea>
<div>
{{firstVariable.subVariable.subVariableKey}}
</div>
</div>
</script>
You are adding a new property to an object which is not reactive.
Vue cannot detect property addition or deletion. Since Vue performs
the getter/setter conversion process during instance initialization, a
property must be present in the data object in order for Vue to
convert it and make it reactive. For example:
Source
Instead of
this.firstVariable = res.data;
Use
this.$set(this.firstVariable, 'subVariable', res.data.subVariable);

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()

set property and retrieve HTML as string from Vue component

In order to separate my code and make it cleaner, I would like to use a Vue component as an HTML template, pass some parameters to the template and get the resulting HTML back as a string.
I have made a simple example that almost works, but for some reason the returned HTML is not up to date. When I hit "click me" I do get an HTML-string from the "MyDetails"-component, but it shows the value passed from the previous time, I hit the "click me"-button, instead of showing the actual value.
Main.vue
<template>
<div>
<p>
<myDetails ref="myDetails"/>
</p>
<button #click="handleClick">click me</button>
<p>{{message}}</p>
</div>
</template>
<script>
import MyDetails from "/components/MyDetails.vue";
export default {
name: "hello",
components: {
MyDetails
},
methods: {
handleClick() {
this.$refs.myDetails.setMessage(new Date().getTime());
this.message = this.$refs.myDetails.$el.outerHTML;
}
},
data() {
return {
message: ""
};
}
};
</script>
MyDetails.vue
<template>
<div style="background-color:red">
<h1>MyDetails component</h1>
<p>{{message}}</p>
</div>
</template>
<script>
export default {
name: "hello",
data() {
return {
message: ""
};
},
methods: {
setMessage(value) {
this.message = value;
}
}
};
</script>
In the example above "MyDetails" is part of the template from the beginning. Is it possible to load it dynamically in the click-handler instead, so it doesn't show up, before I hit the "click me"-button?
Please see code here: https://codesandbox.io/s/vue-fullcalendar-example-50sv9?fontsize=14&hidenavigation=1&theme=dark
Updating the DOM takes time, you are immediately getting the myDetails outerHTML after you are changing its data, which doesn't give time for the change to propagate. Setting a slight delay as follows will give output as expected:
handleClick() {
this.$refs.myDetails.setMessage(new Date().getTime());
setTimeout(() => {
this.message = this.$refs.myDetails.$el.outerHTML;
}, 100)
}
For demo, see the sandbox here

Vue: Using input value in function

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>

How to address the data of a component from within that component?

In a standalone Vue.js script I can mix functions and Vue data:
var vm = new Vue ({
(...)
data: {
number: 0
}
(...)
})
function return100 () {
return 100
}
vm.number = return100()
I therefore have a Vue instance (vm) which data is directly addressable via vm.<a data variable>)
How does such an addressing works in a component, since no instance of Vue is explicitly instantiated?
// the component file
<template>
(...)
</template>
<script>
function return100 () {
return 100
}
export default {
data: function () {
return {
number: 0
}
}
}
// here I would like to set number in data to what return100()
// will return
??? = return100()
</script>
You can achieve the target by using code like this.
<template>
<div>{{ name }}</div>
</template>
<script>
const vm = {
data() {
return {
name: 'hello'
};
}
};
// here you can modify the vm object
(function() {
vm.data = function() {
return {
name: 'world'
};
}
})();
export { vm as default };
</script>
But I really don't suggest you to modify data in this way and I think it could be considered as an anti-pattern in Vuejs.
In almost all the use cases I met, things could be done by using Vue's lifecycle.
For example, I prefer to write code with the style showed below.
<template>
<div>{{ name }}</div>
</template>
<script>
export default {
data() {
return {
name: 'hello'
};
},
mounted() {
// name will be changed when this instance mounted into HTML element
const vm = this;
(function() {
vm.name = 'world';
})();
}
};
</script>