Vue.js - multiple condition class binding - javascript

What is the proper way to bind class to a tag based on multiple conditions?
Given this tag, it seems that when trying to write multiple conditions one is being overwritten by another.
<q-tr :props="props"
:class=["(props.row.Name=='Row Name 1' || props.row.Name=='Row Name 2')?'text-bold':'bg-white text-black', (props.row.Name=='Row Name 3')?'text-green':'bg-white text-black']
>
</q-tr>
So in the above example text-bold class is overwritten by bg-white text-black since the second condition is overriding the first class binding.
Is there a way to structure conditions in if, else if, else style in vue class binding?

Bind that class attribute to a computed property called myClass :
<q-tr
:class="myClass"
>
</q-tr>
computed:{
myClass(){
if(this.props.row.Name=='Row Name 1' ){
return 'text-bold';
}
else if( this.props.row.Name=='Row Name 3'){
return 'text-green';
}
else{
return 'bg-white text-black'
}
}
}

Related

Dynamically change Next.js style type for element

I am attempting to change the color of an element based off of the result from a function
//Example function
if ("123".includes("5")) {
color = "boldOrange"
} else {
let color = "boldGreen"
}
In my CSS, I have two classes, boldGreen and boldOrange. This is the tag:
<b className={styles.color}>(-3.44)</b>
How would I update the styling class based off of the function? I am using Next.js as my framework.
you can try with this:
<b className={"123".includes("5") ? styles.boldOrange : styles.boldGreen}>
(-3.44)
</b>

Are Vue 3 class bindings with variables required to be in-line?

Given the following HTML:
<template v-for="(child, index) in group">
<div :class="{'border-pink-700 bg-gray-100 ': selected === child.id}">
<div>Container Content</div>
</div>
</template>
Is there a way to move the class binding out of the HTML, given that it relies on a condition passed via the v-for loop (child.id)?
The docs mention being able to bind computed properties, but my understanding is that these don't accept arguments (and I haven't been able to get it to work that way).
You can use a method and pass the item to the method:
<div :class="classes(child)">
setup() {
...
const classes = (child) => {
return {
'border-pink-700 bg-gray-100': selected.value === child.id
}
}
return {
...
selected,
classes
}
}
If you were using Vue 2 or the Options API:
methods: {
classes(child) {
return {
'border-pink-700 bg-gray-100': this.selected === child.id
}
}
}
Be sure to avoid changing instance properties in the method, but reading is ok.

How to change display by document.getElementById inAngular

I have a scenario where I am generating dynamic elements with the data from backend some what like
<tr *ngFor="let data of datas" (click)="display(data.id)">
<div id="'full'+data.id" [style.display]=" active? 'block': 'none'">
</div>
</tr>
My Ts File
export class Component{
active=false;
display(id)
{
document.getElementById(`full${id}`).display="block";
}
}
What I want to do is something like above. I tried something like below but that doesn't work it throws error
Property 'display' does not exist on type 'HTMLInputElement'
import { DOCUMENT } from '#angular/common';
import { Inject } from '#angular/core';
export class Component{
active=false;
constructor(#Inject(DOCUMENT) document) {
}
display(id)
{
document.getElementById(`full${id}`).display="block";
}
}
any suggestions ,how to do this .Thanks
Property 'display' does not exist on type 'HTMLInputElement'
That's because HTML elements do not have a property display. What you're looking for is:
document.getElementById(`full${id}`).style.display='block';
Rather than directly manipulating the DOM, the more Angular way of doing this would be to track the visibility state of each row and drive visibility through NgIf
NgIf: A structural directive that conditionally includes a template based on the value of an expression coerced to Boolean. When the expression evaluates to true, Angular renders the template provided in a then clause, and when false or null, Angular renders the template provided in an optional else clause. The default template for the else clause is blank.
Here is an example with a single boolean driving the toggle of a single div, but you could do something similar with a map on your data.
#Component({
selector: 'ng-if-simple',
template: `
<button (click)="show = !show">{{show ? 'hide' : 'show'}}</button>
show = {{show}}
<br>
<div *ngIf="show">Text to show</div>
`
})
export class NgIfSimple {
show: boolean = true;
}
I've solve problem like this:
let fullId = document.getElementById(`full${id}`) as HTMLElement;
fullId.style.display='block';

Sorting array kills javascript instance on element (i.e. wysiwyg-editor)

I've got a CMS-like feature that has an article with multiple particles (called blocks). A particle can be a either a rich text field or a table. Based on the Block's discr attribute, a Quill or Handsontable instance should be initiated.
This works perfectly, until I reorder the blocks. When I've got a Quill instance and a Handsontable instance, after reordering them, the Quill gets a context menu from the Handsontable and the Quill instance gets a toolbar.
I'm new to Vue.js, but I already understand that happens. I've read List Rendering Caveats and Why isn’t the DOM updating?. The two div.chapterblock elements don't get reordered (like a jQuery-like application probably would do), but only their content changes. When I use the inspector, I see the .chapterblock#id and it's content changing, not moving. The (Quill/Handsontable/whatever) instance is bound to a specific DOM element and stays bound to the element, even if it changes.
But what I don't (yet) understand is how to solve the problem. How can I reorder items and keep the Quill/Handsontable instance on the right elements? Destroying and re-initializing the instances doesn't feel right.
My template:
<div class="chapterblock" v-for="(block, index) in blocks" v-bind:data-id="block.id">
<template v-if="block.discr == 'html'">
<div class="quill" v-html="block.content"></div>
</template>
<template v-if="block.discr == 'table'">
<script type="application/json" v-html="block.content"></script>
<div v-bind:id="'handsontable_' + block.id" class="handsontable-wrapper"></div>
</template>
<button v-if="index !== 0" v-on:click="move(block, 'up')">up</button>
<button v-if="index !== 1" v-on:click="move(block, 'down')">down</button>
</div>
Vue instance:
return new Vue({
//...
computed: {
blocks: function () {
return this.chapter.blocks.sort(function compare (a, b) {
if (a.position < b.position) {
return -1
}
if (a.position > b.position) {
return 1
}
return 0
})
}
},
methods: {
move: function (block, direction) {
if (direction === 'up') {
block.position = block.position - 1
} else if (direction === 'down') {
block.position = block.position + 1
}
// fetch to save position
}
}
Use the key attribute on the v-for loop to reorder the elements, instead of replacing their contents:
From https://v2.vuejs.org/v2/guide/list.html#key:
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.

Vue.js: Conditional class style binding

I have some data that is accessible via:
{{ content['term_goes_here'] }}
... and this evaluated to either true or false. I'd like to add a class depending on the truthiness of the expression like so:
<i class="fa" v-bind:class="[{{content['cravings']}} ? 'fa-checkbox-marked' : 'fa-checkbox-blank-outline']"></i>
where true gives me the class fa-checkbox-marked and false would give me fa-checkbox-blank-outline. The way I wrote it above gives me an error:
- invalid expression: v-bind:class="[{{content['cravings']}} ? 'fa-checkbox-marked' : 'fa-checkbox-blank-outline']"
How should I write it to be able to conditionally determine the class?
Use the object syntax.
v-bind:class="{'fa-checkbox-marked': content['cravings'], 'fa-checkbox-blank-outline': !content['cravings']}"
When the object gets more complicated, extract it into a method.
v-bind:class="getClass()"
methods:{
getClass(){
return {
'fa-checkbox-marked': this.content['cravings'],
'fa-checkbox-blank-outline': !this.content['cravings']}
}
}
Finally, you could make this work for any content property like this.
v-bind:class="getClass('cravings')"
methods:{
getClass(property){
return {
'fa-checkbox-marked': this.content[property],
'fa-checkbox-blank-outline': !this.content[property]
}
}
}
<i class="fa" v-bind:class="cravings"></i>
and add in computed :
computed: {
cravings: function() {
return this.content['cravings'] ? 'fa-checkbox-marked' : 'fa-checkbox-blank-outline';
}
}
Why not pass an object to v-bind:class to dynamically toggle the class:
<div v-bind:class="{ disabled: order.cancelled_at }"></div>
This is what is recommended by the Vue docs.
the problem is blade, try this
<i class="fa" v-bind:class="['{{content['cravings']}}' ? 'fa-checkbox-marked' : 'fa-checkbox-blank-outline']"></i>
You could use string template like with backticks `` :
:class="`${content['cravings'] ? 'fa-checkbox-marked' : 'fa-checkbox-blank-outline'}`"
if you want to apply separate css classes for same element with conditions in Vue.js
you can use the below given method.it worked in my scenario.
html
<div class="Main" v-bind:class="{ Sub: page}" >
in here, Main and Sub are two different class names for same div element.
v-bind:class directive is used to bind the sub class in here.
page is the property we use to update the classes when it's value changed.
js
data:{
page : true;
}
here we can apply a condition if we needed.
so, if the page property becomes true element will go with Main and Sub claases css styles. but if false only Main class css styles will be applied.

Categories