vuejs payload only emitting first element in an array - vue.js

im using the dropzone plugin with vuejs and the response from dropzone is an array. The payload has an array of arguments, a response and the file object. Every time i call #vdropzone-success="$emit('processFunction',$event) it will correctly send the request to the right function but only the first element of the payload array is returned. Why? I have attached a screenshot of the vue debugger to help illustrate the problem. How can i access the payload in processFunction to get to array element 0 and 1?
to add more context. This is the function in the library that is emitting to my child component
this.dropzone.on("success", function(file, response) {
vm.$emit("vdropzone-success", file, response);
});
after this in my vue code i am emitting this result to my index component:
<vue-dropzone
id="dropzone"
ref="myVueDropzone"
#vdropzone-drop="$emit('loading')"
#vdropzone-success="$emit('loaded',...$event)"
:use-custom-slot="true"
:options="dropzoneOptions"
>
I am binding to the element on my index.vue here:
<Upload #loading="loading" #loaded="loaded" />
to then call the function loaded
loaded(e) {
console.log(e);
this.notLoading = true;
this.isLoading = false;
},
https://github.com/vuejs/vue/issues/5527 this looks like A similar problem. Whenever i call $event it only returns 0 which is the file. I want it to return 1 which is the response from the serve (Object).

ok.. I feel like there should be a better way to do this, but... it looks like i can't pass the array variable through the vue tags from the library->child->parent directly. Instead I need to pull the array out in js in the child, and re-emit it in the js to the parent. the below solution worked.
library:
this.dropzone.on("success", function(file, response) {
vm.$emit("vdropzone-success", file, response);
});
child (helper.vue):
<!-- file upload -->
<vue-dropzone
id="dropzone"
ref="myVueDropzone"
#vdropzone-drop="$emit('loading')"
#vdropzone-success="processdata"
:use-custom-slot="true"
:options="dropzoneOptions"
>
and the js part of that
methods: {
processdata(...ev){
this.$emit("loaded",ev);
},
and finally the parent (index.vue)
<Upload #loading="loading" #loaded="loaded" />
and the js for that
loaded(...e) {
this.storedValue = e;
not the most elegant solution, but it is working!

You can try this:
Child
#vdropzone-success="$emit('loaded')"
Parent
<Upload #loading="loading" #loaded="loaded" />
loaded(payload) {
this.storedValue = payload;
}

Related

Unable to add elements using the setAttribute

I am using the VUE JS code and trying to add the setAttribute to some of the tags.
Here is the code I am using :
changetab() {
const demoClasses = document.querySelectorAll(".delCon__select");
demoClasses.forEach(button => {
button.setAttribute("tabindex", "0");
});
return true;
},
but when I view in the code inspector, It does not show added to it, I have added the above function in computed.
template is like this :
<template>
<el-container class="orders"></el-download>
</template>
You need to make this type of request in Vue's Lifecycles, like: created or mounted.
Something like:
mounted() {
this.changetab()
}
Computed would not be the most appropriate place for this type of action.

Vue: How to call a function within a sibling component?

I have an app that has a Parent component (app.js) and 2 child sibling components ( Modal.vue and Cart.vue).
I am getting a response back from a call within Modal.vue that needs to trigger a function within Cart.vue right after. What are the best options of going about this?
I don't currently use Vuex, which I know would make this easier.
You can use refs like so:
<parent>
<modal #triggerFunc="triggerFunc"/>
<cart ref="$cartRef"/>
</parent>
...
triggerFunc(){
this.$refs.$cartRef.functionIwantToTrigger()
}
You could create an event bus:
https://www.digitalocean.com/community/tutorials/vuejs-global-event-bus
You can use Custom Events for this using the root Vue instance of the current component tree.
In Modal.vue:
Where you are getting a response back from a call, simply emit a custom event like:
this.$root.$emit('onupdate', data);
In Cart.vue:
Simply listen to this root emitted event like
var vm = new Vue({
data: {},
mounted() {
this.$root.$on('onupdate', data => {
// trigger a function within Cart.vue
this.myFunction(data)
});
}
methods: {
myFunction: function(data) {
console.log(data);
}
}
})

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

VueJS - Update Parent Data After Ajax

I'm trying out VueJS, with the aim of incrementally updating a jQuery project, but I'm having issues with props in a child component passed through data from a parent component.
My parent component is
// parent_component.js
var parentData = {};
var parentComponent = Vue.component('parentComponent', {
data: function() {
return {
parentData: _parentData
}
},
delimiters: ['((', '))']
})
$.ajax({
url: '/someUrl/',
success: function(response) {
_parentData = response
}
My Child component is:
// child_component.js
Vue.component('child-component', {
template: '<div>((data.someProp))</div>'
props: ['data'],
delimiters: ['((', '))']
})
My HTML is:
// index.html
<parent-component inline-template>
<child-component v-bind:data="parentData"></child-component>
</parent-component>
This all works fine when I update _parentData right after initializing the childComponent. But I actually need to do an Ajax call and update the _parentData, it is not updated in the childComponent.
Nb. I checked that the _parentData object is there in the callback of the Ajax call.
Also, I tried putting the Ajax call in the created option of the childComponent, but this didn't help.
What am I missing?
Update
I guess I made the classic beginner's mistake! As stated here, Vue cannot detect property addition. So I need to define the someProp property on the _parentData before making the async call.
So if I define var parentData = { someProp: '' }; it will work.
See this fiddle: https://jsfiddle.net/maaikeb/anr1e88n/
If you share the AJAX part of code, maybe I can help better, but IMHO I think that the easiest way is emiting a event from children, and catch it with the parent element when the AJAX call is done (success or error).
Events provide a way to inform your parent components of changes in children.
Template Usage:
<my-component v-on:myEvent="parentHandler"></my-component>
<!-- Or more succinctly, -->
<my-component #myEvent="parentHandler"></my-component>
Firing an Event:
...
export default {
methods: {
fireEvent() {
this.$emit('myEvent', eventValueOne, eventValueTwo);
}
}
}
Additionally, you can create global event buses to pass events anywhere in your app
Extracted from here.
Edit
Ok, I didn't understand you well, if you have problems sending data down from parent to children when updating the parent the proper way is the double data binding.
Maybe your problem is that the data is only evaluated in component creation, and your child will be created with the initial value of the parent component...
You can try some different things to solve this, like:
1 - Maybe your issue is related to a change detection caveat
Maybe you're creating a new property in an object...
_parentData = response
...when you should do...
_parentData.$set('someObject.someProperty', someValue)
2 - Use watch on parent instead of created:
watch:{
yourData() {
$.ajax({
url: '/someUrl/',
content_type: 'application/json',
data_type: 'json',
success: function(response) {
_parentData = response
}
})
},
3 - Try using .sync ( deprecated in 2.0 ):
<component :something.sync="variable"></component>
4 - Bind .this to the anonymous AJAX call or use arrow functions as #Bert commented:
success: () => (response) {
_parentData = response
}
Hope it helps!

Can't copy props to model data and render it in Vue 2

I'm having this problem that looks a lot like a bug to me and I can't figure out how to solve it.
I created a generic list component and I tell it what child component it should insert in each item and what are the data it should pass to the child component. I'm passing everything as props along with the list (array) itself.
The problem is that I can't mutate the list props. So I try to copy it to model attribute. Otherwise I get this error:
Avoid mutating a prop directly since the value will be overwritten
whenever the parent component re-renders.....
And I can't just make it work in any of the lifecycle events. When I save the file and the hot-reloading reloads the page, the list is there, rendered, full of items. When I press F5 to manually reload the page, it is no more. Everything seems to be alright with code though
So in the parent component I'm doing this:
<List ref="link_list"
:list="this.foo.links" //this is array
:child="'LinkFormItem'" //this is the name of the child component
:section_name="'Links'"
:defaults="{content: '', type: 'facebook'}" />
In the List component I get this:
Template
<li class="" v-for="item in datalist">
<component :is="child" :item="item" ></component>
<button v-on:click='remove(index++)' type="button" name="button" class='red button postfix small'>Remove</button>
</li>
Script
<script>
import Child1 from './Child1'
import Child2 from './Child2'
export default {
name: 'search',
props: ['child', 'list', 'defaults','section_name'], //it is received as 'list'
components: {
Child1, Child2
},
data () {
return {
index: 0,
datalist: [] //i'm trying to copy 'list' to 'datalist'
}
},
beforeMount: function () {
// i'm copying it
for(var k in this.list){
this.datalist.push(this.list[k])
}
},
methods: {
//and here I should change it the way I want
add: function () {
this.datalist.push(this.defaults)
},
getList () {
return this.datalist;
},
remove(index){
var datalist = [];
for(var k in this.datalist){
if(k != index) datalist.push(this.datalist[k]);
}
this.datalist = datalist;
}
}
}
</script>
I don't see any problems with my Script. What is going on??
#edit
Ok, some console.log later I found out what the problem seems to be. The HTTP Request is really taking much longer than the mounting of the component to happen. But when it happens, it is not triggering the update in the list component. Nothing is re-rendered and the list is empty.
Workaround
well I realised the problem was related to propagation. I made a few changes in the code to asure the parent component was updating and changing the model value. but the child component (the list component) was not receiving it.
then I gave up trying to understand why and did the following:
1- used the ref in the child component to force an update in the child component with $forceUpdate and then I was assigning the props to the model in the beforeUpdate event. It was causing an error: an re-rendering loop. The update caused a new update and so on. We could just use a flag to stop it.
2- Instead I just called a child method directly:
this.$refs.link_list.updateList(data.links);
I hate this approach because I think it's way too explicit. But it did the job. Then in the child component a new method:
updateList(list){
this.datalist = list;
}
3- The other possibility that passed through my mind was emitting an event. But I didn't try, too complicated
You can simply do like as follows
data () {
return {
index: 0,
datalist: this.list // to copy props to internal component data
}
},
Once you done about you need to apply data manipulation opertions on new this.datalist , not on this.list
If you don't want to mutate the original list array you can do this:
data () {
return {
index: 0,
datalist: Object.assign({}, this.list)
}
}
I think this will help you