How do I get data with VUE v-for? - vue.js

I am trying to get my data with APOLLO and show them on the page with v-for. However, i can access the data, even though i can see them in the vue console. What am i missing?
I also tried v-for="post in data.posts.nodes", with no luck..

Right now you are calling the apollo query in the parent component (index.vue) and are trying to access data in the child component (Tutorial.vue)
You can pass data to the Tutorial component as a prop or take Apollo query into the Tutorial component.
Pasting the following code into your index.vue, should render your data.
<li v-for="post in post.nodes" :key="post.id" >{{post.title}}</li>

Related

Vue component communication between header component and components in the router-view

Im facing a problem for my VUE app, Im using the vue Router to navigate to my component
In my Header component I use router-link to navigate to a Home component
The problem is :
In my Header component I would like a checkBox (a boolean variable) that change the content of my Home component (rendered in the router-view) like a v-if that would check the boolean variable in the Header
Here is my App.vue template I was trying to solve the problem through emits but Im Kinda stuck for passing data inside a component (inside the router-view)
<template>
<div class="content">
<HeaderComponent #eventCheckBox="handleCheckBox" />
<router-view />
<FooterComponent />
</div>
Do you guys have already faced this issue, is there a way to do it the classic way or should I try plugins like Portal or Teleport ?
Portal and Teleport are the same, just a different name (teleport in Vue3, being the official name).
As of the rest of the question, this explains it very well: https://stackoverflow.com/a/49702934/8816585
Mainly, you need to see if you need to use a store like Pinia (recommended one) and Vuex. Most of the time, you could use a parent/child relationship. Here is another article explaining when you would need something like that: https://markus.oberlehner.net/blog/should-i-store-this-data-in-vuex/#alternatives-to-storing-data-in-vuex
In Vue3, you could even not use a store and rely solely on the singleton pattern + composables (again, a lot of articles are available for that one).
TLDR: use your Vue devtools and inspect the state flowing.
If you need more, reach for more powerful tools.

v-if breaks nuxt ssr

If I use fetched data (fetchPolicy: 'cache-and-network') from apollo in v-if, it will throw
vue.runtime.esm.js:619 [Vue warn]: The client-side rendered virtual DOM tree is not matching server-rendered content. This is likely caused by incorrect HTML markup, for example nesting block-level elements inside <p>, or missing <tbody>. Bailing hydration and performing full client-side render.
<template>
<div
<div v-if="test">
{{ test }}
</div>
</div>
</template>
but if I use it just as variable to render it works fine.
<template>
<div>
{{ test }}
</div>
</template>
The data in real usage is object, that I need to conditionaly render and pass to another components with v-if.
I have tried geting the data trough get, doing watch over the data and seting them manually, but eventually everything broke.
regarding comment:
if I console the test data it will go -> true on server -> false on client and then true on the client again, if I remove the test from v-if it goes: true on server and true on client
this has nothing to do with structure, in real project it has bunch of components and it works just fine if the data isnt used in condition
For anyone facing the same problem, I have fixed it by setting cache-and-network after the mount and all works just fine.
mounted() {
this.$apollo.queries.getCampaign.setOptions({
fetchPolicy: 'cache-and-network',
})
}
You are trying to make the root element of a component conditionnally disappear, which creates an inconsistency in the virtual DOM.
Can you try:
<template>
<div>
<template v-if="test">
{{ test }}
</template>
</div>
</template>
from my experience, nuxt will failed in SSR if you are using v-if unless you wrap in <no-ssr> or <client-only>
SSR is sometimes difficult to debug and such problems occure quite often.
https://ssr.vuejs.org/#why-ssr
some external libraries may need special treatment to be able to run
in a server-rendered app.
This may be the point. Some vue-components cannot be run via SSR out of the box. This is why I asked about the content from the server.
So the easiest fix could be to wrap your component with the <no-ssr> tag. You can do this for each component separatly to find out which one causes the problem.
Once you have isolated the component you can keep the <no-ssr> tag on it and migrate it's functions to the mounted area of your client component.
If it is a small component you can also use v-show instead.

vue-router reloading App.vue on every new route

I have an App.vue file, which has a vue-router component in it that loads the content of my different pages, like this:
<template>
<div>
<router-view
:auth="auth"
:page_id="page_id"
>
</router-view>
</div>
</template>
I also have some AJAX calls in my created() method, which seem to be triggered every time I load a new page via the router. Is there any way to structure things so that my created() method only gets called once when the application loads, not every time a new page within the router loads?
One approach will be using Navigation Guards when you create a logic to determinate when to make your Ajax calls.
Other will be using Vuex, and create a state object to manage the Ajax calls, dispatch an event when the compontent had been loaded before, and bind a computed property to a getter that will contain the value if that component has been loaded previously.
Solution was a lot simpler than I thought:
The App.vue page was using a href links hard-coded to each route.
If you switch to using
<router-link to="path to your route">text here</router-link>
instead, everything works as normal - but Vue doesn't reload the App.vue component!

How to get the parent template component in Vue

I know in vue, I can use this.$parent to get the upper component in the vdom tree. But I'm expecting something different: to get the component that rendered the current component.
For instance, I have a component (named comp-container) with template:
<template>
<comp-a>
<comp-b></comp-b>
</comp-a>
</template>
And in comp-b the $parent would be an instance of comp-a not comp-container which I'm expecting.
My current aproach is traversing up with the $parent attribute until I find comp-b exists in $options.components. This method is working for now but seems quite ugly and breaks if comp-b is a globaly registered component. Is there an official way to do this?
Passing the parent template component via props as <comp-b :container="this"></comp-b> may do the job, but it's too verbose to be liked.
I'm not sure about the exact use case, but basically if there are slots involved (which I almost assume, because otherwise $parent will work fine), you can find the rendering component at:
this.$slots.default[0].context;
Basically, the context property of a slot is the rendering context (rendering component - i.e. the component who's template the component was rendered in).
Only tested with Vue 2

Vue component not updating after parent state change

I have Vue component which receives json data from props, after this render child components using v-for and pass this data as prop. Everything works fine until i try to remove one item from this list, when i remove it, it removes element incorrectly. In vue devtools i see that parent receives data correctly but not renders it properly. can anyone help me?
here is my code: https://gist.github.com/giokaxo/3d291b9b7b8ef97f81dc83799c430302
Use "key" attribute when rendering elements using v-for, for example:
<p v-for="(product, index) in order.products" :key="i">..</p>
The relevant documentation is here:
You can directly use v-for on a custom component, like any normal
element:
<my-component v-for="item in items" :key="item.id"></my-component>
In 2.2.0+, when using v-for with a component, a key is now required.
However, this won’t automatically
pass any data to the component, because components have isolated
scopes of their own. In order to pass the iterated data into the
component, we should also use props:
<my-component
v-for="(item, index) in items"
v-bind:item="item"
v-bind:index="index"
v-bind:key="item.id">
</my-component>
The reason for not automatically injecting item into the component is because that makes the component
tightly coupled to how v-for works. Being explicit about where its
data comes from makes the component reusable in other situations.
And here:
When Vue is updating a list of elements rendered with v-for, it by
default uses an “in-place patch” strategy. If the order of the data
items has changed, instead of moving the DOM elements to match the
order of the items, Vue will simply patch each element in-place and
make sure it reflects what should be rendered at that particular
index.
...
To give Vue a hint so that it can track each node’s identity, and thus
reuse and reorder existing elements, you need to provide a unique key
attribute for each item. An ideal value for key would be the unique id
of each item.