Throw worning for props in vue3 when using with typescript generic - vuejs3

I facing such strange warning.
I defined non-Array types look like posted sample codes.
But, Vue3 was throwing warnings.
Have some solutions??
or I got some miss takes?
Simply, I was defined modelValue type look like T | T[] | undefined
But, Vue3 detected Null | Array.
Then, How a T are have been ignored??
I'm using Nuxt3, Vue3, composition api
// types/index.d.ts
type ItemType { [key: string]: any } | string | boolean
// CSelect.vue
<template><div>{{/* contents - It's not a key on this Topic */}}</div></template>
<script setup lang="ts" generic="T extends ItemType">
defineProps<{
items: T[]
modelValue: T | T[] | undefined
}>()
</script>
// create.vue - how i used
<template>
<div class="create">
<div class="title-area">
<CForm>
<InputTemplate>
{{/* This CSelect components are Throw warnings by v-model */}}
<CSelect
v-model="data.category"
class="nft-input"
:items="categoryItems"
/>
</InputTemplate>
</CForm>
</div>
<div>
</template>
<script setup lang="ts">
const categoryItems = computed(() => ['value1', 'value2', 'value3'])
const data = reactive({ category: String(categoryItems.value[0]) })
</script>
[Vue warn]: Invalid prop: type check failed for prop "modelValue". Expected Null | Array, got String with value "Limited".
at <CSelect modelValue="Limited" onUpdate:modelValue=fn class="input" ... >
at <InputTemplate title="Category" >
at <CForm modelValue=false onUpdate:modelValue=fn class="inputs-area" ... >
at <Create onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< undefined > >
at <Anonymous key="/member/99/create" routeProps= {Component: {…}, route: {…}} pageKey="/member/99/create" ... >
at <Anonymous >
at <RouterView name=undefined route=undefined >
at <NuxtPage>
at <Default >
at <Anonymous key="default" name="default" hasTransition=false >
at <Anonymous >
at <Anonymous>
at <App key=1 >
at <NuxtRoot>

Your parent component create.vue has no setup and lang="ts". You're passing to a child v-model and class with no : so they aren't props, they are attributes. div element will have them because he is a root element.
Example how to use attributes:
<template>
<div>
<label :for="label">{{label}}</label>
<input v-bind="$attrs" :id="label" :value="$attrs.modelValue" #input="$emit('update:modelValue', $event.target.value)">
</div>
</template>
<script setup>
defineProps(['label'])
defineEmits(['update:modelValue'])
</script>
v-bind assign all attributes to one element.
I'm not using generic in components, so I can just tell you stop! User don't care about generic, and you are not experienced programmer to build UI libraries for different programmers.

Related

[Vue warn]: Property "xxx" was accessed during render but is not defined on instance

I'm getting this super confusing Vue warning and I can't figure it out:
[Vue warn]: Property "me" was accessed during render but is not defined on instance.
at <UserReputation user= {reputation: {…}, _id: '638f81dbb288267e6340ddbc', username: 'artsborba'…} class="mt-1" >
...
Here on StackOverflow I can find more topics with this warning, but seems each one is a different case, and mine is just not making sense! My vue version is ^3.1.0, vuetify ^3.1.0 and vite ^2.5.4.
My component looks like:
// MyComponent.vue
<v-menu location="end" location-strategy="connected">
<template #activator="{ props }">
<div
v-bind="props"
class="user-info-container cursor-pointer"
>
<UserAvatar
:user="me"
/>
<div v-if="me" class="user-data">
<div class="username-row">
{{ me.username }}
<AppIcon
icon="downward-arrow"
color="primary"
class="user-menu-icon"
:class="{ 'is-active': props['aria-expanded'] === 'true' }"
/>
</div>
<!-- HERE WE HAVE THE WARNING SOURCE -->
<UserReputation :user="me" class="mt-1" />
</div>
</div>
</template>
...
</v-menu>
In the same component I have the me set as a prop:
props: {
me: {
validator: prop => typeof prop === 'object' || prop === null,
required: true
}
},
Now, please notice that in the same component I have another one using this me pro (<UserAvatar :user="me"...>), which doesn't trigger this warning. Only the <UserReputation... component usage does! If I comment out the <UserReputation... tag, the warning goes away.
I already tried placing this me as a computed value instead of a prop, directly inside MyComponent.vue (it comes from a Pinia store) and many other structures with no success. Hopefuly someone can help on this! Thanks in advance.
Maybe you are accesing at me property inside your UserReputation component, but in the parent you are passing me to user prop, like this :user="me", so... you need to access to user prop instead me prop inside UserReputation component.
If this answer doesn't resolve the question, please share us the structure of UserReputation component.

Cannot destructure property 'isActive' of 'undefined' as it is undefined

Using script setup in vue3, I have code like this in template
...
<router-link
v-for="t in tas"
:key="t.text"
custom
:to="`/dashboard/${t.type}`"
v-slot="{ isActive, navigate }"
>
<div
:class="{ active: isActive }"
#click="navigate"
>
{{ t.text }}
</div>
</router-link>
...
Its throwing error TypeError: Cannot destructure property 'isActive' of 'undefined' as it is undefined. when running a simple test
it('match snapshot', () => {
const wrapper = shallowMount(MYView, {
stubs: ['router-link'],
});
expect(wrapper.html()).toMatchSnapshot();
});
You need to stub it using RouterLinkStub, see https://test-utils.vuejs.org/api/#routerlinkstub

Data Binding between parent and child component in vue3 composition api

I have successfully bound data in a two way format in vue 3 like this :
<template>
<p for="">Year of Incorporation</p>
<input type="text" v-model="input" />
<div>
{{ input }}
</div>
</template>
<script>
export default {
setup() {
let input = ref("")
return {input};
},
};
</script>
What I want to do now is put the input inside a child component like this:
Parent Component:
<template>
<Child v-model="input" />
{{input}}
</template>
Child Component:
<template>
<input type="text" v-model="babyInput" />
</template>
<script>
export default {
setup() {
let babyInput = ref("")
return {babyInput};
},
};
</script>
The Vue.js documentation presents a nice way of handling v-model-directives with custom components:
Bind the value to the child component
Emit an event when the Child's input changes
You can see this example from the docs with the composition when you toggle the switch in the right-top corner (at https://vuejs.org/guide/components/events.html#usage-with-v-model).

Sveltekit couldn't load and render data from Firestore

I've been trying to get this sveltekit code to work for the past 1 week and no matter how I tried, it doesn't seem to work.
Before I go to my code, this is the error message:
Cannot read properties of undefined (reading 'length') TypeError: Cannot read properties of undefined (reading 'length')
at Proxy.each (/Users/cadellteng/Documents/code/police/APDVolunteers/node_modules/svelte/internal/index.js:1710:31)
at eval (/src/lib/components/officer-list.svelte:74:29)
at eval (/src/lib/components/officer-list.svelte:109:5)
at officer-list.svelte:45:12
at Object.$$render (/Users/cadellteng/Documents/code/police/APDVolunteers/node_modules/svelte/internal/index.js:1745:22)
at eval (/src/lib/sections/training-record.svelte:25:94)
at Object.$$render (/Users/cadellteng/Documents/code/police/APDVolunteers/node_modules/svelte/internal/index.js:1745:22)
at eval (/src/routes/admin/index.svelte:17:97)
at Object.$$render (/Users/cadellteng/Documents/code/police/APDVolunteers/node_modules/svelte/internal/index.js:1745:22)
at Object.default (root.svelte:43:39)
This is my code to get data from Firebase:
<script lang="ts" context="module">
// Import Firebase
import { db } from '$lib/scripts/firebaseInit'; //from my custom FirebaseInit.ts
import { collection, getDocs } from 'firebase/firestore';
export async function load() {
let allOfficers = [];
console.log("Loading data");
const querySnapshot = await getDocs(collection(db, "officers"));
// console.log(querySnapshot);
querySnapshot.forEach((doc) => {
// doc.data() is never undefined for query doc snapshots
let data = doc.data();
// console.log(doc.id, " => ", data);
allOfficers.push(data);
});
console.log(allOfficers)
return {
props: { allOfficers }
};
}
</script>
<script lang="ts">
export let allOfficers;
</script>
And the following are my code to render the data:
<div class="officer__list">
{#each allOfficers as officer}
<div class="officer__card accordion">
<div class="officer__content-details">
<h4 class="officer-name">{officer.name.displayed}</h4>
<p class="officer-rank-appointment">
Rank 1 | Head of Department
</p>
</div>
</div>
{/each}
</div>
And just in case you are wondering if my FirebaseInit.ts is not working well, I have another example that worked without changing anything in the script tags:
<div class="test-container">
<ul>
{#each allOfficers as officer}
<li>
{officer.name.displayed}
</li>
{/each}
</ul>
</div>
The above works like magic without changing anything in the script tags.
Edit: This is a component within a bigger svelte file. I realize when I make this its own route, it works...? What's wrong?
So I have managed to solve the problem and I can't use the context module to load data at the component level. After I move the script tag content for the load to the route level, it works perfectly. I just need to pass it down into individual components as props.

Angular2: Async pipe for array index

I have an observable of string Arrays const obs$: Observable<string[]> on my component as a property. While I can successfully use the async pipe on a *ngIf statement, the pipe fails when accessed via array indexer (obs$ | async)[0].
Example:
<!-- evaluates the array emmitted by obs$ for truthyness -->
<div *ngIf="obs$ | async">
<!-- only shown if obs$ emitted an array with length > 0 -->
<!-- but this fails with error: Cannot read property '0' of null -->
<img [src]="(obs$ | async)[0]">
</div>
The instance of obs$ is set in the component's constructor, so obs$ shouldn't be undefined when the template is data-bound.
How to properly access the array's elements in the template?
This might work
<img [src]="(obs$ | async) ? (obs$ | async)[0] : null">
I would try the Elvis operator at this level since your data is undefined at the beginning:
<img [src]="(obs$ | async)?[0]">

Resources