How can I update the msg variable in the following code? - vue.js

I have written the following code in a single Vue component. I am very new to Vue. I want to know how can I update the msg variable in the following and pass the updated value to the template in this Vue component:
<template>
<div class="dropzone">
<form id="dropzone" method='POST' enctype="multipart/form-data" v-on:drop="upload" #dragover.prevent>
<my-vue-component v-model="msg" ref="markdownEditor" />
</form>
</div>
</template>
<script>
export default {
data: () => {
return {
msg: 'zyx'
}
},
methods: {
upload: (e) => {
self.msg = '123'
}
}
}
</script>
I am really stuck and none of the links that google redirects me to are out of my reach. Because all of them either talk about new Vue({}) or dont provide much on export default.
Am I doing something wrong here?
I have also tried this.msg, but then I get the error saying msg of undefined...

Change this:
upload: (e) => {
self.msg = '123'
}
to this:
upload (e) {
this.msg = '123'
}
Note that upload (e) { is short-hand for upload: function (e) {.
The key changes are:
Use this instead of self.
Don't use an arrow function because that binds this to the surrounding scope and in this case that's the global scope. What you want is for this to be bound to your component instance (which is actually a Vue instance) so you need to use a normal function. Vue tries to ensure the binding is correct but it can't do that with an arrow function because it is already bound.
The config options that appear in a component like this are almost all the same as the config options that you would pass to new Vue, so if you see examples that are using the other one it will rarely make any difference. Usually it is pretty obvious when a config setting doesn't make sense for one or the other.

Related

how to pass a function as parameter in a vue directive

in react and jsx I would use curly braces to pass nested functions and their params, as parameters. but since there is this quote syntax in vue js, I am confused.
what I'm trying to do is something like this:
<span #click="myFirstFunction( ()=> console.log('param') )" />
myFirstFunction(code){
code();
}
actually, this is the simplified version
what I'm trying to do is to save that code in an state and run it in other situations
but this doesn't seem to work.
Actually, your syntax is correct. But in your simple example, you are trying to access a property or a data which is not defined. You may think console is a global object it should be accessed from anywhere, but no. You can only access component properties (data, methods, etc.) from the template in VUE. So you should do something like below to access the console or any other global object:
data() {
return {
console: Object,
};
},
created() {
this.console = console;
},
SandBox
You should do either
<span #click="() => console.log('param')" />
or
<span #click="myFirstFunction" />
myFirstFunction should be defined as a method.
methods: {
myFirstFunction() {
// your function
}
}

V-model binding to generated input text field

Dynamic V-models created during an ajax request doesn't update when I try inputting a value
I'm using vue2.x and axios. I want to get the value set in generated input when user submit the form. I managed to set v-model on this input during ajax request
I receive this HTLM as response:
<input type="text" value="" v-model="generatedcode">. But after submitting the form the value is still empty. Looks like Vue ignore the v-model directive. How can I fix it ?
Here is my code :
VUE
var app = new Vue({
el: '#subcribtionform',
data: {
generatedform:'',
generatedcode:''
},
methods:{
OnSuccess(response){
this.generatedform = response.data;
},
OnclickSub(){
axios.post('/submitformURL',{
lastname: this.lastname,
generatedcode: this.generatedcode,
})
}
created: function () {
axios.get('/generate_inputURL').then(this.OnSuccess);
}
HTML
<div v-html="generatedform"></div>
GENERATED INPUT
<input type="text" value="" v-model="generatedcode"/>
Try:
created: function () {
axios.get('/generate_inputURL').then(res => this.OnSuccess(res));
}
Component data must be function not object. You should be seeing warning about this in console. I guess your component is not reactive data then, which means that is not redrawn after on request done.
data(): {
return {
generatedform:'',
generatedcode:''
}
}
As I can see, you want to change the vue-app template using v-html attr - I think this is not possible. While mounting the application, the template compiles into render function, so your trick does not make any sense. You can try to do the following:
Construct the template (using html recieved from server as you want ) as string or as hidden el in the DOM
Set it in your app object - template:your_html_template
Create vue app

Vue test utils - setChecked() not updating v-model

I am writing unit tests for some components I made at my job. We are using Mocha (TDD) and the Chai assertion library. I have a component with some checkboxes, and using the setChecked() method on them from vue-test-utils is not behaving as expected. I have made a small example that reproduces the error:
TestComponent.vue:
<template>
<div>
<input class="checkboxTest" type="checkbox" v-model="cbVal">
<input class="inputTest" type="text" v-model="textVal">
</div>
</template>
<script>
define([], function() {
return {
data: function() {
return {
cbVal: false,
textVal: ""
}
}
}
})
</script>
test.js:
suite("Random test", function() {
var VueTest;
var TestComponent;
//Import the vue test utils library and TestComponent
suiteSetup(function(done) {
requirejs(
["vue-test-utils", "vuec!components/TestComponent"],
function(VT, TC) {
VueTest = VT;
TestComponent = TC;
done();
}
);
});
//This test passes
test("fill in the input", function() {
var wrapper = VueTest.mount(TestComponent);
wrapper.find(".inputTest").setValue("Hello, world!");
assert.equal(wrapper.vm.textVal, "Hello, world!");
});
//This one does not
test("programatically check the box", function() {
var wrapper = VueTest.mount(TestComponent);
wrapper.find(".checkboxTest").setChecked(true);
//Prints out AssertionError: expected false to equal true
assert.equal(wrapper.vm.cbVal, true);
});
});
The textVal data member in TestComponent is getting changed, but cbVal is not. Can anyone please explain why setValue() works just fine, but setChecked() does not? Thank you in advance.
I had a similar issue and the accepted answer did not solve my problem. I don't think the accepted answer is correct either, as setChecked was added specifically to avoid having to manually set the values via the elements.
In my case, I wanted Vue to react to the v-model change and redraw. I tried async and many other methods, until finding the one that works: wrapper.vm.$forceUpdate().
Here's what my working code looks like:
wrapper.find("#someRadioButtonId").setChecked(true)
// manually force Vue to update
wrapper.vm.$forceUpdate()
expect(wrapper.find("#someRadioButtonId").classes()).toContain("selected") // success!
I can't answer why it doesn't work, but I can tell you your approach is incorrect in the first place.
You shouldn't be interacting with the html elements directly to set their values. When you set vue-model to cbVal you should instead be interacting with cbVal.
In other words, change your code from setChecked() to cbVal = true in order for it to comply with how Vue wants you to develop your project. There's no guarantee Vue can remain dynamic and reactive if you don't interact with your code the way Vue wants you to.

Vue 2 pass props to child [old : "call child's method"]

ok so I've learned that I'm not supposed to call a child's method but pass it props instead.
I've got (parent) :
<template>
<div id="main">
<Header :title ="title"/>
<router-view/>
<LateralMenu/>
</div>
</template>
<script>
export default {
name: 'app'
data: function () {
return {
title: true
}
},
methods: {
hideTitle: function () {
this.title = false
console.log(this.title)
},
showTitle: function () {
this.title = true
console.log(this.title)
}
}
}
</script>
and (child) :
<script>
export default {
name: 'Header',
props: ['title'],
created () {
console.log(this.title)
},
methods: {
}
}
</script>
the first console logs (inside the parent) print correctly on each method but the second console log within the child stays true all the time. I got this from : Pass data from parent to child component in vue.js
inside what method does the console.log need to be to be printed everytime the methods in the parent are triggered?
(this is why I wanted to go for method-calling, originally, by going with variables instead, we're potentially omitting valuable parts of the process such as optimization and a "when" for the execution(s!!) of our code. pontetally being the key word here, don't blow up on me, keep in mind that I'm learning.)
OLD:
I've browsed the web and I know there a a million different answers
and my point is with the latest version of vue none of those millions
of answers work.
either everything is deprecated or it just doesn't apply but I need a
solution.
How do you call a child method?
I have a 1 component = 1 file setup.
DOM is declared inside a <template> tag javascript is written inside
a <script> tag. I'm going off of vue-cli scaffolding.
latest method I've tried is #emit (sometimes paired with an #on
sometimes not) doesn't work :
child :
<script>
export default {
name: 'Header',
created () {
this.$on('hideTitlefinal', this.hideTitlefinal)
},
methods: {
hideTitlefinal: function () {
console.log('hideeeee')
},
showTitlefinal: function () {
console.log('shwowwww')
}
}
}
</script>
parent :
<template>
<div id="main">
<Header v-on:hideTitle="hideTitlefinal" v-on:showTitle="showTitlefinal"/>
<router-view/>
<LateralMenu/>
</div>
</template>
<script>
export default {
methods: {
hideTitle: function () {
this.$emit('hideTitle')
},
showTitle: function () {
this.$emit('showTitle')
}
}
}
</script>
console :
Uncaught TypeError: this.$emit is not a function
at Object.showTitle (Main.vue?1785:74)
at VueComponent.showTitle (LateralMenu.vue?c2ae:113)
at boundFn (vue.esm.js?efeb:186)
at invoker (vue.esm.js?efeb:1943)
at HTMLDivElement.fn._withTask.fn._withTask (vue.esm.js?efeb:1778)
Please don't do this. You're thinking in terms of events. When x happens, do y. That's sooo jquery 2005 man. Vue still has all that stuff, but we're being invited to think in terms of a view model...
You want your state in a variable, in window scope, and you want reactive pipes linking your vue stuff to your state object. To toggle visibility, use a dynamic class binding, or v-if. Then think about how to represent your state. It could be as simple as having a property like store.titleVisible. But, you want to 'normalize' your store, and avoid relationships between items of state. So if title visibility really depends on something higher up, like an editMode or something, then just put the higher-up thing in the store, then create computed properties if you need them.
The goal is that you don't care when things happen. You just define the relationships between the markup and the store, then let Vue take care of it. The docs will tell you to use props for parent=>child and $emit for child=>parent communication. Truth is you don't need this until you have multiple instances of a component, or reusable components. Vue stuff talks to a store, not to other vue stuff. For single-use components, as for your root Vue, just use the data:.
Whenever you find yourself writing show/hide methods, you're doing it wrong. It's intuitive (because it's procedural), but you'll quickly appreciate how much better the MVVM approach is.

vuejs handsontable official and calling handsontable method

I'm a beginner, this is probably more of a javascript problem than vue but anyway:
there a plugin for spreadsheet named handsontable and in the normal use you make the table by doing this
hot = new Handsontable(container, {option})
and then you can use the method like hot.loadData() etc..
To use handsontable with vuejs, there a wrapper we can find here https://github.com/handsontable/vue-handsontable-official. With the wrapper you make a table like this :
<template>
<div id="hot-preview">
<HotTable :root="root" :settings="hotSettings"></HotTable>
</div>
</template>
<script>
import HotTable from 'vue-handsontable-official';
import Vue from 'vue';
export default {
data: function() {
return {
root: 'test-hot',
hotSettings: {
data: [['sample', 'data']],
colHeaders: true
}
};
},
components: {
HotTable
}
mounted () {
localforage.config({
driver: localforage.INDEXEDDB,
name: 'matchlist-database'
})
localforage.getItem('DB').then(function (value) {
console.log('then i fetch the DB: ' + JSON.stringify(value))
if (value !== 'null') {
console.log('dB contain something')
**root**.loadData(value)
}
</script>
So it work fine when i give an array but to load the data from a DB you must call the handsontable method hot.loadData(data).
i cannot find how to call this method in vuejs i always get the error
TypeError: root.loadData is not a function
i tried with all i could think of instead of root ex: HotTable.loadData(value)
but to no avail
Can someone point me out how i would call handsontable methods from the vuejs wrapper. Or point me out what kind of reading i should do to understand my mistake. Thank a lot
There are two problems here, not bad ones :)
1st problem:
If you want to refer to your data inside Vue's methods/computed properties/watchers/lifecycle events, you should use the this keyword. If you have data: function() { return { root: "root-value" }} and you would like to console.log that "root-value" string, you should write console.log(this.root) inside your mounted handler.
If you had something like:
data: function() {
return {
hot = new Handsontable(container, {option})
....
};
You could call hot.loadData() like so:
mounted() {
this.hot.loadData();
...
}
So this refers to the Vue instance which exposes your data properties.
2nd problem:
If I understand the component wrapper correctly, you are supposed to pass data to it as props, not call any Handsontable methods directly.
<HotTable :root="root" :settings="hotSettings"></HotTable>
This means that Vue passes whatever you have as root in your data to the HotTable component. It also passes whatever you have as settings in your data. In the example, HotTable receives these:
root: 'test-hot',
hotSettings: {
data: [['sample', 'data']],
colHeaders: true
}
Now if you want to change/update/modify/add data that should be passed to the HotTable component, you should update your data in the Vue instance. You should do something like this.hotSettings = something new and this.root = something else and the HotTable component would receive those.
To understand what's really happnening with the HotTable, read all of the component documentation. Really. You will save lots of time if you read through the documentation. It all makes sense after that!
https://v2.vuejs.org/v2/guide/components.html