submit the data both from parent and child component - laravel

I am using Laravel 5.7 with vue.js and mysql
When I hit the submit button in parent component, Is there any way to submit the selected file from child component (Images) also?
Parent Component - This component has one textbox, a button to save and declared a component to render the html for selecting the image.
<template>
<div>
<label class="control-label">Name</label>
<input name="Name" type="text" v-model="saveForm.Name">
<images></images> //Child Component declaration
<button type="button" #click="store()">
Save
</button>
</div>
</template>
<script>
export default {
data() {
return {
saveForm: {
Name: ''
}
};
},
methods: {
store() {
axios.post("my route", this.saveForm).then(response => {
if(response.data.Status) {}
});
}
}
}
</script>
Image component(child component), Actually, this component has many images around 58.
<template>
<div>
<input type="file" id="Image">
</div>
</template>
<script>
export default {
data() {
},
methods: {
}
}
</script>

You can use $refs to access the files from the parent component:
https://v2.vuejs.org/v2/guide/components-edge-cases.html#Accessing-Child-Component-Instances-amp-Child-Elements
And a FormData object to upload the files through ajax:
https://blog.teamtreehouse.com/uploading-files-ajax
Parent component:
<template>
...
<!-- Declare a 'ref' attribute on the child component -->
<images ref="imageComponent"></images>
...
</template>
<script>
export default {
data() {
return {
saveForm: {
Name: ''
}
};
},
methods: {
store() {
// get the child attribute's files through the $refs properties
let files = this.$refs.imageComponent.$refs.fileInput.files;
// Create a new FormData object.
let formData = new FormData();
// Loop through each of the selected files.
for (let i = 0; i < files.length; i++) {
let file = files[i];
// Check the file type.
if (!file.type.match('image.*')) {
continue;
}
// Add the file to the request.
formData.append('files[]', file, file.name);
}
// Add the Name
formData.append('Name', this.saveForm.Name);
// Ajax request
axios.post("my route", formData).then(response => {
if(response.data.Status) {}
});
}
}
}
</script>
Child component:
<template>
...
<!-- Declare a 'ref' attribute on the file input -->
<input ref="fileInput" type="file" id="Image">
...
</template>
<script>
export default {
data() {
},
methods: {
}
}
</script>

Related

Vuejs Sibling Component data passing with method

I have a Vuejs Laravel page with Parent and 2 child
In my Parent template I have
<template>
<div>
<h4>DATA ANALYSIS</h4>
<dataAnalysisGraph />
<br>
<hr>
<dataAnalysisTable />
</div>
and in my dataAnalysisGraph child component i have a method that send request everytime the dropdown changes.
//dataAnalysisGraph
<template>
<div>
<div>
<select class="form-control select" name="" #change="GenerateChart" v-model='chartType' >
<option value="1">One</option>
<option value="2">Two</option>
<option value="3">Three</option>
</select>
</div>
<br><br><br>
<highcharts class="hc" :options="chartOptions" ref="chart"></highcharts>
</div>
</template>
<script>
export default {
data() {
return {
data: [],
}
},
methods: {
GenerateChart(){
this.axios
.get('api/'+this.chartType)
.then(response => {
this.data = response.data;
});
},
},
created() {
this.GenerateChart();
},
};
</script>
In my dataAnalysisTable child component. I want to get the this.data from dataAnalysisGraph component and pass it to the dataAnalysisTable and updates it every time the dropdown form dataAnalysisGraph component changes.
this is my dataAnalysisTable component currently
<template>
<div>
{{data}}
</div>
</template>
<script>
export default {
data() {
return {
data: [],
};
},
methods: {
},
created() {
},
};
</script>
You can emit an event inside dataAnalysisGraph returning this.data to the parent and connect this value using v-model to the dataAnalysisTable component. You can read more in the vuejs guide specifically in the "Usage with v-model" section.

Image file path in data property not showing until I open up the component in vue chrome dev tools

I'm trying to build an image preview system for an avatar:
<template>
<div>
<div class="level">
<img :src="avatar" width="50" height="50" class="mr-1">
</div>
<form method="POST" enctype="multipart/form-data">
<input type="file" accept="image/*" #change="onChange">
</form>
</div>
</template>
<script>
import axios from 'axios'
export default {
data() {
return {
avatar: null,
setAuthHeader: axios.defaults.headers.common['Authorization'] = 'Bearer ' + this.$store.state.token,
};
},
computed: {
user() {
return this.$store.state.user
},
avatar_path() {
this.avatar = this.user.avatar_path
},
},
methods: {
onChange(e) {
if (! e.target.files.length) return;
let file = e.target.files[0];
let reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = e => {
this.avatar = e.target.result;
this.persist(file);
};
},
persist(avatar) {
let data = new FormData();
data.append('avatar', avatar);
this.setAuthHeader;
axios.post(`/settings/avatar`, data)
.then(() => flash('Avatar uploaded!'));
}
}
}
</script>
In my code the user computed property returns a JSON object from vuex which gets the object from local stroage.
What keeps happening is when I refresh the page that changes the profile image the default image doesn't show up. The element looks like this in chrome devtools:
<img width="50" height="50" class="mr-1">
When I open up vue dev tools, click on the component this functionality is in, the image src gets added:
<img width="50" height="50" class="mr-1" src="http://127.0.0.1:8000/storage/avatars/default.png">
You're using the avatar_path computed property incorrectly:
You shouldn't be modifying state in a computed property (you're assigning to this.avatar).
Nothing is accessing avatar_path for it to be called. It's when you open Vue dev tools that the dev tools code accesses that property so it can display it in the component data UI.
The best fix is to change avatar into a computed property like this:
computed: {
avatar() {
if (this.user) {
return this.user.avatar_path;
} else {
// Use a placeholder image URL
return '/path/to/placeholder.png';
}
}
}
<template>
<div>
<div class="level">
<img :src="avatar" width="50" height="50" class="mr-1">
</div>
<form method="POST" enctype="multipart/form-data">
<input type="file" accept="image/*" #change="onChange">
</form>
</div>
<script>
import axios from 'axios'
export default {
data() {
return {
setAuthHeader: axios.defaults.headers.common['Authorization'] = 'Bearer ' + this.$store.state.token,
};
},
computed: {
user() {
return this.$store.state.user
},
avatar() {
return this.user.avatar_path;
},
},
methods: {
}
}

How to transfer data between components placed in different views

I have two compoennts placed in one the same view.
#extends('layouts.app')
#section('content')
<bus></bus>
<bus2></bus2>
#endsection
I want to pass data (name) from one component to other one after clicking button. To do that I' using $emit function.
/// bus component
<template>
<div>
<p> Name Bus 1{{name}}</p>
<input type="button" #click="setName()" value="s"/>
</div>
</template>
<script>
export default {
created() {},
data: function() {
return {
name: "Volvo"
};
},
methods: {
setName: function(id) {
this.$root.$emit("sname", this.name);
}
},
props: []
};
</script>
///bus 2 component
<template>
<div>
<p> Name bus 2{{name}}</p>
</div>
</template>
<script>
export default {
created() {
this.$root.$on("sname", data => {
this.name = data;
});
},
data: function() {
return {
count: 0,
name: ""
};
},
methods: {}
};
</script>
Everything works fine. Name is transfered from bus to bus2. The problem exists when I place bus2 in different view - data are not transfered but code is the same. How can I transfer data between components placed in different views
Try using Vuex to specify your app state, and mutate this when it's necessary.
Vuex states are accessible from every components using this.$store or $store.

Parsing dynamically loaded directives in Vue

I have a Vue component that makes a post request, and then outputs the returned html.
Sometimes, the html that is returned by the post contains Vue directives.
Is there a way to have Vue parse the returned html before it is output?
(In the longer term, I will rewrite this as a pure Vue solution, with the post request returning data rather than html. I'm after a short term solution if its possible).
EDIT:
Here's my stab based on thanksd's suggestion but I'm not sure how to bind the new Vue instance to an html element.
<template>
<div>
<input type="text" class="form-control" v-model="value" #change="getResults" ></input>
<div>
<template v-bind="results"></template>
</div>
</div>
</template>
<script>
import{eventHub} from '../utils/event.js'
export default {
data : function(){
return {
value : '',
results : {}
}
},
methods:{
getResults(){
if(this.value.length < 3){return;}
this.$http.post('/ajax/search',{search:this.value}).then((response)=>{
this.results = Vue({template:response.body});
});
},
},
}
After the post request returns you could create a new Vue instance, passing the html as the template and binding it to an element in your current Vue instance's template:
<template>
<div>
<input type="text" class="form-control" v-model="value" #change="getResults" ></input>
<div>
<div id="results"></div>
</div>
</div>
</template>
<script>
export default {
data() {
return { value: '' }
},
methods: {
getResults() {
if (this.value.length < 3) {
return;
}
this.$http.post('/ajax/search', { search: this.value }).then((response) => {
new Vue({ el: '#results', template: response.body });
});
}
}
}
</script>
Or as #Bert pointed out, you could add a <component> tag to your template and pass its definition via the is prop:
<template>
<div>
<input type="text" class="form-control" v-model="value" #change="getResults" ></input>
<component :is="results"/>
</div>
</template>
<script>
export default {
data() {
return {
value: '',
results: null
}
},
methods: {
getResults() {
if (this.value.length < 3) {
return;
}
this.$http.post('/ajax/search', { search: this.value }).then((response) => {
this.results = { template: response.body };
});
}
}
}
</script>

How to dataset after ajax communication with vuejs

I'm trying to implement modal windows with Vuejs.
The code below shows that after the user uploads the favorite photo,
then modal window appears, and photos which were uploaded so far and the newly registered photos are displayed
it will confirm when the user press the "confirm" button.
However, at present, data is not set in the modal window after fetching data with ajax after uploading.
How do I set the data in the modal window part?
<template>
<div>
<!-- upload -->
<div class="button__action">
<button type="button" #click="uploadData(originalData.image)">upload</button>
</div>
<!-- Modal window -->
<modal name="modal-view">
<div>
<div class="modal__box" v-if="modalList.list">
<img :src="modalList.list.url">
<p class="image__name">{{modalList.list.name}}</p>
</div>
<button type="button" #click="submit">Confirm</button>
</div>
</modal>
</div>
</template>
<script>
import { post } from './handler/api'
import { toFormat } from './handler/form'
export default {
props: {
originalData: {
type: Object,
required: true,
}
},
data: function(){
return {
modalList : {
list : [],
},
}
},
methods: {
showModal () {
this.$modal.show('modal-view');
},
uploadData() {
const form = toFormat({image: this.originalData.image})
post(`/api/upload/`, form)
.then((res) => {
if(res.data) {
Vue.set(this.$data, 'modalList', res.data.list);
this.$modal.show('modal-view');
}
})
.catch((err) => {
//error
})
},
submit() {
}
}
}
</script>
Try this:
uploadData() {
var vm = this;
post(`/api/upload/`, toFormat({image: this.originalData.image})).then(res => {
if(res.data) {
vm.modalList = res.data.list;
this.$modal.show('modal-view');
}
})
}

Resources