orderBy on a Nuxt3 v-for loop - javascript

I have a Nuxt3 project and my v-for loop is working, but I can't figure out how to order my list.
I know it's a Vue thing and not Nuxt, but I am new to both.
<template>
<div class="max-w-7xl mx-auto my-10 sm:px-6 lg:px-8">
<div v-if="pending">Loading ...</div>
<div v-else>
<ul class="list-none" style="columns: 4">
<li
v-for="nda in ndas"
v-bind:key="nda.id"
class="font-color: text-slate-600 hover:text-red-600 hover:underline"
>
<Nuxt-link :to="'/ndas/' + nda.id">
{{ nda.user_signature }}
</Nuxt-link>
</li>
</ul>
</div>
</div>
</template>
<script setup>
const { pending, data: ndas } = useLazyFetch(
"https://***/nda-data.json"
);
watch(ndas, (newNdas) => {});
</script>

You need to computed filtered array for this. Just create a new computed property and return filtered array.
const filteredNdas = computed(() => {
return ndas.filter(item => item.id > 5)
})
And so use your new array in the v-for loop
v-for="nda in filteredNdas"

Related

Having trouble using database data in vue app?

Hi I've been trying to get multiple profiles from a database and use v-for to try and display them all but whenever I try it doesn't work on and I can't figure out how to get it to use the data which should be getting imported.
Below is what the javascript file looks like.
import { projectFirestore } from "../Firebase/Config";
import { ref } from "vue"
const getPremium = () => {
const Premium = ref([])
const error = ref(null)
const load = async () => {
try{
const res = await projectFirestore.collection('Premium').get()
Premium.value = res.docs.map(doc => {
console.log(doc.data())
return {...doc.data(), id: doc.id}
})
}
catch (err){
error.value = err.message
console.log(error.value)
}
}
return { Premium, error, load}
}
export default getPremium
And heres the vue where I am trying to use v-for to create the profiles.
<script>
import getPremium from "../Composables/getPremium.js";
const {Premium, error, load} = getPremium();
load();
</script>
<template>
<div v-for =" Premium in getPremiums" :key="Premium.id" >
<div class= "hover:scale-105 transition ease-in-out duration-300 bg-neutral-800 hover:bg-neutral-900 active:bg-neutral-900 text-neutral-400 font-bold rounded-xl">
<br>
<p>{{ Premium.Name }}</p>
<img src="../assets/Sample-pic.png" class="object-contain ml-6 w-60 h-80 transition ease-in-out duration-300">
<div class="grid grid-cols-2 grid-rows-fit text-left ml-6">
<p>Location:</p>
<p>{{ Premium.Location }}</p>
<p>Rates:</p>
<p>{{ Premium.Rates }} /hr</p>
<p>Phone:</p>
<p>{{ Premium.Phone }}</p>
</div><br>
</div>
</div>
</template>
I'm not sure what I need to do from here to get it to work properly, I'm new to using databases and any help would be greatly appreciated, Thankyou
Besides, you are trying to iterate through function, you iterate it using in operator. In operator iterates object properties, no arrays. And created variables call using first small character not big one like you have in code "Premium".
<script>
import getPremium from "../Composables/getPremium.js";
const { premiumList, error, load } = getPremiumList(); // Name variables, functions with first small letter not big one. Interfaces, Clases with first big letter. Add "List" or "s" in end of name so everyone knows it is array.
load();
</script>
<template>
<main>
<div v-for="item of premiumList" :key="item.id">
<div
class="hover:scale-105 transition ease-in-out duration-300 bg-neutral-800 hover:bg-neutral-900 active:bg-neutral-900 text-neutral-400 font-bold rounded-xl"
>
<br />
<p>{{ item.Name }}</p>
<img
src="../assets/Sample-pic.png"
class="object-contain ml-6 w-60 h-80 transition ease-in-out duration-300"
/>
<div class="grid grid-cols-2 grid-rows-fit text-left ml-6">
<p>Location:</p>
<p>{{ item.Location }}</p>
<p>Rates:</p>
<p>{{ item.Rates }} /hr</p>
<p>Phone:</p>
<p>{{ item.Phone }}</p>
</div>
<br />
</div>
</div>
</main>
</template>
You are destructuring Premium from getPremium(), so that is what you should use in your v-for
<script>
import getPremium from "../Composables/getPremium.js";
const { Premium, error, load } = getPremium();
load();
</script>
<template>
<main>
<div v-for="item in Premium" :key="item.id">
<div
class="hover:scale-105 transition ease-in-out duration-300 bg-neutral-800 hover:bg-neutral-900 active:bg-neutral-900 text-neutral-400 font-bold rounded-xl"
>
<br />
<p>{{ item.Name }}</p>
<img
src="../assets/Sample-pic.png"
class="object-contain ml-6 w-60 h-80 transition ease-in-out duration-300"
/>
<div class="grid grid-cols-2 grid-rows-fit text-left ml-6">
<p>Location:</p>
<p>{{ item.Location }}</p>
<p>Rates:</p>
<p>{{ item.Rates }} /hr</p>
<p>Phone:</p>
<p>{{ item.Phone }}</p>
</div>
<br />
</div>
</div>
</main>
</template>

Vue.js iterate props array and manage additional state for that array

I have the prop that is array, iterate it in template and try to manage hover state with displaying additional element when hover is happened:
<template>
<div class="d-flex justify-center" style="height: 100%">
<div v-for="(item, i) in data" :key="i" class="flex-grow-1 d-flex flex-column" style="height: 100%">
<div class="px-2" style="height: 100%;">
<div class="d-flex flex-column-reverse justify-start align-end" style="height: 100%;">
<div class="bar"
:class="{'bar-active' : item.isActive}"
#mouseover="item.isHover = true"
#mouseleave="item.isHover = false"
:style="`height: ${getBarHeight(item.y)}%`"/>
<div class="container">
<div v-if="item.isHover || item.isActive" class="label fw-600 fs-12 tc-text-primary">{{getIncomeView(item)}}</div>
</div>
</div>
</div>
<div class="container">
<div class="label content-accent" style="white-space: nowrap;">{{item.x}}</div>
</div>
</div>
</div>
</template>
<script lang="ts">
import { Component, Prop, Vue, Watch } from "vue-property-decorator";
import BarChartModel from "./bar-chart-model";
#Component({
components: {
}
})
export default class OverviewChart extends Vue {
#Prop({default: () => []})
data!: BarChartModel[];
hovers: boolean[] = [];
...
}
</script>
The problem is coming when I try to pass the data as prop. Data ceases to be updated with item.isHover = true and hover feature doesn't work. I tried to keep the hover state in separate data array (out of the prop in hovers: boolean[] = []), but it also doesn't work (state array is changed, but if hasn't react on the v-if="hovers[i]". What I can do to track the hover state and display the additional element during hover and pass the data as prop?

Method "getChampionName" has type "undefined" in the component definition. Did you reference the function correctly?

I'm trying to use this function (src/api/)
function getChampionName(champId) {
axios.get('http://ddragon.leagueoflegends.com/cdn/12.5.1/data/en_US/champion.json')
.then(({ data }) => {
let list = data
let championList = list.data
for (var i in championList) {
if (championList[i].key == champId) {
return championList[i].id
}
}
})
.catch((err) => console.log(err))
}
export {getChampionName}
In this component (src/components/)
<template>
<div class="w-72">
<header class="rounded-tl-lg rounded-tr-lg bg-slate-400 p-0.5">
<p>Champion's Mastery</p>
</header>
<ul class="grid gap-1 rounded-bl-lg rounded-br-lg bg-slate-50 p-0.5">
<li v-for="champ in masteryData.slice(0,10)" :key="champ.championId">
<div class="flex items-center justify-between">
<div class="flex items-center gap-2">
<img src="https://ddragon.leagueoflegends.com/cdn/12.5.1/img/champion/Karma.png" alt="" class="rounded-lg h-14 w-14">
<div>
<p class="font-medium text-center">{{ getChampionName(champ.championId) }}</p>
<p>Level {{ champ.championLevel }}</p>
</div>
</div>
<p class="text-2xl font-medium">{{ champ.championPoints }} Pts</p>
</div>
</li>
</ul>
</div>
</template>
<script>
import getChampionName from '#/api/search'
export default{
name: 'MasteryInfo',
props: [
'masteryData'
],
methods: {
getChampionName
}
}
</script>
But I'm getting this error Method "getChampionName" has type "undefined" in the component definition. and don't know what does it mean.
It seems you didn't import the method properly.
Change the import into:
import { getChampionName } from '#/api/search';
You can read more about import export in javascript here:
https://javascript.info/import-export
If you think you almost have the same question as this question, you can also refer to this:
Method "showDate" has type "undefined" in the component definition

SvelteKit: 'filtered' is not a store with a 'subscribe' method

I am trying to write a Pokedex SvelteKit app (as a tutorial from James Q Quick). When I save my index.svelte file - it says the error in the title of this question.
My index.svelte code is as follows:
<script>
import Nav from '../components/nav.svelte'
import {pokemon} from '../stores/pokestore'
import PokemanCard from "../components/pokemanCard.svelte"
let searchTerm = "";
let filtered = [];
$: { // Reacts to any data that changes ($: {what will happen when data changes})
if (searchTerm !== pokemon.searchTerm) {
searchTerm = pokemon.searchTerm;
filtered = filtered(pokemon.pokemons, searchTerm);
}
}
</script>
<svelte:head>
<title>Svelte Kit Pokedex</title>
</svelte:head>
<!-- All HTML Work -->
<h1 class="text-4xl text-center m-8 uppercase">SvelteKit Pokedex</h1>
<input type="text" class="w-full rounded-md text-lg p-4 border-2 border-gray-200" placeholder="Search Pokemon" bind:value={searchTerm}>
<style>
</style>
<div class="py-4 grid gap-4 md:grid-cols-2 grid-cols-1">
{#each $filtered as pokeman}
<PokemanCard pokeman={pokeman} />
{/each}
</div>
How do I fix this?
Thanks :)
filtered is just an array, not a svelte store (or entity that exposes a subsribe() method) so you can't use the $ shorthand to subscribe to it. Just iterate it as an array (without the $).
{#each filtered as pokeman}
...
{/each}
But is pokemon a store? if so you'll need to subscribe to it in the reactive statement to see the changes.
<script>
import Nav from '../components/nav.svelte'
import {pokemon} from '../stores/pokestore'
import PokemanCard from "../components/pokemanCard.svelte"
let searchTerm = "";
let filtered = [];
$: if (searchTerm !== $pokemon.searchTerm) {
searchTerm = $pokemon.searchTerm;
filtered = filtered($pokemon.pokemons, searchTerm);
// *Note: I'm not sure where this 'filtered()' method is coming from but it will conflict with your `filtered` array variable.
}
</script>
<svelte:head>
<title>Svelte Kit Pokedex</title>
</svelte:head>
<!-- All HTML Work -->
<h1 class="text-4xl text-center m-8 uppercase">SvelteKit Pokedex</h1>
<input type="text" class="w-full rounded-md text-lg p-4 border-2 border-gray-200" placeholder="Search Pokemon" bind:value={searchTerm}>
<style>
</style>
<div class="py-4 grid gap-4 md:grid-cols-2 grid-cols-1">
{#each filtered as pokeman}
<PokemanCard pokeman={pokeman} />
{/each}
</div>
Alternatively you could make use of a svelte derived store for your filtered collection, in which case you would use the $ shorthand in iterating it
<script>
import { derived } from 'svelte/store';
import { pokemon } from './stores.js';
const filtered = derived(
pokemon,
$pokemon => $pokemon.pokemons.filter(p => /* your filter logic */ )
);
</script>
<div class="py-4 grid gap-4 md:grid-cols-2 grid-cols-1">
{#each $filtered as pokeman}
<PokemanCard pokeman={pokeman} />
{/each}
</div>

#click within v-for triggers all #click events

When a single #click is triggered from within the v-for the display property in all of the objects within the array is updated, rather than just by index. I only want that element that is click to receive the event and update the display property, not all of them.
<script>
import TransitionExpand from '#/transitions/transition-expand'
import ResourceCard from '#/components/resource-card'
export default {
components: {
TransitionExpand,
ResourceCard
},
data () {
return {
}
},
methods: {
toggle (evt, i) {
this.status[i].display = !this.status[i].display
}
},
async asyncData ({ app }) {
const { data } = await app.$axios.get('training_modules')
const status = Array(data.trainingModules.length).fill({ display: false })
return {
modules: data.trainingModules,
status
}
}
}
</script>
<template>
<div>
<div class="container px-4 mx-auto mt-16 lg:mt-32">
<div class="flex flex-wrap mb-20">
<h1 class="w-full lg:w-1/2 mb-6">Training Modules</h1>
<p class="w-full lg:w-1/2 leading-7 text-abbey"></p>
</div>
<div
v-for="(item, i) in modules"
:key="item.id"
class="mb-12"
>
<div class="flex items-center">
<h2>{{ item.title }}</h2>
<img #click="toggle($event, i)" class="ml-auto cursor-pointer" src="#/assets/images/icons/plus.svg" alt="open">
</div>
<TransitionExpand v-show="status[i].display">
<div class="">
<p class="mt-6 mb-12">{{ item.description }}</p>
<div class="flex flex-wrap -m-3">
<ResourceCard
v-for="resource in item.resources"
:key="resource.id"
:resource="resource"
/>
</div>
</div>
</TransitionExpand>
</div>
</div>
<BaseFooter />
</div>
</template>
Problem is in const status = Array(data.trainingModules.length).fill({ display: false }) code which is filing all array items with the same object which is observable hence change in display property will be applied to all elements in the array as status[0] === status[1].
Use map instead and it will work as expected:
const status = data.trainingModules.map(() => ({ display: false }));

Categories

Resources