RiotJS use property as class name - riot.js

Let's consider following template:
<ul class="clearfix">
<li each={ timeslot, i in events }
class={ ??? }
data={ timeslot }
style="width: { timeslot.len*100 }px;">
<div>{ timeslot.start.format() }</div>
<div>{ timeslot.title }</div>
</li>
</ul>
I have a state property in my timeslot object, that has the exact same set of values I would like to use as class names. Thus it would be straightforward to use class={ timeslot.state }. But class is evaluated differently.
Is there any way to avoid expressions in this case and use the property as it is as class name?
Thank you.

When you use a {} expression, it can be evaluated in a number of ways. If you are setting as an object, IE: class={foo: true, bar: false } it is treated like a list of class names to add based on whether the value of each key is true-ish.
BUT... if you do class="{ timeslot.classname }" - it will instead be treated like a string and the output will be the class="whatever" you are looking for... as long as timeslot.classname is a string.

In > 3.4.0 you can create an object, which will then do what you want:
timeslot.state={SomeClass:true}
See http://riotjs.com/guide/#expressions and scroll to Class object expressions

Related

Nuxt.js: Can I add a class using a ternary operator based on a Boolean from a prop?

I'm trying to use a Boolean in a prop to add a class based on a ternary operator. I'm obviously not doing it right because it is always evaluating to false.
<div :class="$style.inner + ' ' + (isRight == true ? 'is-right' : 'is-false')" :style="`color: #` + fontColor"></div>
If it's true, I need is-right added to the class, otherwise, this doesn't need to be added.
props: {
isRight: {
type: Boolean,
default: false
},
}
index.vue
<Signpost isRight=true/>
.is-right { padding-left:20% }
Looking at their Docs, I'm not sure I can do this with a Boolean actually.
To pass a Boolean to a prop you need to use v-bind or : like this:
<signpost v-bind:isRight="true" />
or
<signpost :isRight="true" />
Also if the only possible values for isRight is true or false you can shorten your ternary to just be:
:class="isRight ? 'is-right' : 'is-false'
I actually had a little syntax error for my prop that needed binding:
<Signpost :is-right="true"/>
And then on the div as #kissu said:
<div :class="[isRight ? 'is-right' : '']"></div>
Try passing the prop as :is-right="false" to have it passed down as Boolean and not as a basic String (is-right="false").
For the class, it can be written like as shown in the docs
<div :class="[isRight ? 'is-right' : 'is-false']"></div>
That way, you will even be able to do a strong equality check: isRight === true (comparing boolean to boolean).
VueJS devtools can help you see the type (thanks to the color).
There are some strongly recommended prop name casing recommendation that can be found here: https://v2.vuejs.org/v2/style-guide/#Prop-name-casing-strongly-recommended
props: {
greetingText: String // camel-cased here
}
<WelcomeMessage greeting-text="hi"/> <!-- kebab-cased here -->
Also, feel free to write ES6 template litterals, it may help the lecture. A working solution would be:
<div :style="`color: #${fontColor}`"></div>
Can also be done for your class, but I didn't want to risk a bad interpolation here.

Looping in Vue and adding dynamic className

I am quite new to Vue and I have an issue.
I have an array of objects and I want the wrapper of the loop to have dynamic className
For example
<div v-for="({time, date, name}, i) in myObject" :key="i" class="my-custom-class">
well, if the key (i) is greater than 3 then I want the className to have a different name
or at least to add an extra name (like hiddenDiv).
I know is not possible to add the v-if condition in the v-for statement.
Any help is appreciated.
You could bind the class using a condition based on the current loop index :class="{'hide-div':i>3}":
<div v-for="({time, date, name}, i) in myObject"
:key="i" :class="{'hide-div':i>3}" class="my-custom-class" >
Another way of doing this using computed property...
<div v-for="({time, date, name}, i) in myObject"
:key="i" :class="getClassName(i)" class="my-custom-class" >
and in your computed
computed: {
getClassName() {
return i => {
if(i === 0) return 'classOne';
elseif(i === 1) return 'classTwo'
else return 'classThree';
// In this way you can maintain as many classNames you want based on the condition
}
}
}
If you want to apply a dynamic class in vue then you can use class bindings to apply a specific class to the element.
You can read about class and style bindings here.
Also, you can define a method with the class and apply some conditions on which the class needs to be changed.

How to specify multiple dynamic attributes by single computed prop in VueJS

I have this html element:
Link text
I want to add data-tooltip and title attributes dynamically by condition:
Link text
Is there any way in VueJS to add multiple dynamic attributes at same time:
<!-- instead of this: -->
Link text
<!-- something like this: -->
<a href="javascript:" ...tooltipAttributes >Link text</a>
You could take advantage of v-bind on the DOM element you wish to apply multiple attributes to based on some dynamically changing condition.
Here's a Plunker example demonstrating how you might go about it.
Take note of the object returned:
computed: {
multiAttrs() {
return this.showAttrs ? {
'data-toggle': 'tooltip',
title: 'Some tooltip text',
} : null;
}
}
You should be able to use v-bind="tooltipAttributes"
the docs here https://v2.vuejs.org/v2/api/#v-bind have more info, but the key part is under usage
Dynamically bind one or more attributes, or a component prop to an expression.
From the Docs:
1. You can dynamically bind multiple attributes/props to a single element by using v-bind:
(no colon, no extra attribute, just v-bind)
<a href="#" v-bind="tooltipAttributes" >Link text</a>
2. And then declare the variable in the computed section:
(you can also declare it in the data section, but that would require manual direct value changes)
computed() {
return {
tooltipAttributes: {
title: 'Title',
'data-toggle': this.toggle === true && !disabled
}
}
}
Note: Attributes with dashes/hyphens - in them (e.g. data-toggle) need to be a string because Javascript doesn't recognize - as a valid symbol in variable naming.
This is THE SAME AS:
<a href="#" title="Title" :data-toggle="this.toggle === true && !disabled" >Link text</a>

v-for : is there a way to get the key for the nested(second) loop besides "Object.keys(obj)[0]" in Vuejs?

Here's the markup:
<ul>
<li v-for="(topic,label,index) in guides" :key="index">
<ul>
<strong> {{label}} </strong>
<li v-for="rule in topic">
{{rule.val}},
{{Object.keys(topic)[0]}}
</li>
</ul>
</li>
And here's the data for this list:
data: {
guides: {
"CSS" : {
1502983185472 : {
"modifiedby" : "bkokot",
"val" : "When adding new rule, use classes instead of ID whenever possible"
},
1502983192513 : {
"modifiedby" : "bkokot",
"val" : "Some other rule"
},
},
"Other" : {
1502628612513 : {
"modifiedby" : "dleon",
"val" : "Some test text"
},
1502982934236 : {
"modifiedby" : "bkokot",
"val" : "Another version of text"
},
}
}
}
So as you can see there is a "guides" property which is an object of other objects that do have inner objects too.
All I want is to get the keys from inner (second) loop (numbers "1502983185472" etc).
The only solution that i see right now is "Object.keys(topic)[0]", but is there a more accurate alternative in vuejs for this?
Adding key, index parameters to the second loop(with new unique variable names) doesn't work for me.
Here's a working fiddle: https://jsfiddle.net/thyla/yeuahvkc/1/
Please share your thoughts.
If there is no good solution for this - may it be a nice topic for a feature request in Vuejs repo(unless I'm missing something terrible here)?
Generally if you're curious - that number is a momentjs timestamp - I'm using this data in firebase, and saving initial timestamp as an object key seemed to be a pretty nice solution (since we need a key anyway, to save some space - I can use this key instead of another extra timestamp property in my object, this also makes the instance very 'targetable' in firebase).
Thank you in advance ! Cheers!
p.s: another possible solution is converting inner loop (css, other) from objects into arrays and using time-stamp as another object property, but I'm using firebase - saving this data as an object gives me an ability to quickly access some instance without parsing the entire parent object/array, makes it more easy to filter, search, reupdate, etc - thus converting object into array is not a good solution for instance with very large number of items.
Your fiddle renders the number key of the first entry of a topic for each of the rules in that topic. I'm assuming you want to actually show the number key for each corresponding rule.
That value is passed as the second parameter in the v-for:
<li v-for="(rule, ruleID) in topic">
{{ rule.val }},
{{ ruleID }}
</li>
Here's a working fiddle.
Here's the documentation on using v-for with an object.
This can be solved by as follows in the second loop like
<li v-for="(rule,index) in topic">
{{rule.val}},
{{index}}
</li>
Please refer this fiddle => https://jsfiddle.net/yeuahvkc/7/
Use explicit definitions
Other answers use ".val", but it's not clear where that originates.
Instead, just declare everything, like:
<li v-for="(value, key, index) in rule">
{{key}}: {{value}} - {{index}}
</li>

How to dynamically generate css class inside an each statement for an Ember View

<div>
{{#each value in controller}}
<div {{classNameBindings "col-lg-{{value}}"}}>{{value}}</div>
{{/each}}
</div>
Above is my partial view.
I want to generate classes like: col-lg-1, col-lg-2 etc
My controller is:
App.circleController = Ember.ArrayController.extend({
setupController: function(controller) {
controller.set('content', [1,2,3,4,5,6,7]);
}
});
why I get error: assertion failed: an Ember.CollectionView's content must implement Ember.Array. ?
I use a custom view to apply dynamically-named classes to items inside of an each helper. The class name is generated inside the view by a property than depends on a supplied index.
App.ItemView = Ember.View.extend({
classNameBindings: ['itemClass'],
index: null,
itemClass: function() {
return 'class-'+this.get('index');
}.property('index')
});
In the template, I supply the index through a {{view}} helper inside each iteration.
{{#each value in controller}}
{{#view App.ItemView indexBinding="value"}}
Item #{{value}}
{{/view}}
{{/each}}
For a closer look, check out this jsfiddle.