I'm new in vue 3, and I need your help. I created vue app that uses rest API to fetch the data. Also I added the features as filter and search to my application. But when I use filter or search function, it creates another computed arrays. First array is data, another is filteredData and third is filterByDate. Please, can you tell me, how to operate only with one araay in an app. Thanks in advance! There is a code of my component.
<template>
<Loading v-if="isLoading" />
<AsteroidLayout
v-else
:data="data"
:fetchData="fetchData"
:plusDay="plusDay"
:changeDay="changeDay"
>
<div >
<input
type="text"
placeholder="Search an asteroid by name"
v-model="searchQuery"
/>
</div>
<button @click="sorted = !sorted">Filter by close approach date</button>
<div v-if="sorted" v-for="asteroid in filterByDate" :key="asteroid.name">
<Asteroids :asteroid="asteroid" />
</div>
<div v-for="asteroid in filteredData" :key="asteroid.id">
<Asteroids :asteroid="asteroid" />
</div>
</AsteroidLayout>
</template>
<script>
import { onMounted, ref } from "vue";
import { addDays } from "date-fns";
import { computed } from "vue";
import Loading from "../components/Loading.vue";
import AsteroidLayout from "../components/AsteroidLayout.vue";
import Asteroids from "../components/Asteroids.vue";
export default {
components: {
Loading,
AsteroidLayout,
Asteroids,
},
setup() {
const API_KEY = "Kzb0E64htPxZGEM33UC62hrug7mfHAzEzIH8Qyu1";
const data = ref([]);
const isLoading = ref(false);
const sorted = ref(false);
const plusDay = ref(0);
const searchQuery = ref("");
onMounted(() => {
fetchData(data.value);
});
const fetchData = (type) => {
isLoading.value = true;
data.value = type;
fetch(
`https://api.nasa.gov/neo/rest/v1/feed?end_date=${getDate()}&&api_key=${API_KEY}`
)
.then((res) => res.json())
.then((res) => {
let fetchedData = res.near_earth_objects[getDate()];
data.value = fetchedData;
isLoading.value = false;
})
.catch(() =>
alert(
"Sorry, we can't load the asteroids data. Please try again later or check your internet connection"
)
);
};
const getDate = () => {
return `${addDays(new Date(), plusDay.value).toISOString().substring(0, 10)}`;
};
const changeDay = (day) => {
plusDay.value = day;
fetchData(data.value);
};
const filteredData = computed(() => {
return data.value.filter((asteroid) => {
return asteroid.name.toLowerCase().indexOf(searchQuery.value.toLowerCase()) != -1;
});
});
const filterByDate = computed(() => {
return data.value.sort((a, b) => {
return (
Date.parse(new Date(a.close_approach_data[0].close_approach_date_full)) -
Date.parse(new Date(b.close_approach_data[0].close_approach_date_full))
);
});
});
return {
data,
isLoading,
fetchData,
plusDay,
changeDay,
filteredData,
searchQuery,
filterByDate,
sorted,
};
},
};
</script>
<style scoped>
.inputWrapper {
text-align: right;
}
.search {
border: none;
height: 30px;
width: 200px;
outline: none;
border: 3px solid var(--secondary);
border-radius: 35px;
color: black;
font-size: 14px;
font-weight: 200;
text-align: center;
}
</style>
And there is a screenshot of the vue devtools
CodePudding user response:
You need just 1 computed prop for your searchQuery
You can try this instead
const filteredData = computed(() => {
let modifiedData = data.value;
if(sorted.value){
modifiedData = modifiedData.sort((a, b) => {
return (
Date.parse(new Date(a.close_approach_data[0].close_approach_date_full)) -
Date.parse(new Date(b.close_approach_data[0].close_approach_date_full))
);
});
}
if(searchQuery.value !== ''){
modifiedData = modifiedData.filter((asteroid) => {
return asteroid.name.toLowerCase().indexOf(searchQuery.value.toLowerCase()) != -1;
});
}
return modifiedData;
});
In HTML
<div v-for="asteroid in filteredData" :key="asteroid.name">
<Asteroids :asteroid="asteroid" />
</div>
This way you have sorted as well as filtered data according to searchQuery
and all modifications are on original data
which you received from api.