Vue v-bind:class doesn't work on default truthiness check - javascript

So I have a simple v-bind:class like this: <div v-bind:class="{ showBranding: brandingEnabled }">BRANDING</div>
In my data, brandingEnabled is true and can be changed to false. Changing it to false does no remove the class.
It works perfect if I do this: <div v-bind:class="{ showBranding: (brandingEnabled == 'true') }">BRANDING</div>
Could this be an issue with my booleans being treated as strings? I have tried setting them (in my Vue data) to true, rather than "true" but that doesn't change anything either.
I have also tried setting the data to type: Boolean via props but to no avail.
I would really rather have it working with the simple syntax if possible...
Any help would be appreciated!

If showBranding is a CSS class, you have to add single quote around your css className, like this:
<div :class={'showBranding': brandingIsEnabled}>
// content
</div>
Then your class has to be inside a style tag into your component like this:
<style scoped>
.showBranding {
// content
}
</style>
Check also if your brandingIsEnabled data is inside your script tag like this:
<script>
export default {
data() {
return {
brandingIsEnabled: true
}
}
}
</script>
This example uses the single component syntax.

new Vue({
el: '#br',
data: {
showBranding: 'brandingClass',
brandingEnabled:true
}
});
CSS Code
.brandingClass{
display:none
}
html code
<div id="br">
<div :class="{ showBranding:brandingEnabled }">BRANDING</div>
</div>

Related

How to add conditional styling in Vue.js using a method?

I want to add conditional styling in a child component based on the values of a prop passed from the parent component.
This a working example of conditional styling:
<li v-bind:class="[booleanValue ? 'stylingClassOne' : 'stylingClassTwo']"
but this is only applicable for when my styling is based on a single variable which can only be of two values (true/false).
I want to achieve conditional styling based on a variable that can take multiple values. Assume I pass a string from my parent component to my child component stylingDecider, which can be of values stylingClassOne, stylingClassTwo, stylingClassThree.
Therefore I want to do the following:
<li v-bind:class="getStylingClass(stylingDecider)"> but this does not work. The reason I need a method to decide what the styling is because there will be some other processing going on in the that will return a class based on said processing, so I can't just use <li v-bind:class="stylingDecider".
What am I doing wrong? Please advise, thanks.
I am using Vue 3 and bootstrap-vue 3.
I just created a working code snippet:
Vue.component('child', {
props: ['dynamicstyle'],
template: `<ul><li v-bind:class="getStylingClass(dynamicstyle)">Hello !!</li></ul>`,
methods: {
getStylingClass(stylingDecider) {
return stylingDecider;
}
}
});
var app = new Vue({
el: '#app',
data: {
stylingDecider: 'stylingClassTwo'
}
});
.stylingClassTwo {
background: green;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<child :dynamicstyle="stylingDecider">
</child>
</div>

Function Return HTML

I have function who return html
renderSuggestion(suggestion) {
const query = this.query;
if (suggestion.name === "hotels") {
const image = suggestion.item;
return this.$createElement('div', image.title);
} else {
let str = suggestion.item.name;
let substr = query;
return this.$createElement('div', str.replace(substr, `<b>${substr}</b>`));
}
},
But<b> element not render in browser as html element. Its display like string...
How I display this <b> element?
Tnx
That is because when you provide a string as the second argument of createElement, VueJS actually inserts the string as a text node (hence your HTML tags will appear as-is). What you want is actually to use a data object as the second argument, which give you finer control over the properties of the created element:
this.$createElement('div', {
domProps: {
innerHHTML: str.replace(substr, `<b>${substr}</b>`)
}
});
Of course, when you are using innerHTML, use it with caution and never insert user-provided HTML, to avoid XSS attacks.
You can also create a component and use v-html to render the output.
Declare props for your inputs:
export default {
props: {
suggestion: Object,
query: String
}
};
And use a template that uses your logic in the template part
<template>
<div class="hello">
<div v-if="suggestion.name === 'hotels'">{{suggestion.item.title}}</div>
<div v-else>
<div v-html="suggestion.item.name.replace(this.query, `<b>${this.query}</b>`)"/>
</div>
</div>
</template>
This allows for greater flexibility when using more complex layouts.
A working example here
Provide more detail(possibly a picture) of how it's not showing. Consider using a custom CSS class to see the div and what's happening to it.
bold {
border-style: black;
font-weight: bold;
}
then just use the "bold" class instead of "b".

Execute function when clicking on DOM element in Vue.js

I want to execute a function when I'm clicking on elements in the dom with a specific class. It just doesn't work, but I'm also receiving any error. This is my
code snippet:
methods: {
initTab: function(){
document.querySelectorAll('.element').onclick = this.nextTab()
}
},
mounted: function () {
this.initTab()
}
I
I want to execute the function every time I click on the element. Would be very thankful if anybody could help me :)
There's very little need (if at all) for document.querySelectorAll() in a Vue app.
In this situation you can take advantage of delegation:
<div #click="onClick">
<!-- Clicks on any element inside this div will be handled -->
</div>
methods: {
onClick(e) {
if (e.target.classList.contains('element')) {
// Handle the click
}
}
}
Add #click="initTab($event)" to the document or template root, that allows you to track every click event on your template, that way you could put your logic to the elements which have only .element class name. If you're using it in a component you could do : <template> <div #click="initTab($event)"> ... </div> </template>
var app = new Vue({
el: '#app',
data() {
return {
}
},
methods: {
nextTab(){
console.log("You clicked on an element with class name =element")
},
initTab(event){
let targetClassNames=event.target.className.split(" ");
targetClassNames.filter(e=>{
if(e==="element"){
this.nextTab();
}
});
}
},
mounted() {
}
})
#app{
height:100px;
display:grid
}
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.17/dist/vue.js"></script>
<div id="app" #click="initTab($event)">
<button class="element">1</button>
<button class="element btn">2</button>
<button class="btn">3</button>
<button class="element btn-primary">4</button>
<button class="btn elementory">5</button>
</div>
You're trying to use general javascript logic within vue. This is not often a good idea.
What I do in such cases is something like this:
<component-name #click="nextTab(tabName)"></component-name>
However, in a v-for loop you can also do something like this:
<ul v-for="tab in tabs">
<li #click="nextTab(tab)">{{tab}}</li>
</ul>
That way in methods you only need:
methods: {
nextTab: function(tab){
// whatever it is you want to do here
}
},
And you won't need mounted at all.
Conclusion: try to avoid repetition by creating components or elements (like li) that repeat - not by trying to add an event-listener to a class.

How can I add dynamically an attribute with VueJS?

I know I can set a value to an attribute dynamically with v-bind, however I would like add dynamically the attribute, not the value. Something like this (although this is not valid):
<a
:href="url"
{{ downloadable ? 'download' : null }}
class="link"
#click="onClick">
{{ text }}
</a>
Note: I'm not using JSX
I was thinking about using $attrs (https://v2.vuejs.org/v2/api/#vm-attrs) but it's read only.
Is there a way to do this on Vue?
Solution:
JavaScript:
new Vue({
el: '#app',
data() {
return {
msg: 'Inspect element to test',
downloadable: true
}
},
computed: {
dynamicAttribute() {
if(!this.downloadable) {
return null
}
return { [`download`]: "link or w/e" }
}
}
})
HTML:
<a v-bind="dynamicAttribute">{{msg}}</a>
If you want it to look like:
<a ... download="value">text</a>
with download visible only when downloadable is true, you can actually do it using v-bind:
https://jsfiddle.net/eywraw8t/274691/
You can check if it works by changing downloadable to true or false and inspecting the element.
Other than boolean attribute you cannot dynamically add or set attribute using Vue.js. For example -
v-bind:disabled="isActive"
If isActive is true, then the attribute disabled will be added to the element, otherwise it will be removed. This mechanism doesn't work for other attribute which are not boolean.
You can use Javascript for that purpose -
element.setAttribute('attributeName', 'value');

Angular 6 [ngClass] not working with boolean in component.js

What I'm trying to do is hide text when ngState is true. When a certain element is clicked, that state is set to true. The [ngClass] should then add the hide class and hide the text. This first snippet is from the component.ts which outlines the boolean variable and the function which sets it to true.
export class MainMenuComponent implements OnInit {
ngState = false;
constructor() {
}
newGame(){
this.ngState = this.ngState === true ? false : true;
console.log(this.ngState);
}
}
This next snippet is the component html
<canvas id='sparkCanvas'></canvas>
<div class="menuBox">
<div class="title" [ngClass]="{'hide': ngState}">Dark Shards</div>
<div class="optContainer">
<ul>
<li *ngFor="let opt of opts" class="{{opt.class}}" [ngClass]="{'hide': ngState}" (click)="opt.f()">{{opt.n}}</li>
</ul>
</div>
</div>
and here is the hide class below
.hide{
opacity: 0;
}
When I replace [ngClass]="{'hide': ngState}" with [ngClass]="{'hide': true}"
It will then work as intended. What am I not understanding here?
Here is a link to my code with a working example:
https://stackblitz.com/edit/angular-fg48ro?file=src%2Findex.html
Try without Quote
<li *ngFor="let opt of opts" class="{{opt.class}}" [ngClass]="{hide: ngState}" (click)="opt.f()">{{opt.n}}</li>
EDIT
When i see your code, the issue is not related to angular, but with javascript context, you need to specifiy the context of this like
' f: this.newGame.bind(this),'
DEMO

Categories

Resources