I'm trying to send file from vue-page to server. For this I use:
FileFrom component:
<template>
<div class="FileForm" v-bind:name="name">
<label class="FileFormLabel">
{{ name }}:
<input type="file" files="files" v-on:change="fileUpload" v-bind:name="name"/>
</label>
<button class="SubmitBtn" v-on:click="submit">
Submit
</button>
</div>
</template>
<script>
export default {
name: 'FileForm',
props: ["value", "name"],
data: function() {
return {
files: [],
}
},
methods: {
fileUpload: function(event) {
this.$emit("upload", [event.target.files[0]])
},
submit: function() {
this.files = []
this.$emit("submit")
},
},
}
</script>
Page:
<template>
<Container>
<div class="content">
<h1>
Upload files
</h1>
<div class="forms">
<FileForm v-bind:files="files['Model']" name="Model" v-on:upload="upload_model" v-on:submit="submit_model">
</FileForm>
</div>
</div>
</Container>
</template>
<script>
import axios from 'axios'
import Container from '#/components/Container.vue'
import FileForm from '#/components/FileForm.vue'
export default {
name: 'App',
data: function() {
return {
files: {},
}
},
components: {
Container,
FileForm
},
methods: {
upload_model: function(file) {
this.files['Model'] = file
},
submit_model: function() {
let formData = new FormData();
formData.append('Model', this.files['Model']);
axios.post('http://' + document.location.host + '/api/upload_model', formData, {
headers: {
'Content-Type': 'multipart/form-data'
},
})
}
},
}
</script>
But sending request looks like this:
-----------------------------316537648527426258472746653245
Content-Disposition: form-data; name="Model"
[object File]
-----------------------------316537648527426258472746653245--
A file is not sent as file but as string "[object File]".
As far as I understand the problem is that FormData.append converts all non-Blob(or File) objects to string and this.files['Model'] is not this one. It is proxy object which Vue.js uses for reactivity.
How can I take the internal object from this proxy and use it for sending?
I changed
formData.append('Model', this.files['Model']);
to
formData.append('Model', this.files['Model'][0]);
in page code.
And now it works fine. I don't know, is it the way to get needed value from proxy or I just returned array of files instead of single file somewhere in my code, but it helped.
I am trying to set some objects in a Bootstrap-Vue form select which I get via JSON.
The JSON is made up of teacher objects from the following fields:
[
{
"id": 1,
"name": "John",
"surname": "Doe",
"email": "john.doe#gmail.com"
}
]
What I'm trying to do is put the name and surname in the select list, that is the full name.
I have already managed to do this via a computed property by processing the list.
But now I want that when I select a teacher, the list of courses is filtered according to the chosen teacher.
To do this I need the teacher's email, which I can't recover, having processed the teachers to get the full name.
Consequently, I can't even update the list of courses based on the teacher chosen.
This is the code for the template:
<b-form-group
id="input-group-3"
label="Docente:"
label-for="input-3"
>
<b-form-select
v-model="teacher"
:options="teachers"
value-field="item"
text-field="fullName"
required
#change="filterCourse"
></b-form-select>
<div class="mt-3">
Selected: <strong>{{ teacher }}</strong>
</div>
</b-form-group>
This is the script code:
import { mapGetters, mapActions } from "vuex";
export default {
data() {
return {
teacher: "",
course: "",
};
},
created: function() {
this.GetActiveTeachers();
this.GetActiveCourses();
},
computed: {
...mapGetters({
ActiveTeacherList: "StateActiveTeachers",
ActiveCourseList: "StateActiveCourses",
FilteredTeacherList: "StateTeacherByCourse",
FilteredCourseList: "StateCourseByTeacher",
}),
teachers: function() {
let list = [];
this.ActiveTeacherList.forEach((element) => {
let teacher = element.name + " " + element.surname;
list.push(teacher);
});
return list;
},
},
methods: {
...mapActions([
"GetActiveTeachers",
"GetActiveCourses",
"GetCourseByTeacher",
"GetTeacherByCourse",
"AssignTeaching",
]),
async filterCourse() {
const Teacher = {
teacherEmail: "john.doe#gmail.com", // For testing purpose
};
try {
await this.GetCourseByTeacher(Teacher);
} catch {
console.log("ERROR");
}
},
async filterTeacher() {
const Course = {
title: "Programming", // For testing purpose
};
try {
await this.GetTeacherByCourse(Course);
} catch {
console.log("ERROR");
}
},
},
};
You're currently using the simplest notation that Bootstrap Vue offers for form selects, an array of strings.
I suggest you switch to use their object notation, which will allow you to specify the text (what you show in the list) separately from the value (what's sent to the select's v-model).
This way, you'll be able to access all the data of the teacher object that you need, while still being able to display only the data you'd like.
We can do this by swapping the forEach() in your teachers computed property for map():
teachers() {
return this.ActiveTeacherList.map((teacher) => ({
text: teacher.name + " " + teacher.surname,
value: teacher
}));
},
Then, all you need to do is update your filterCourse() handler to use the new syntax, eg.:
async filterCourse() {
const Teacher = {
teacherEmail: this.teacher.email,
};
try {
await this.GetCourseByTeacher(Teacher);
} catch {
console.log("ERROR");
}
},
As a final note, if you don't want or need the full object as the value, then you can mold it to be whatever you need, that's the beauty of this syntax.
For example, you want the full name and email, instead of the parts:
value: {
fullName: teacher.name + " " + teacher.surname,
email: teacher.email
}
Here's two different options you can do.
One would be to generate the <option>'s inside the select yourself, using a v-for looping over your teachers, and binding the email property to the value, and displaying the name and surname inside the option.
This will make your <b-select>'s v-model return the chosen teachers e-mail, which you can then use in your filter.
new Vue({
el: '#app',
data() {
return {
selectedTeacher: null,
activeTeachers: [{
"id": 1,
"name": "Dickerson",
"surname": "Macdonald",
"email": "dickerson.macdonald#example.com"
},
{
"id": 2,
"name": "Larsen",
"surname": "Shaw",
"email": "larsen.shaw#example.com"
},
{
"id": 3,
"name": "Geneva",
"surname": "Wilson",
"email": "geneva.wilson#example.com"
}
]
}
}
})
<link href="https://unpkg.com/bootstrap#4.5.3/dist/css/bootstrap.min.css" rel="stylesheet" />
<link href="https://unpkg.com/bootstrap-vue#2.21.2/dist/bootstrap-vue.css" rel="stylesheet" />
<script src="https://unpkg.com/vue#2.6.12/dist/vue.min.js"></script>
<script src="https://unpkg.com/bootstrap-vue#2.21.2/dist/bootstrap-vue.js"></script>
<div id="app">
<b-select v-model="selectedTeacher">
<option v-for="teacher in activeTeachers" :value="teacher.email">
{{ teacher.name }} {{ teacher.surname }}
</option>
</b-select>
{{ selectedTeacher }}
</div>
The other option would be to change your computed to return an array of objects instead of simple strings as you're currently doing.
By default <b-select> expects the properties value and text if you use an array of objects in the options prop.
Here you would bind the email for each teacher to the value, and the name and surname to the text prop.
This will make your <b-select>'s v-model return the chosen teachers e-mail, which you can then use in your filter.
Reference: https://bootstrap-vue.org/docs/components/form-select#options-property
new Vue({
el: '#app',
data() {
return {
selectedTeacher: null,
activeTeachers: [{
"id": 1,
"name": "Dickerson",
"surname": "Macdonald",
"email": "dickerson.macdonald#example.com"
},
{
"id": 2,
"name": "Larsen",
"surname": "Shaw",
"email": "larsen.shaw#example.com"
},
{
"id": 3,
"name": "Geneva",
"surname": "Wilson",
"email": "geneva.wilson#example.com"
}
]
}
},
computed: {
teacherOptions() {
return this.activeTeachers.map(teacher => ({
value: teacher.email,
text: `${teacher.name} ${teacher.surname}`
}));
}
}
})
<link href="https://unpkg.com/bootstrap#4.5.3/dist/css/bootstrap.min.css" rel="stylesheet" />
<link href="https://unpkg.com/bootstrap-vue#2.21.2/dist/bootstrap-vue.css" rel="stylesheet" />
<script src="https://unpkg.com/vue#2.6.12/dist/vue.min.js"></script>
<script src="https://unpkg.com/bootstrap-vue#2.21.2/dist/bootstrap-vue.js"></script>
<div id="app">
<b-select v-model="selectedTeacher" :options="teacherOptions"></b-select>
{{ selectedTeacher }}
</div>
I am creating a time application using the Openweather API. I try to show the meteorological icon corresponding to the selected city and the meteorological state.
My code is as follows:
HTML:
<div class="column">
<div class="media-content">
<div class="content">
<p>
<strong>
<h1 class="has-text-inf o"> {{ ciutatActual.weather[0].icon }} </h1>
</strong>
</p>
</div>
</div>
</div>
javascript:
var vm = new Vue({
el: '#eltemps',
data: {
selectedCity: "",
ciutatActual: null,
ciutats: [
"Barcelona",
"Lleida",
"Zaragoza",
"Sevilla",
"Madrid",
"Paris",
"Melbourne",
"Moscow",
"Pekin",
"Marrakech"]
},
created: function () {
this.selectedCity = this.ciutats[0]
},
watch: {
selectedCity: function (){
this.getWeather(this.selectedCity)
}
},
methods: {
getWeather(city) {
const url = 'https://api.openweathermap.org/data/2.5/weather?q=' + city + '&units=metric&lang=ca&appid=8660dddfbe5f16ee37dbd6883d8f07d5';
fetch(url)
.then(function (response) {
return response.json()
})
.then(function (item) {
vm.ciutatActual = item;
})
.catch(function(error) {
console.log(error);
})
},
itemClicked: function(item) {
this.getWeather();
this.onClick(item);
}
}
})
The ruling comes from here: {{ciutatactual.weather [0] .icon}}
that instead of showing the icon it shows me just one code
My problem is with this json.
http://dev-rexolution.pantheonsite.io/api/noticias
I need to consume with vuejs 2 only the first element of the array to be able to display it, working with the console I worked but with no vuejs.
This console log work: console.log(response.data[0].title[0].value);
<template>
<div class="Box Box--destacado1">
<div class="Media Media--rev">
<div class="Media-image">
</div>
<div class="Media-body">
<span class="Box-info">{{ noticias[0].field_fecha[0].value}}</span>
<h3 class="Box-title">
{{ /*noticias[0].title[0].value */}}
</h3>
<p class="Box-text">{{/*noticias[0].field_resumen[0].value*/}}</p>
</div>
</div>
</template>
<script>
import axios from 'axios';
export default {
data: () => ({
noticias: [],
errors: []
}),
// Fetches posts when the component is created.
created() {
axios.get(`http://dev-rexolution.pantheonsite.io/api/noticias`)
.then(response => {
// JSON responses are automatically parsed.
this.noticias = response.data
})
.catch(e => {
this.errors.push(e)
})
}
}
</script>
You're probably running into an issue where your template is attempting to show data that doesn't exist until the AJAX request has completed.
I would set a flag to indicate when the data is available and toggle the display using v-if. For example
Template
<div class="Media-body" v-if="loaded">
Script
data () {
loaded: false,
noticias: [],
errors: []
}
and in your created hook
.then(response => {
this.loaded = true
this.noticias = response.data
})
Alternatively, set up your initial noticias array with some dummy data
noticias: [{
title: [{ value: null }]
field_fecha: [{ value: null }]
field_resumen: [{ value: null }]
}]
I am using vue.js 2 with webpack template. i am new to vue.js.
i want to bind DOM after data is received in ajax call.
here in my code contains v-for in which the response html is need to bind with v-html="tHtml[index]" every time after data is received from api call.
What can be used to re-bind or refresh view/DOM as we use $scope.$apply() in angularjs.
home.vue
<template>
<div class="row" id="home">
<h3 v-if="msg"><span class="label label-warning">{{msg}}</span></h3>
</div>
<div v-for="obj in tdata">
<div v-html="tHtml[$index]"></div>
</div>
</div>
</template>
<script>
import appService from '../service'
import bus from '../service/bus'
export default {
created() {
appService.checkAuth();
console.log("service appService val: "+appService.user.authenticated);
//called after vue has been created
bus.$on('eventBusWithTopic', (data) => { //fetch event bus on ready to get data
//alert("event fetched! "+data.user_id);
console.log("event fetched! "+data.user_id);
this.searchedTopic = data.topic;
this.user_id = data.user_id;
bus.$off('eventBusWithTopic'); //un-bind event after use
//check details
})
},
data() {
return {
searchedTopic: '',
user_id: '',
tdata: {},
tHtml: []
}
},
methods: {
getdata(){
console.log("dfd "+this.user_id);
appService.getdata(this, this.user_id, this.searchedTopic).success((res) => {
//console.log(" res: "+JSON.stringify(res));
this.tdata = res.data;
if(this.tdata.length > 0){
//**GET HTML** // <<--==--==--==
for(var i=0;i<this.tdata.length;i++){
this.getTemplate(this.tdata[i].id_str);
}
}
if(res.success == 0)
this.msg = res.message;
}).error((e) => console.log("error while getting data: "+JSON.stringify(e)))
},
getTemplate(id){
this.$http.get("https://uqkcgyy8wb.execute-api..*****../user/"+id+"/getHtml", (resp) => {
//return resp.data.html;
this.tHtml[this.tHtml.length] = resp.data.html;
console.log(this.tHtml);
}).error((e) => console.log("error while getting html: "+JSON.stringify(e)))
}
}
}
</script>