I'm rather new to VueJS, and I would like to add a picture loaded from an API as a background image. However, the image loading eventually works.
Here is the code:
<template>
<div id="bio" :style="{ backgroundImage: 'url(' + this.settings.bio_bg.url +')' }">
<h1>Biography</h1>
<router-link to="/">Home</router-link><br />
<span>Biography</span><br />
<router-link to="/shop">Shop</router-link><br />
<router-link to="/contact">Contact</router-link><br />
</div>
</template>
<style scoped>
</style>
<script>
export default {
data () {
return {
settings: {},
bio: {}
}
},
created () {
.catch(error => this.setError(error))
this.$http.secured.get('/settings')
.then(response => {
this.settings = response.data
console.log(this.settings)
})
.catch(error => this.setError(error))
}
}
</script>
The image is loaded, but my console returns two errors:
Error in render: "TypeError: Cannot read property 'url' of undefined"
Cannot read property 'url' of undefined
I guess that since the Axios call is asynchronous, everything arrives after the page is done loading, but is still loaded after.
What would the proper way be to correctly wait for data to be available? I tried a few things that I know from React, but it doesn't load at all (even though the errors stop showing up)
Thank you in advance
Yo need to be sure that this.settings.bio_bg.url exist from the component birth, so compiler doesn't broke trying to render it. In order to do so, just setup a 'fake' url in the original data of the component:
export default {
data () {
return {
settings: {
bio_bg: {
url: '',
}
},
bio: {}
}
},
created () {
this.$http.secured.get('/settings')
.then(response => {
this.settings = response.data
console.log(this.settings)
})
.catch(error => this.setError(error))
}
}
This not only prevent errors, also provides better intellisense since now your code editor can now that settings has a bio_bg member which in turn has an url.
If instead of ' ', you provide a real image url with a placeholder img, probably the UI will be nicer:
data () {
return {
settings: {
bio_bg: {
url: 'http://via.placeholder.com/350x150',
}
},
bio: {}
}
}
Related
I'm new to Vue js and I'm trying to understand the logic of the usage of nextTick in a method. So I have two components like this:
IsTuruIslem.vue
<template>
...
<t-row>
<is-turu-islem-goruntule ref="isTuruIslemGoruntule"
#kaydet="kaydet"
#guncelle="guncelle">
</is-turu-islem-goruntule>
</t-row>
...
</template>
<script>
...
isTuruIslemPopupAc(detay) {
if (!detay) this.$refs.isTuruIslemGoruntule.open();
else {
let guncellenecekDetay = JSON.parse(JSON.stringify(detay));
console.log("Popup:", guncellenecekDetay);
this.$refs.isTuruIslemGoruntule.open({
isUpdate: true,
detay: guncellenecekDetay
});
}
}
...
</script>
IsTuruIslemGoruntule.vue
<template>
...
<t-row>
<t-col :span="20">
<t-select
id="sirket"
ref="sirket"
label="Şirket *"
v-model="detay.sirket"
item-value="id"
item-text="aciklama"
/>
</t-col>
</t-row>
<t-row>
<t-col :span="20">
<t-select
id="cmb_durum"
ref="durum"
label="Durum"
itemText="text"
itemValue="id"
v-model="detay.durumBaseDTO"
:readonly="false"
:clearable="true"
:disabled="false"
/>
</t-col>
....
</template>
<script>
...
methods: {
open: function(options) {
this.isOpen = true;
if (options) {
this.isUpdate = true;
this.detay = JSON.parse(JSON.stringify(options.detay));
} else {
this.detay = {};
}
//this.$nextTick(() => {
this.$refs.durum
.get("/ytts/api/common/durumlar/aktifPasif", null)
.then(data => {})
.catch(err => null);
this.$refs.islem
.get("/ytts/api/tanimYonetimi/isTuruIslem/sorgula/islemListesi")
.then(data => {})
.catch(err => null);
this.$refs.sirket
.get("/ytts/api/tanimYonetimi/isTuruIslem/sorgula/sirketListesi")
.then(data => {})
.catch(err => null);
//});
//console.log("DETAY:", this.detay);
},
...
</script>
My question is code as in this example doesn't work properly and I get "Cannot read property 'get' of undefined" at the line where this.$refs.durum exists. But when I uncomment the nextTick method which resides at the top of this.$refs.durum, it magically works. I really don't get the idea of this usage. Can someone clearly explain it to me? Thank you for your attention.
If the <t-select ref="durum"> component is not created (by using v-if, for example) then this.$refs.durum won't exist.
Let's say you use something like v-if="show" with show set to false to control the creation of that component. If, in your method, you set show to true, then the component won't be created as soon as you do so, you have to wait until Vue has updated the DOM (this is a performance thing). For this, you need to use $nextTick to wait until that time, only then will the component be created and this.$refs.durum will exist.
You haven't provided all of your code, so I can't say for sure, but it looks like maybe isOpen is controlling the visibility of that component.
im really going through hard times trying to figure out how to get my API data through Vuex, is there some body whom has accurate bibliography of how to do this step by step, or even better help me with this code?
Formerly without using Vuex , but Vue all request worked perfectly, but now i dont understand clearly what i should do, here sharing part of my code:
data() {
return {
testArray: []
};
methods: {
getJsonData() {
fetch(
"https://app.ticketmaster.com/discovery/v2/events.json?countryCode=" +
this.countriesDrop +
"&apikey=xxxxxxxxxxxxxxxxxxxxxxxx",
{
method: "GET"
}
)
.then(response => {
return response.json();
})
.then(test => {console.log(this.testArray)
this.testArray = test._embedded.events;
})
.catch(err => {
console.log(err);
});
},
watch: {
countriesDrop: function(val) {
this.getJsonData();
}
},
As you can see in the request also is included an external element which make it changes attuning with the watcher and the value the user might asign.
I already got set Vuex and all else pluggins...just dont know how to act like , thus would appreciate an accurate link or tutorial either help with this basic problem resolved on detail step by step, .....thanks!
In your code there's nothing with Vuex. I guessed you want to set the state so that the getJsonData() method is called according to what's in the store.
Here's a snippet as an example of handling async in a Vuex environment.
const store = new Vuex.Store({
state: {
testArray: []
},
mutations: {
setTestArray(state, data) {
state.testArray = data
}
},
actions: {
getJsonData({
commit
}, countriesDrop) {
if (countriesDrop && countriesDrop !== '') {
fetch(`https://jsonplaceholder.typicode.com/${countriesDrop}`, {
method: "GET"
})
.then(response => {
return response.json();
})
.then(json => {
commit('setTestArray', json)
})
.catch(err => {
console.log(err);
});
}
}
}
})
new Vue({
el: "#app",
store,
computed: {
getDataFromStore() {
return this.$store.state.testArray
}
},
methods: {
getData(countriesDrop) {
this.$store.dispatch('getJsonData', countriesDrop)
}
}
})
<script src="https://cdn.jsdelivr.net/npm/es6-promise#4/dist/es6-promise.auto.js"></script>
<script src="https://unpkg.com/vuex#3.1.2/dist/vuex.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<button #click="getData('todos')">GET TODOS</button>
<button #click="getData('albums')">GET ALBUMS</button>
<ol>
<li v-for="data in getDataFromStore">{{data.title}}</li>
</ol>
</div>
The point is that Vuex is a central element in a Vue-Vuex application. You can store app state, handle async and sync functions (actions, mutations) with it, and all your Vue components can rely on the state - that should be the "single source of truth".
So, you get your input from a component (the Vue instance in this snippet), and dispatch an action that is available in the Vuex store. If the action needs to modify the state, then you call a mutation to do that. With this flow you keep reactivity for all your components that use that state.
I used a computed to get data from the Vuex store, but getters can be set also.
This way you don't "pollute" your components with functions and data that should be in the store.
I have a wrapper component which provides the children with API calls and stores the result, and a list component which shows the requested items passed via prop. The problem is that it shows them in development mode but doesn't in production though API call is ok in both cases and the response is correct.
Both modes I ran in the same environment. Looks like a reactivity issue.
This is a template code:
<vue-api>
<vue-list-filter-synchronizer slot-scope="{ result, getPrograms }"
...
#params-updated="getPrograms">
...
<div class="content">
<vue-list :items="result ? result.data : []"
.../>
</div>
</vue-list-filter-synchronizer>
</vue-api>
VueAPI component:
const VueAPI = {
data() {
return {
result: null,
error: null,
loading: false
}
},
...
methods: {
getPrograms(params) {
this.query(services.getPrograms)([params]);
},
query(f) {
return (args=[]) => {
if (!this.loading) {
this.loading = true;
f(...args)
.then(({ data }) => this.result = data)
.catch(error => this.error = error)
.finally(() => this.loading = false);
}
}
},
render() {
return this.$scopedSlots.default(this.slotScope);
}
}
I expect that result.data in VueAPI component will be shown as the list items in development and in production modes but it's so only in development mode.
First of all, my vue.debug.js had an old version so that it works with it and doesn't without. When I updated it the problem appears in debug mode too.
Secondly, the problem is that I used a deprecated syntax for slot-scope. When I changed it to v-slot syntax everything starts to work as expected.
Vue.js version is: 2.x
Hi. I'm sending an ajax request in vue js to another page and getting it's source which contains vue.js syntax such as events. When this source is added to property and property added to a template, the ajax data source (that contains vue.js syntax) can not be rendered and does not work properly.
For example template is:
<div id="app">
{{{ foo }}}
</div>
and app.js is:
var app = new Vue({
el: '#app',
data: {
foo: 'bar'
},
mounted(){
this.$http.get('/media').then(function(response){
data = response.body;
Vue.set(app, 'foo', data);
});
},
methods: {
alertVideoLink: function(event){
alert(event.target.href);
}
}
});
In the above app.js code, ajax request returns this code (that is response.body):
Video Link
but this link can't be rendered and does not work properly! I'm testing the render method and some useful hints, but no way found. Please help... Thanks
Sounds like you want to use an Async Component.
Something like...
components: {
'async-media': () => Vue.http.get('/media').then(res => ({
template: res.body,
methods: {
alertVideoLink (event) {
this.$emit('click', event)
}
}
}))
}
Then in your template...
<async-media #click="handleClickEventFromChildComponent" />
Here's an example using a timeout to fake "load" a template
var app = new Vue({
el: '#app',
data: {},
components: {
'async-media': () => new Promise(resolve => {
setTimeout(() => {
resolve({
template: 'Video Link',
methods: {
alertVideoLink(event) {
this.$emit('click', event.target.href)
}
}
})
}, 2000)
})
},
methods: {
handleClickEventFromChildComponent (href) {
console.info('Clicked on', href)
}
}
});
<div id="app">
<p>Wait 2 seconds</p>
<async-media #click="handleClickEventFromChildComponent" />
</div>
<script src="https://unpkg.com/vue#2.4.2/dist/vue.min.js"></script>
#Phil's answer is correct but in my project need to be changed. in this case, the better way is: using global components vs local components because is simple for this work.
I am trying to create a web app based on a database. Setup: NodeJS and a Vuejs 2 app generated with the CLI (with Webpack). Currently, I am using axios to retrieve records into an object. Based on that object I want to draw some svg lines from certain points to other points. The method works completely as designed when running it from an #click (v-on directive). However, when I try to add it to the created hook it doesn't work. No errors displayed. It's just not running. Does anyone no why? Code example below.
<template>
<div class="holder">
<step v-for="item in steps"></step>
<events v-for="point in points"></events>
<button #click= "createArrows">Test</button>
</div>
</template>
<script>
import axios from 'axios'
import Step from './Step.vue'
import Events from './Events.vue'
export default {
name: 'Graph',
data () {
return {
steps: '',
events: '',
points: []
},
components: {
Step, Events
},
methods: {
getSteps: function() {
let getsteps = this
axios.get('localhost:8000/api/steps')
.then(function (response) {
getsteps.steps = response.data
})
.catch(function (error) {
getsteps.steps = "Invalid request"
})
},
getEvents: function() {
let getevents = this
axios.get('localhost:8000/api/events')
.then(function (response) {
getevents.events = response.data
})
.catch(function (error) {
getevents.events = "Invalid request"
})
},
createArrows: function() {
},
created() {
this.getSteps(),
this.getEvents(),
this.createArrows()
}
}
EDIT: Promises are already included in the axios library. Since I am new to this concept I missed this one. Refactored code below:
methods: {
getData: function() {
let getdata = this
axios.all([
axios.get('localhost:8000/api/steps'),
axios.get('localhost:8000/api/events')
])
.then(axios.spread(function (stepResponse, eventResponse) {
console.log('success')
getdata.steps = stepResponse.data
getdata.events = eventResponse.data
getdata.createArrows()
}))
.catch(function (error) {
console.log("Invalid request")
})
},
createArrows: function() {
}
},
created() {
this.getData()
}
}
</script>
I think it's a classic async issue.
With v-on, your call to createArrows is "timewise after" getSteps and getEvents: meaning that getSteps and getEvents have finished executing their internal ajax promises, have populated the relevant data into the component instance for createArrows to find and access.
However, inside the created() hook, if you think about it, the calls fall through to createArrows() instantaneously (before the promisy things inside getSteps and getEvents have finished).
You'll have to refactor the call to createArrows inside created() as promise resolve for it work there correctly.