I'm new to the front end and just trying things out. I followed the tutorial and vue examples to create a simple web app. I want to populate the dropdown select box with data fetched from the backend now. But whatever I tried it just didn't work and fails with TheSandbox.vue:18 Uncaught (in promise) TypeError: Cannot set properties of undefined (setting 'sendOptions')
. Unfortunately, all the vue examples in the tutorial are for the static data set. What am I missing here? The code is below:
App.vue
<script setup>
import TheHeader from './components/TheHeader.vue'
import TheSandbox from './components/TheSandbox.vue';
</script>
<template>
<header>
<img alt="Vue logo" class="logo" src="./assets/logo.svg" width="125" height="125" />
<div class="wrapper">
<TheHeader msg="You did it!" />
</div>
</header>
<main>
<TheSandbox />
</main>
</template>
TheSandbox.vue
<script setup>
import { ref } from 'vue'
const sendAmount = ref('')
const sendSelected = ref('')
const sendOptions = ref([])
async function fetchItems() {
return fetch('<MYURL>', {
method: 'GET',
headers: {
"Content-Type": "application/json",
},
}).then(response => {
console.log(response)
response.json().then(data => {
this.sendOptions = data.map(item => ({
value: item.code, // actual value for the option
text: item.name, // display text for the option
}))
console.log(data)
});
}).catch(err => {
console.error(err);
});
}
import { onMounted } from 'vue'
import { nextTick } from 'vue'
onMounted(async () => {
// Fetch the data first
await fetchItems();
// Use await nextTick to wait until the DOM is updated
await nextTick();
// Now, you can interact with the DOM if necessary (e.g., selecting a default option)
console.log('DOM updated and options are rendered');
})
</script>
<template>
<div class="item">
<div class="details">
<h3>
You send {{ sendAmount }} {{ sendSelected }}
</h3>
<input v-model="sendAmount" placeholder="0" />
<select v-model="sendSelected">
<option v-for="option in sendOptions" :key="option.value" :value="option.value">
{{ option.text }}
</option>
</select>
</div>
</div>
</template>
Thanks!
refer to sendOptions
with sendOptions.value
since it's declared with ref
:
sendOptions.value = data.map(item => ({
value: item.code, // actual value for the option
text: item.name, // display text for the option
}))
this
refers to the global scope (window
) which doesn't have the property sendOptions
.
Try to restructure your code in this way :
<script setup>
import { ref, onMounted, nextTick } from "vue";
const sendAmount = ref("");
const sendSelected = ref("");
const sendOptions = ref([]);
async function fetchItems() {
try {
const response = await fetch("<MYURL>", {
method: "GET",
headers: {
"Content-Type": "application/json",
},
});
const data = await response.json();
sendOptions.value = data.map((item) => ({
value: item.code, // actual value for the option
text: item.name, // display text for the option
}));
console.log(data);
} catch (err) {
console.error(err);
}
}
onMounted(async () => {
// Fetch the data first
await fetchItems();
// Use await nextTick to wait until the DOM is updated
await nextTick();
// Now, you can interact with the DOM if necessary (e.g., selecting a default option)
console.log("DOM updated and options are rendered");
});
</script>