how to change styles depending of true/false in vuejs - vue.js

I'm trying to change the style if one of the classes returns true.
My template-
<div
class=""
:class="{
' green': visibleComponent != 'orders',
' opacity-25 ': visibleComponent == 'orders',
}"
#click="orders"
>
<div class="">
Orders
</div>
</div>
Any help on how do I go about this?

Do this;
<div
:class="`${visibleComponent !== 'orders' ? 'green' : 'opacity-25'}`"
#click="orders"
>

I assume you talking about Conditional Rendering
this offical sample code should be clear about how to use v-if
<script>
export default {
data() {
return {
awesome: true
}
}
}
</script>
<template>
<button #click="awesome = !awesome">toggle</button>
<h1 v-if="awesome">Vue is awesome!</h1>
<h1 v-else>Oh no 😢</h1>
</template>

this is how u do it:
<div class="anyclass" :class="dynamicClass" #click="orders">
<div class="">
Orders
</div>
</div>
<script setup> // Composition API
const dynamicClass = computed(() => {
return {
'green': visibleComponent != 'orders',
'opacity-25 ': visibleComponent == 'orders',
}
})
// Options API
export default {
computed: {
dynamicClass() {
return {
'green': visibleComponent != 'orders',
'opacity-25 ': visibleComponent == 'orders',
}
}
}
}
</script>

Assuming you have already defined visibleComponent in your data object or as a ref() with Vue3, you could use a ternary operator inline with a dynamic class binding. This is most similar to what you are showing in your code already.
If you are unfamiliar with ternary operators, it is basically an if/else statement using shorthand. condition ? ifConditionTrue : ifConditionFalse This format works very nicely with Vue dynamic class bindings.
<div
:class="
visibleComponent
? visibleComponent != 'orders' && 'green'
: visibleComponent == 'orders' && 'opacity-25'
">
</div>
This first checks if the visibleComponent property has been assigned a value. Then if that value is not 'orders', the green class will bind to the div. Else if the value is 'orders', the opacity-25 class will bind.

Related

How to fire an event in mount in Vuejs

I have a sidebar that you can see below:
<template>
<section>
<div class="sidebar">
<router-link v-for="(element, index) in sidebar" :key="index" :to="{ name: routes[index] }" :class='{active : (index==currentIndex) }'>{{ element }}</router-link>
</div>
<div class="sidebar-content">
<div v-if="currentIndex === 0">
Profile
</div>
<div v-if="currentIndex === 1">
Meine Tickets
</div>
</div>
</section>
</template>
<script>
export default {
mounted() {
EventBus.$on(GENERAL_APP_CONSTANTS.Events.CheckAuthentication, () => {
this.authenticated = authHelper.validAuthentication();
});
console.log()
this.checkRouter();
},
data(){
return {
currentIndex:0,
isActive: false,
sidebar: ["Profile", "Meine Tickets"],
routes: ["profile", "my-tickets"],
authenticated: authHelper.validAuthentication(),
}
},
computed: {
getUser() {
return this.$store.state.user;
},
},
methods: {
changeSidebar(index) {
this.object = this.sidebar[index].products;
this.currentIndex=index;
},
checkRouter() {
let router = this.$router.currentRoute.name;
console.log(router);
if(router == 'profile') {
this.currentIndex = 0;
} else if(router == 'my-tickets') {
this.currentIndex = 1;
}
},
},
}
</script>
So when the link is clicked in the sidebar, the route is being changed to 'http://.../my-account/profile' or 'http://.../my-account/my-tickets'. But the problem is currentIndex doesn't change therefore, the content doesn't change and also I cannot add active class into the links. So how do you think I can change the currentIndex, according to the routes. Should I fire an event, could you help me with this also because I dont know how to do it in Vue. I tried to write a function like checkRouter() but it didn't work out. Why do you think it is happening? All solutions will be appreciated.
So if I understand correctly, you want currentIndex to be a value that's based on the current active route? You could create it as a computed property:
currentIndex: function(){
let route = this.$router.currentRoute.name;
if(router == 'profile') {
return 0;
} else if(router == 'my-tickets') {
return 1;
}
}
I think you could leverage Vue's reactivity a lot more than you are doing now, there's no need for multiple copies of the same element, you can just have the properties be reactive.
<div class="sidebar-content">
{{ sidebar[currentIndex] }}
</div>
Also, you might consider having object be a computed property, something like this:
computed: {
getUser() {
return this.$store.state.user;
},
object() {
return this.sidebar[currentIndex].products;
}
},
Just use this.$route inside of any component template. Docs .You can do it simple without your custom logic checkRouter() currentIndex. See simple example:
<div class="sidebar-content">
<div v-if="$route.name === 'profile'">
Profile
</div>
<div v-if="$route.name === 'my-tickets'">
Meine Tickets
</div>
</div>

Element in VueJS template reference self

I have a component which will have many div elements, with only one having an 'active' class on click. I'm trying to bind the 'active' class if a variable 'activeSlide' is equal to the element.
v-bind:class="{ 'active': activeSlide === ?? }"
I'm just not sure what the ?? should be. I haven't been able to find anything that tells how an element can reference itself. Or maybe there is a better approach?
My Code in .vue component file:
<template>
<div v-on:click="show" v-bind:class="{ 'active': activeSlide === ?? }"></div>
</template>
<script>
export default {
data() {
return {
activeSlide: null
}
}
methods: {
show: function(e) {
this.activeSlide = e.target;
}
}
}
</script>
I would assume that the ?? is intended to be something uniquely identifying to the active element.
<template>
<div v-on:click="show('Slide1')" v-bind:class="{ 'active': activeSlide === 'Slide1' }"></div>
<div v-on:click="show('Slide2')" v-bind:class="{ 'active': activeSlide === 'Slide2' }"></div>
</template>
<script>
export default {
data() {
return {
activeSlide: null
}
}
methods: {
show: function(value) {
this.activeSlide = value;
}
}
}
</script>
So basically when you click the slide it will change the activeSlide property to the value passed into the v-on:click method.
There are more dynamic ways of doing this such as if you were to loop through a series of elements you could then compare the active index to the index of the element instead of explicitly saying Slide1 or Slide2.
Here is a dynamic example
<template>
<div v-for="slide in slides" :key="slide.id" v-on:click="show(slide.id)" v-bind:class="{ 'active': activeSlide === slide.id }"></div>
</template>
<script>
export default {
data() {
return {
activeSlide: null
}
}
methods: {
show: function(value) {
this.activeSlide = value;
}
}
}
</script>
so you can use any available data in the iteration to compare, just pass in slide.whatever to the method and set the class to equal the same thing.

Filter in AngularJS converted to VueJS

I used AngularJS for a long time and now I'm making the switch to VueJS, but I can't figure out why this simple Angular code isn't easily converted to in VueJS.
This is a search-field:
<input type="search" ng-model="searchFor.$">
And then I'm using it like this:
<ul>
<li ng-repeat="user in users | filter: search">
{{ user.email }}
</li>
</ul>
This filter is an easy thing and search in everything in the 'users'-array, so not even the mailaddresses.
How can I do this easily in Vue? Can't figure it out, only can find solutions where you define the specific column it should look.
In this case you must use a computed property that returns a filtred array. The computed array will recursively search in each string properties of your user.
Here is an example
new Vue({
el: '#app',
data() {
return {
search : '',
users : [{name : "John Doe", email : "xerox#hotmail.us"}, {name : "Jane Doe"}],
}
},
computed : {
filteredUsers() {
if (!this.search) return this.users
var find = function(object, search) {
for (var property in object) {
if (object.hasOwnProperty(property)) {
if (typeof object[property] == "object"){
find(object[property]);
} else if (object[property].includes !== undefined){
if (object[property].includes(search)) return true;
}
}
}
return false;
}
return this.users.filter(user => {
return find(user, this.search)
})
}
}
})
<script src="https://npmcdn.com/vue/dist/vue.js"></script>
<div id="app">
<input type="text" v-model="search" placeholder="Filter users">
<p v-show="!filteredUsers.length">No results</p>
<ul>
<li v-for="user in filteredUsers">{{user.name}}, email : {{user.email || 'N/A'}}</li>
</ul>
</div>

Conditionally adding a CSS class in Vue

Just started with Vue so I can't get this simple thing working. All I'm trying to do is toggle a class based on a condition.
<button type="button"
class="btn dropdown-toggle"
v-bind:class="{ btn-default: (search.category != 'all') }">
{{ filterCategoryText || 'Category' }}
</button>
Firstly, as you discovered, you should probably remove the duplicate class definition. You can mix static and dynamic classes in the bound class definition. (If you leave the duplicate there it still works, though)
Then, you have the choice...
Object syntax
// property names will be in the class list if their values are truthy
:class="{
'btn-default': search.category != "all",
'btn' : true,
'dropdown-toggle' : true
}"
Array syntax
// an item in the array becomes a class in the class list
:class="[
search.category != 'all' ? 'btn-default':'',
'btn',
'dropdown-toggle'
]"
Simple expression
// if you only have one item, just use a simple expression
:class="search.category != 'all' ? 'btn-default':''"
Docs are here
You still could have used Object syntax for the class binding. I guess the code in you example didn't work because you didn't wrap object property name with quotes. Moreover, you have at least three options here. In such case I would always stick with objects if possible as it's usually more readable. Take a look:
new Vue({
el: '#app',
data: {
red: 'nope',
},
methods: {
toggle() {
this.red = this.red === 'yes' ? 'nope' : 'yes';
}
},
})
.is-bold {
font-weight: 900;
}
.is-red {
color: red;
}
<script src="https://unpkg.com/vue"></script>
<div id="app">
<p class="is-bold" :class="{'is-red': red === 'yes'}">
Option
</p>
<p class="is-bold" :class="red === 'yes' ? 'is-red' : ''">
Option 1
</p>
<p class="is-bold" :class="[red === 'yes' ? 'is-red' : '']">
Option 2
</p>
<button #click="toggle">Toggle class</button>
</div>
jsfiddle: https://jsfiddle.net/oniondomes/06bg516h/
Figured it:
<button type="button"
:class="[(search.category) ? '' : 'btn-default', 'btn dropdown-toggle']"
{{ filterCategoryText || 'Category' }}
</button>
try this instead of v-bind:class="{ 'btn-default': search.category != 'all' }"

template v-if="main", not working with return this.$route.path.indexOf('/') === 0 in computed "main"

works with my other routes like "/dashboard", etc, but is appearing in all routes. I basically want this template to only appear when the url is "/". Have tried it throughout my project and just plum doesn't work. PLease help and thank you!! for any suggestions.
<template v-if="main">
<div id="accordion-nav">
<div class="accordion-panels">
Dashboard <i class="fa fa-caret-right" aria-hidden="true"></i>
</div>
<div class="accordion-panels">
Shifts <i class="fa fa-caret-right" aria-hidden="true"></i>
</div>
<div class="accordion-panels">
Other <i class="fa fa-caret-right" aria-hidden="true"></i>
</div>
</div>
</template>
<script>
export default {
name: 'accordion-nav',
computed: {
main: function () {
return this.$route.path.indexOf('/') === 0
}
}
}
</script>
<style scoped>
</style>
Setup the v-if in the sidebar component itself
'<template>
<div id="sidebar" class="sidebar"
:class="{ isOpen: isOpen }">
<div class="sidebar-opener"
#click="toggle">{{openerText}}</div>
<accordion-nav v-if="main"></accordion-nav>
<accordion></accordion>
</div>
</template>'
<script>
export default {
data () {
return {
}
},
computed:{
main(){
return this.$route.path === '/'
}
}
}
</script>
With this.$route.path you get a string that equals the path of the current route resolved as absolute path in any component of your app.
So you can use this to check whether you are in the root route using:
this.$route.path === '/'
Here is the example fiddle
Use v-if="main" as a method v-if="main()" instead of a computed property
methods: {
main: function () {
return this.$route.path.indexOf('/') === 0
}
Methods do such complex updates much better than computed properties. Computed = lazy