Vue.js import images - javascript

So I am making an app with a control panel and i want to be able to change a few images inside the app dynamically and my problem is, it just won't work
This is the div I am trying to change
<div class="bg-image bg-parallax overlay" :style="`background-image:url(${bg1url})`"></div>
this is the script part of the Home.vue file
<script>
import axios from 'axios';
export default {
name: 'Home', // this is the name of the component
data () {
return{
page_data: {},
bg1url: null,
};
},
created() {
axios.get("http://localhost:5001/api/v1/pages")
.then((result) => {this.page_data = result.data.page_data});
this.bg1url = require('#/assets/img/' + this.page_data.background1);
alert(page_data.background1);
},
};
</script>
I have tried most of the suggestions on stack overflow but nothing seems to work.
I use the default webpack configurations and generated structure
Note: the parts with axios fetching from the backend work correctly. The only problem is adding the image to the style.

I think could be because you are setting the value for bg1url outsite of promise (calback function of axios), and so this make the code sync and not async
so please try to update, use this instead
created() {
axios.get("http://localhost:5001/api/v1/pages").then(result => {
this.page_data = result.data.page_data
this.bg1url = require('#/assets/img/' + this.page_data.background1);
});
},

Related

Wait for data in mapstate to finish loading

I have stored a userProfile in Vuex to be able to access it in my whole project. But if I want to use it in the created() hook, the profile is not loaded yet. The object exists, but has no data stored in it. At least at the initial load of the page. If I access it later (eg by clicking on a button) everything works perfectly.
Is there a way to wait for the data to be finished loading?
Here is how userProfile is set in Vuex:
mutations: {
setUserProfile(state, val){
state.userProfile = val
}
},
actions: {
async fetchUserProfile({ commit }, user) {
// fetch user profile
const userProfile = await fb.teachersCollection.doc(user.uid).get()
// set user profile in state
commit('setUserProfile', userProfile.data())
},
}
Here is the code where I want to acess it:
<template>
<div>
<h1>Test</h1>
{{userProfile.firstname}}
{{institute}}
</div>
</template>
<script>
import {mapState} from 'vuex';
export default {
data() {
return {
institute: "",
}
},
computed: {
...mapState(['userProfile']),
},
created(){
this.getInstitute();
},
methods: {
async getInstitute() {
console.log(this.userProfile); //is here still empty at initial page load
const institueDoc = await this.userProfile.institute.get();
if (institueDoc.exists) {
this.institute = institueDoc.name;
} else {
console.log('dosnt exists')
}
}
}
}
</script>
Through logging in the console, I found out that the problem is the order in which the code is run. First, the method getInstitute is run, then the action and then the mutation.
I have tried to add a loaded parameter and played arround with await to fix this issue, but nothing has worked.
Even if you make created or mounted async, they won't delay your component from rendering. They will only delay the execution of the code placed after await.
If you don't want to render a portion (or all) of your template until userProfile has an id (or any other property your users have), simply use v-if
<template v-if="userProfile.id">
<!-- your normal html here... -->
</template>
<template v-else>
loading user profile...
</template>
To execute code when userProfile changes, you could place a watcher on one of its inner properties. In your case, this should work:
export default {
data: () => ({
institute: ''
}),
computed: {
...mapState(['userProfile']),
},
watch: {
'userProfile.institute': {
async handler(institute) {
if (institute) {
const { name } = await institute.get();
if (name) {
this.institute = name;
}
}
},
immediate: true
}
}
}
Side note: Vue 3 comes with a built-in solution for this pattern, called Suspense. Unfortunately, it's only mentioned in a few places, it's not (yet) properly documented and there's a sign on it the API is likely to change.
But it's quite awesome, as the rendering condition can be completely decoupled from parent. It can be contained in the suspensible child. The only thing the child declares is: "I'm currently loading" or "I'm done loading". When all suspensibles are ready, the template default is rendered.
Also, if the children are dynamically generated and new ones are pushed, the parent suspense switches back to fallback (loading) template until the newly added children are loaded. This is done out of the box, all you need to do is declare mounted async in children.
In short, what you were expecting from Vue 2.

Why it sends multiple request, when I call it only once?

My project were working fine. I just found out in console network that one of my GET request is sending twice, even I just send it once. See network console
If I comment the the whole code of created function, all GET request would no longer load/exist in the console network. (see code below)
I want to know what causes this, and how should I fix this?
Here is the Component.vue
<script>
export default {
created: async function() {
await this.$store.dispatch('file/all');
},
};
</script>
And the vuex module post.js's action:
const actions = {
all({commit}, data) {
return axios.get(`files`)
.then(response => {
commit('setData', response);
});
},
}
After many hours of searching, I found out that the key that is assigned to the Component caused the problem.
When the key is modified the GET request will send again. This the reason why it sends twice. Special thanks to #Anatoly for giving me the hint.
Below is the usage codes:
<template>
<Component :key="componentKey" #edit="dataIsChanged"/>
</template>
<script>
export default {
components: { Component },
data: () => ({
componentKey: 0,
}),
methods: {
dataIsChanged: function() {
this.componentKey = Math.random();
}
}
};
</script>

VUE JS Dynamic background image after axios request

I'm trying to display a background image that it's path needs to be loaded through an API.
The plan is: From a main grid of links, click one and display a background image according to the one clicked.
As of now I am using axios to query my API which sends the data I need. I have the following script part on my component.
<script>
import axios from 'axios'
const lhost = require("#/config/global").host;
let championData;
export default {
name: 'IndividualChampion',
props: {
},
data: () => ({
champions: [],
verPersonagem: mdiMovieOpen,
}),
computed: {
},
created: async function() {
try {
let champion = this.$route.fullPath.split('/')[2];
let response = await axios.get(lhost + "/champion/" + champion + '/full');
championData = response.data
console.log(championData)
let background = '#/assets' + championData['skins']['0']['splash'].replace('.png','.jpg')
}
catch (e) {
return e;
}
},
methods: {
}
}
</script>
And this is my HTML
<template>
<div :style="{ backgroundImage: `url(${require(background)})` }">
</div>
</template>
I have searched but can't seem to find a solution in which the background image is loaded and, when loaded, is presented.
Can someone help?
Judging from your use of '#/assets', you seem to be using webpack with a resolve alias. The expression require(background) is not enough for webpack to determine what files it needs to add to your bundle.
You can help Webpack by specifying the directory that you want to load your file from. All you have to do is take out '#/assets/' from the background variable and use it directly in the require call so that Webpack can see it.
<template>
<div v-if="background" :style="{ backgroundImage: `url(${require('#/assets/' + background)})` }">
</div>
</template>
<script>
import axios from 'axios'
const lhost = require("#/config/global").host;
let championData;
export default {
name: 'IndividualChampion',
props: {
},
data: () => ({
champions: [],
verPersonagem: mdiMovieOpen,
background: ''
}),
computed: {
},
created: async function() {
try {
let champion = this.$route.fullPath.split('/')[2];
let response = await axios.get(lhost + "/champion/" + champion + '/full');
championData = response.data
console.log(championData)
this.background = championData['skins']['0']['loading'].replace('.png','.jpg')
}
catch (e) {
return e;
}
},
methods: {
}
}
</script>
It will bundle every possible file inside the directory, though.
You can read more about it here: https://webpack.js.org/api/module-methods/#dynamic-expressions-in-import

nuxt.js get default head in vue.js component

I am trying to get the head object that is configured by nuxt.config.js in a vue layout. In order to show the same title in an app bar as the page title.
I know that you can alter the page title with the head function in a vue component. But is it also possible to retrieve this information somehow?
<script>
export default {
data () {
return {
title: head.titleTemplate // possible?
}
},
head () {
// here it is possible to change it but how about getting it?
}
}
</script>
Another approach could be to get some data out of an page in the nuxt.config.js. But I think this is not how the hierarchy is structured.
Thanks for you help I am just starting to use javascript to code a website :)
(If I understand you correctly) You can use the changed callback to keep track of the latest meta info used (and thus the title).
Example:
head() {
return {
changed: (info) => {
this.title = info.title;
console.log(info, info.title);
},
};
},
data() {
return {
title: '',
};
},
In nuxt.config.js before export I have setted variable with a string of the title.
Then added it to the head section and create a new env section:
https://nuxtjs.org/api/configuration-env/
const title = `Site title`
export default {
head: {
title
},
env: {
title
}
}
This how I'm getting the title in any Vue component:
export default {
computed: {
title () {
return process.env.title
}
},
}
This helps you to keep your original title in process.env.title, even if you will want to change head.title dynamically.
Did anyone found a better solution maybe? :)

Vue.js - Global Data from AJAX Call

I'm giving Vue.js a try and so far I'm loving it because it's much simpler than angular. I'm currently using vue-router and vue-resource in my single page app, which connects to an API on the back end. I think I've got things mostly working with a the primary app.js, which loads vue-router and vue-resource, and several separate components for each route.
Here's my question: How do I use props to pass global data to the child components when the data is fetched using an asynchronous AJAX call? For example, the list of users can be used in just about any child component, so I would like the primary app.js to fetch the list of users and then allow each child component to have access to that list of users. The reason I would like to have the app.js fetch the list of users is so I only have to make one AJAX call for the entire app. Is there something else I should be considering?
When I use the props in the child components right now, I only get the empty array that the users variable was initialized as, not the data that gets fetched after the AJAX call. Here is some sample code:
Simplified App.js
var Vue = require('vue');
var VueRouter = require('vue-router')
Vue.use(VueRouter);
var router = new VueRouter({
// Options
});
router.map({
'*': {
component: {
template: '<p>Not found!</p>'
}
},
'/' : require('./components/dashboard.js'),
});
Vue.use(require('vue-resource'));
var App = Vue.extend({
ready: function() {
this.fetchUsers();
},
data: function() {
return {
users: [],
};
},
methods: {
fetchUsers: function() {
this.$http.get('/api/v1/users/list', function(data, status, response) {
this.users = data;
}).error(function (data, status, request) {
// handle error
});
}
}
});
router.start(App, '#app')
Simplified app.html
<div id="app" v-cloak>
<router-view users = "{{ users }}">
</router-view>
</div>
Simplified dashboard.js
module.exports = {
component: {
ready: function() {
console.log(this.users);
},
props: ['users'],
},
};
When dashboard.js gets run, it prints an empty array to the console because that's what app.js initializes the users variable as. How can I allow dashboard.js to have access to the users variable from app.js? Thanks in advance for your help!
p.s. I don't want to use the inherit: true option because I don't want ALL the app.js variables to be made available in the child components.
I believe this is actually working and you are being misled by the asynchronous behavior of $http. Because your $http call does not complete immediately, your console.log is executing before the $http call is complete.
Try putting a watch on the component against users and put a console.log in that handler.
Like this:
module.exports = {
component: {
ready: function() {
console.log(this.users);
},
props: ['users'],
watch: {
users: {
handler: function (newValue, oldValue) {
console.log("users is now", this.users);
},
deep: true
}
}
}
};
In the new version of Vue 1.0.0+ you can simply do the following, users inside your component is automatically updated:
<div id="app" v-cloak>
<router-view :users="users"></router-view>
</div>

Categories

Resources