How to render conditional html - vue.js

I have to render some html code based on conditions like:
if (status == 'pending') {
// render <span class='pending'>pending</span>
} else {
// render <span class='complete'>complete</span>
}
I would like a better way to to this.
Is ok to use computed properties to render html ?

If you have a bunch of different statuses, then you can have something like this in the template:
<span v-if="status" :class="status">{{ status }}</span>
The span will be displayed when status is truthy and the class and inner text will be set to the status value.

You may looking for v-if
<span v-if=“status==‘pending’” >....
https://v2.vuejs.org/v2/guide/conditional.html

You can use v-if directive:
<span class='pending' v-if="status === 'pending'">
pending
</span>
<span class='complete' v-else>
complete
</span>
See more details: https://v2.vuejs.org/v2/guide/conditional.html

Related

Vue Bootstrap, how to interact with plus/minus icon on dynamic generated collapse content separately

I have a VueJS view that creates collapsed contents using Bootstrap Vue Collapse Component.
The data is dynamic and can contains hundreds of items, which is why you see in the code below it was created via a v-for loop in Vue.
<div class="inventory-detail" v-for="(partNumberGroup,index) in inventory" :key="index" >
<b-button block v-b-toggle="partNumberGroup.partNumber" v-bind:id="partNumberGroup.partNumber" variant="primary"
#click="(evt) =>{isActive = !isActive && evt.target.id == partNumberGroup.partNumber}">
<i v-bind:id="partNumberGroup.partNumber" class="float-right fa" :class="{ 'fa-plus': !isActive, 'fa-minus': isActive }"></i>
{{ partNumberGroup.partNumber }}
</b-button>
<div class="inventory-detail__card" v-for="item in partNumberGroup.items">
<b-collapse v-bind:id="partNumberGroup.partNumber" >
<b-card>
<!--Accordion/Collapse content -->
</b-card>
</b-collapse>
</div>
</div>
This works fairly well in that I can individually expand and collapse each content separately. However, the one issue I'm facing is each time I click the icon fa-minus (-) orfa-plus (+), all of them changed as per the images below.
Any tips on how I should implementing this? in my code I tried the dynamic CSS class switching but I still lack the ability to switch on specific element.
I feel like the solution to this is to somehow conditionally apply dynamic CSS class or somehow able to use the attribute 'aria-expanded'.
You can try something like this. Whenever somebody clicks on the icon, set its index as activeIndex (using the setActiveIndex method). Then you can set the class accordingly by comparing the activeIndex with current index
<i
#click="setActiveIndex(index)"
v-bind:id="partNumberGroup.partNumber"
class="float-right fa"
:class="{ 'fa-plus': !isActive(index), 'fa-minus': isActive(index) }">.
</i>
then in the script part:
...
data() {
return {
activeIndex: -1
}
},
methods: {
/* set active index on click */
setActiveIndex(index) {
this.activeIndex = index;
},
/* check if index is active or not */
isActive(index) {
return index === this.activeIndex;
}
}

How to use v-if and v-else on vue.js?

I try this code:
<h1 v-if="2 === 1">Yes</h1>
<h1 v-else>No</h1>
but not work and show both of them tags <h1>
How to use v-if and v-else on vue.js?
If you don't need to remove the element from the DOM and the condition is simply to toggle some text - you could just use a ternary operator. See below
<h1 v-text="2 === 1 ? 'Yes' : 'No'" />

Vuejs - Event delegation and v-for context reference

I'm using the following snippet to render a list:
<div #click.prevent="myhandler($event)"><!-- Delegated event handler-->
<div class="tasks" v-for="(task, subName) in step.tasks">
<button type="button">
{{ task.caption }}
</button>
<span> {{ task.callableName }} </span>
</div>
</div>
methods: {
myhandler(e){
// Event target may be a button element.
let target = e.target;
// …
// Let's assume we know 'target' is a button element instance.
// I wish I could have access to the v-for item ("task") which is associated in some ways to the button that was clicked.
// let the_task_reference = ?;
}…
Is there a clean way so that I could reach the v-for scope specific task related to that button?
Thank you.
An alternative would be to store the index of the task on the button.
<div class="tasks" v-for="(task, index) in step.tasks">
<button type="button" :data-index="index">
{{ task.caption }}
</button>
<span> {{ task.callableName }} </span>
</div>
And in your handler get the task using the index.
myhandler(evt){
const task = this.step.tasks[evt.target.dataset.index]
...
}
Example.
If you had something stronger like an id, that would be even better.
Not Recommended
There is a hidden property, __vue__ that is added to Vue and Component root elements. Were you to iterate over a component, you would be able to do something like in this example.
I wouldn't recommend that approach because it relies heavily on Vue internals that could change from version to version, but it's there today.
The most straight-forward solution would be to put the event handler on the same div as the v-for directive and just pass in the task variable:
<div
class="tasks"
v-for="(task, subName) in step.tasks"
#click.prevent="myhandler(task, $event)"
>
<button type="button">{{ task.caption }}</button>
<span>{{ task.callableName }}</span>
</div>
If you really need to use an event handler on a parent element, you could keep track of the clicked task via a component property and add an extra click handler to the div with the v-for directive:
<div #click.prevent="myhandler($event)"
<div
class="tasks"
v-for="(task, subName) in step.tasks"
#click="clickedTask = task"
>
<button type="button">{{ task.caption }}</button>
<span>{{ task.callableName }}</span>
</div>
</div>
You would need to add a clickedTask property:
data() {
return {
clickedTask: null,
}
}
And then in the handler you could refer to the task via this.clickedTask.

v-if and v-else inside of v-for for different text rendering

I can't find a way to choose different options for rendering text inside of v-for. Is it possible or do I need to structure the logic differently to do something like the code below?
<template>
<ul v-show="showNotifications">
<li v-for="notification in notifications">
// if notification.type = 'friend request'
New friend request from {{ notification.name }}
// else
New notification from {{ notification.name }}
</li>
</ul>
</template>
Notification is a array of objects with data like name and notification type.
Use another template element like following (not tested)
<template>
<ul v-show="showNotifications">
<li v-for="notification in notifications">
<template v-if="notification.type == 'friend request'">
New friend request from {{ notification.name }}
</template>
<template v-else>
New notification from {{ notification.name }}
</template>
</li>
</ul>
I did what Xymanek said and that isn't work for me completely, I also added a method like this since I realize the component is reactive to the variable in "v-for", in this case "notifications"
forceReload(){
this.files.push(fakeNotification);
this.files.pop();
}
as can see this just force the v-for to "re-render" by pushing a fake object to the array.
you can call this method just after the value of "notification.type" change.

vue.js conditional rendering of an attribute [duplicate]

This question already has answers here:
VueJS conditionally add an attribute for an element
(11 answers)
Closed 4 years ago.
I'd like to learn what is the best way to conditionally render an HTML attribute in Vue.js. For example, add data-toggle="tooltip" if there is a tooltip message for current instance.
The code I have now:
<span
:data-toggle="!!col.col_spec.tooltip ? 'tooltip' : ''"
:title="col.col_spec.tooltip"
>
{{ col.col_spec.title }}
</span>
Though, I don't like the 2nd line much… Even if I use computed property here, I'd prefer not to have data-toggle attribute at all, when there is no tooltip to display.
Very so elegant solution:
<span
:data-toggle="!!col.col_spec.tooltip ? 'tooltip' : false"
:title="col.col_spec.tooltip"
>
{{ col.col_spec.title }}
</span>
Yes, yes, yes, it's just necessary that there is not an empty string, but a Boolean false
Something like:
<span ref="column">
{{ col.col_spec.title }}
</span>
And in Vue:
mounted(){
if (this.col.col_spec.tooltip){
this.$refs.column.setAttribute("data-toggle", this.col.col_spec.tooltip);
}
}
A bit late, but here is my take on it:
HTML:
<span
:data-toggle="tooltip"
:data-original-title="tooltipTitle"
>
{{ tooltipTitle }}
</span>
Vue:
methods: {
tooltipTitle: function() {
var title = this.col.col_spec.title;
if (!!title) return title;
return false;
}
}
This will remove the "data-original-title" attribute if there is none to display, consequently removing the tooltip altogether. You must use "data-original-title" instead of just "title" because Bootstrap will automatically add it once you initialise the "title" attribute, and changing "title" to false will not remove the "data-original-title".
Here's another working but not so elegant solution:
<span v-if="!!col.col_spec.tooltip" data-toggle="tooltip" >
{{ col.col_spec.title }}
</span>
<span v-else >
{{ col.col_spec.title }}
</span>