How to use ternary operator in transition using javascript in vuejs? - vue.js

I'm trying to achieve a very basic slide between h2, using vuejs and gsap. I need 2 different types of transitions, based on the direction (next and previous slide). To obtain a compact code, I used the ternary operator ?:
<transition :css="false" #enter="direction ? enterNext : enterPrev">
<h2 :key="currentPage.id">
<NuxtLink
:to="currentPage.to"
:title="currentPage.longTitle"
exact-active-class="is-active"
>
{{ currentPage.title }}
</NuxtLink>
</h2>
</transition>
If I use 2 div with a v-if / v-else syntax, it works well. What am I doing wrong here ? Do I need to format differently what the ternary returns ?

#enter is an event handler. You can pass a function name here like #enter="enterNext" (that's what you probably did before) or valid JS code fragment like #enter="enterNext($event)" (function call)
Your ternary doesn't return anything as it is missing return statement.
Anyway what you probably want is this: #enter="direction ? enterNext() : enterPrev()"

Related

Arithmetic inside vue js expressions

I have some html code and i am displaying some value like this
<h4 class="text-dark pull-right">
<strong>USD {{item.addbedrooms[0].the_price_per_night }}</strong>
</h4>
I got the displayed value from a web service that only allows one to display the data like above. Is there a way i can do some arithmetic on the expression like
<strong>USD {{item.addbedrooms[0].the_price_per_night }} x {{duration}} </strong>
This produces USD 27*1 and not a multiplication. Is it possible to multiple at this level?
Anything you output from {{ }} is converted to a string in the template. You can do it by having the arithmetic operation within the {{ }}
<strong>USD {{item.addbedrooms[0].the_price_per_night * duration}} </strong>
But I would recommend that you optimize your array via a computed and not add any methods into your template.

How to use `v-if` and `v-for` on the same element?

Hi I'm trying to figure out how to use v-if on a iterated element which also uses v-for. I need to check if the current element has any of a series of classes, which are numbers.
so the classes of each article would be:
<article class="post-item post-guide 12 22 19 30 55">...
this is the HTML that renders all:
<article v-if="showIfHasClass" :class="'post-item post-guide ' + guide.categories.toString().replace(/,/g, ' ')"
v-for="(guide, index) in guides" :key="index">
<header>
<h1 class="post-title">
{{ guide.title.rendered}}
</h1>
</header>
</article>
I have tried with methods that check the class of all elements, that works, but i'm trying to use a clean Vue built-in solution with v-if without success, i'm not able to retrieve the class of this in a successful way.
Should showIfHasClass be a computed property? I have tried with that too... but it seems, I'm missing something along the way.
my data I have to check against is an array:
data:{
guides: [...]
selectedCategories: [1, 22, 33, 100, 30];
}
or maybe it is better to directly loop over the guides and check if they have the selectedCategory or not, then remove the element from the guides data array?
What is more effective?
Besides the option to create an additional filtered computed (effectively eliminating the need to use v-for and v-if on the same element), you also have a template level way of dealing with such edge-cases: the <template> tag.
The <template> tag allows you to use arbitrary template logic without actually rendering an extra element. Just remember that, because it doesn't render any element, you have to place the keys from the v-for on the actual elements, like this:
<template v-for="(guide, index) in guides">
<article v-if="isGuideVisible(guide)"
:key="index"
class="post-item post-guide"
:class="[guide.categories.toString().replace(/,/g, ' ')]">
<header>
<h1 v-text="guide.title.rendered" />
</header>
</article>
</template>
isGuideVisible should be a method returning whether the item is rendered, so you don't have to write that logic inside your markup. One advantage of this method is that you can follow your v-if element with a fallback v-else element, should you want to replace the missing items with fallback content. Just remember to also :key="index" the fallback element as well.
Apart from the above use-case, <template> tags come in handy when rendering additional wrapper elements is not an option (would result in invalid HTML markup) (i.e: table > tr > td relations or ol/ul > li relations).
It's mentioned here as "invisible wrapper", but it doesn't have a dedicated section in the docs.
Side note: since you haven't actually shown what's inside guide.categories, I can't advise on it, but there's probably a cleaner way to deal with it than .toString().replace(). If guide.categories is an array of strings, you could simply go: :class="guide.categories".
I think the most Vue way is to create a computed property with filtered items from selected categories, then use that in v-for loop (the idea is to move the business logic away from template).
computed: {
filteredItems(){
return this.guides.filter(e => this.selectedCategories.includes(e.category))
}
}
Also, as a note, it is not recommended to use v-if and v-for on the same element, as it may interfere with the rendering and ordering of loop elements. If you don't want to add another level of nesting, you can loop on a 'template' element.
<template v-for="item in items">
// Note the key is defined on real element, and not on template
<item-element v-if='condition' :key="item.key"></item-element>
</template>

How to access URL queries that have hyphen in them vue js

I am trying to display a v-alert conditionally based on whether the payment-successful query parameter is true or false.
Here's what I tried:
<v-alert v-if="$route.query.payment-successful == true" type="success" dismissible>
I'm an alert
</v-alert>
But it does not seem to work since the alert is not being displayed when I set the query param. I also tried putting the $route.query.payment-successful between quotes but it did not work either.
Try out to use [] squared brackets accessor :
<v-alert v-if="$route.query['payment-successful'] == true"></v-alert>

vue multiple tag 'template' in one single file component

I am work in company with big frontend team, and guys use multiple template tag in single file components. Before that I never see something like this, for me it bad practice. But head developers think that I am stuped, when I ask about that.
Can some one please explain me, when I must use it and why? and if it possible please give link to vue documentation.
And yes, we use vuetify.
example:
<template>
<VContainer>
<VRow>
<VCol>
<h2>
{{ title }}
</h2>
<p>
{{ subtitle }}
</p>
</VCol>
</VRow>
<Share />
<template v-if="p.length > 0">
<VRow>
<VCol>
{{ text }}
</VCol>
</VRow>
<VDivider/>
</template>
<template v-for="(t, index) in ts">
<VRow :key="index">
<VCol v-if="t.p.length > 0">
{{ text }}
</VCol>
</VRow>
<VDivider
v-if="index < t.length - 1"
:key="`divider-${index}`"
class="mx-3"
/>
</template>
</VContainer>
</template>
The <template> used here is just a way to handle loops or conditionals without inserting extra nodes into the DOM.
You could put the v-if or v-for directly on the <VRow> instead of on a <template> that wraps it, but sometimes that's undesirable -- if there are already other conditions there that you want to keep separate, or if you want to wrap multiple nodes in the same condition, as in your example where you have both a <VRow> and a <VDivider> contained in a single <template>.
It's not bad practice and has no undesirable performance effect at all. Your head developers should be better able to communicate that to you rather than calling you 'stupid'.
I think it does't matter use multiple template, We should not use div wrapper the condition render Component, the div will insert to DOM.
here is the official documemnt https://v2.vuejs.org/v2/guide/conditional.html#Conditional-Groups-with-v-if-on-lt-template-gt

Error if don't check if {{object.field}} exists

I have a question about checking if some field in object exists.
I want to print all categories which user has so I'm doing something like this:
<ul *ngIf="user.categories.length > 0" *ngFor="#category of user.categories">
<li>
{{category.name}}
</li>
</ul>
The reason? All the data are PROPERLY printed, but I'm getting an error in web console like this:
Cannot read property 'name' of null
But when I do something like:
<ul *ngIf="user.categories.length > 0" *ngFor="#category of user.categories">
<li *ngIf="category">
{{category.name}}
</li>
</ul>
Then all is okay.
Am I doing something wrong or maybe I have to check this every time? Have you ever had a problem like this one?
basic usage
Use the safe-navigation operator
{{category?.name}}
then name is only read when category is not null.
array
This only works for the . (dereference) operator.
For an array you can use
{{records && records[0]}}
See also Angular 2 - Cannot read property '0' of undefined error with context ERROR CONTEXT: [object Object]
async pipe
With async pipe it can be used like
{{(chapters | async)?.length
ngModel
With ngModel currently it needs to be split into
[ngModel]="details?.firstname" (ngModelChange)="details.firstname = $event"
See also Data is not appending to template in angular2
*ngIf
An alternative is always to wrap the part of the view with *ngIf="data" to prevent the part being rendered at all before the data is available to prevent the dereference error.