1👍
There are several problems here.
The data
function is called just once, when the corresponding Vue instance is created. Within that function you can get a reference to its Vue instance via this
. At that point some properties, such as those corresponding to props
, will already exist. However, others won’t.
The object returned from data
is used to create new properties on the instance. In this case you’re creating 4 properties: topic1
, topic2
, currentBreed
and breeds
. Vue creates those properties based on that returned object, so they won’t exist until after the data
function is run.
So when you write { name: this.topic1 , key: this.topic1 },
within that data
function you’re attempting to access a property called topic1
that doesn’t exist yet. As such it will have a value of undefined
. So you’re creating an entry equivalent to { name: undefined , key: undefined },
.
Further, there is no link back to topic1
. That object won’t be updated when the value of topic1
changes.
It’s also worth noting a few points about timing.
- The
data
function will be called before thecreated
hook, so theaxios
call isn’t made until after thedata
properties are populated. - An
axios
call is asynchronous. - Using
await
may make the code a little easier to read but the ‘waiting’ is mostly just an illusion. The remaining code inside the function won’t run until the awaited promise is resolved but that won’t cause anything outside of the function to wait.await
is equivalent to usingthen
. - The component will render just after the
created
hook is called. This is synchronous, it won’t wait for theaxios
request. Themounted
hook will then be called, all before theaxios
call has completed.
All of this means you may need to adjust your template to handle the case where the axios
call hasn’t completed yet as it will initially render prior to the values of topic1
and topic2
being available.
Specifically addressing the breeds
property you have a few options. One is to inject the values in once the value has loaded:
breeds: [
{ name: "" , key: "" }, // Initially empty values
{ name: "German Shepherd", key: "germanshepherd" },
// ...
const res = await this.promise;
this.topic1 = res.data[0].Trends;
this.topic2 = res.data[1].Trends;
this.breeds[0].name = this.breeds[0].key = this.topic1;
Another is to use a computed
property for breeds
(you’d remove it from the data
for this):
computed: {
breeds () {
return [
{ name: this.topic1 , key: this.topic1 },
{ name: "German Shepherd", key: "germanshepherd" },
{ name: "Husky", key: "husky" },
{ name: "Pug", key: "pug" },
{ name: "(Error)", key: "error" },
]
}
}
As we’re using a computed
property it will be updated when topic1
changes as it’s a reactive dependency.
Using a computed
property is probably the most natural solution in this case but there are other tricks you can use to get this to work.
For example, you could use property getters for the two properties in that first breed object (that’s JavaScript property getters, nothing to do with Vue):
data () {
const vm = this;
return {
topic1: null,
topic2: null,
currentBreed: 0,
breeds: [
{
get name () {
return vm.topic1;
},
get key () {
return vm.topic1;
}
},
{ name: "German Shepherd", key: "germanshepherd" },
{ name: "Husky", key: "husky" },
{ name: "Pug", key: "pug" },
{ name: "(Error)", key: "error" },
]
}
},
I’m not advocating this approach for your use case but it is an interesting way to do it that can sometimes be useful. The key thing to note is how the dependency on topic1
is evaluated only when the properties name
and key
are accessed, not when the data
function is executed. This allows topic1
to be registered as a dependency of whatever is accessing name
and key
, e.g. during rendering.