Adding two computed class properties on a :class="{{}} {{}}" in Vue - css

I'm pretty new to the Vue world and was curious if I'm able to apply 2 computed properties to a :class.
I've tried giving a space to each prop :class="{{prop1}} {{prop2}}"
but on reload the content will all disappear because something seems to be wrong.
Does anybody know if this is possible or if its even a good to do things this way?
Backstory
Im creating an input that will have the :class="{{showWhenButtonClicked}}" and another to give it a green input or a red input classname when the email is not valid.
If there are any details that I'm missing or a better way let me know. Thanks!!
computed: {
validateEmail() {
var re = /^(([^<>()\[\]\\.,;:\s#"]+(\.[^<>()[\]\\.,;:\s#"]+)*)|(".+"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
return re.test(String(this.emailTo).toLowerCase())
},
showEmailInput() {
return this.sendEmail ? 'hide-show-option' : 'hide-option-input'
},
displayEmailError() {
return this.validateEmail() ? "valid-input" : "not-valid-input"
}
},
<input :class="{{showEmailInput}} {{displayEmailError}}" placeholder="Enter Email..." v-model="emailTo" #blur="{{validateEmail}}" type="email">

You'd use array syntax to apply a list of classes:
<input :class="[showEmailInput, displayEmailError]"/>

Nick's answer is the best one so far. But you can also store the class in a computed variable, which I think cleans up the code:
classList({ sendEmail, validateEmail }) {
return [
sendEmail ? 'hide-show-option' : 'hide-option-input',
validateEmail ? "valid-input" : "not-valid-input"
]
}
OR you can return an object instead, but in this case it's not as succinct as the array
classObject({ sendEmail, validateEmail }) {
return {
'hide-show-option': sendEmail,
'hide-option-input': !sendEmail,
'valid-input': validateEmail,
'not-valid-input': !validateEmail
}
}
When you start to integrate more complex logic in classes, the two options above will make even more sense.

try this
:class="prop1 + ' ' + prop2"

Related

Is there a better way to do this in handlebars?

Im using handlebars to spit out some static pages using a partial like so:
{{> component/card size="small" title="Card Title" }}
Now depending on the "size" of the card required, i need to set some different tailwind classes. Im currently doing it like so, but there must be a better way? Adding the class to the container and writing css is not an option.
{{setVariable "additionalHeadingClass" "text-5 md:text-6 mb-4"}}
{{#ifEquals size "small"}}
{{setVariable "additionalHeadingClass" "text-4 mb-1"}}
{{/ifEquals}}
{{#ifEquals size "large"}}
{{setVariable "additionalHeadingClass" "text-4 sm:text-5 md:text-8 mb-4"}}
{{/ifEquals}}
<h3 class="text-primary font-bold {{#root.additionalHeadingClass}}">{{title}}</h3>
and heres the helper im using:
Handlebars.registerHelper("setVariable", function (varName, varValue, options) {
if (!options.data.root) {
options.data.root = {};
}
options.data.root[varName] = varValue;
});
My opinion is that there is too much code in your template for what it actually does. Despite the intimidating number of lines, we really just want to map a size to a string of class names. I would also advise against the setVariable because I find it harder to think about when we creating a side-effect by manipulating a variable on our context object. I would much prefer a more functional-style helper, where we just give it the size and it returns the class names string.
I would create such a helper using a simple switch:
Handlebars.registerHelper('additionalClasses', function(size) {
switch (size) {
case 'large':
return 'text-4 sm:text-5 md:text-8 mb-4';
case 'small':
return 'text-4 mb-1';
default:
return 'text-5 md:text-6 mb-4';
}
});
And then we may reduce our template to the much simpler:
<h3 class="text-primary font-bold {{additionalClasses size}}">{{title}}</h3>
I have created a fiddle for reference.

Programmatically assigning css classes in React

In my React app I have a set of classes that I am assigning to various elements. They are named button1, button2, button3, etc. Currently I am using a switch statement to determine which class to assign.
switch (num) {
case 1:
return {
memberButton: styles.button1
};
case 2:
return {
memberButton: styles.button2
};
case 3:
return {
memberButton: styles.button3
};
}
Is there a way to assign the class by doing something like this:
className={styles.button + rowNumber}
Of course that doesn't work. I'm trying to eliminate the need for a switch statement by constructing the class name in code.
Yo should do it like this:
className={styles[`button${rowNumber}`]}
You need to use brackets to access an Objects hash value using a variable since variables can't be used with dot notation. E.g.:
styles = {
'button1': 'button 1 styles',
'button2': 'button 2 styles',
'button3': 'button 3 styles',
}
Then you would just do:
className={ styles[`button${rowNumber}`] }
In short - With dot notation you cannot use variables, but with bracket notation you can.
You can try the following approaches
<div className={"form-group "+ this.props.errorMessage.roleError ?this.props.errorMessage.roleError : '' +" has-feedback"}></div>
another with template literal
<div className={`form-group ${this.props.errorMessage.roleError ?this.props.errorMessage.roleError : ''} has-feedback`}></div>
in your code
className={ styles[`button${rowNumber}`] }
or
className={styles['button'+rowNumber+'\''] }

How to put a reactive Template inside of a Surface in famo.us/Meteor

I've read several posts on this but nothing that would really answer my question in an up-to-date way (i.e. UI.insert is depreciated).
So what's the best way of inserting/rendering a Template into a Surface reactively, meaning, not only one data object (renderWithData), but whatever is defined in the Template.helpers should also be updated reactively. Code tried so far:
var div = document.createElement('div');
//UI.insert(UI.render(function() { return Template.hello; }), div);
surface = new famous.core.Surface({
//content: Blaze.toHTML(function() { return Template.hello; }),
//content: div,
content: '<div class="hell"></div>',
size: [window.innerWidth, window.innerHeight],
properties: {...}
});
Blaze.render(function() { return Template.hello}, $('.hell')[0]);
These are 3 different approaches I've tried. First UI.insert inserts it, but handlebars-style Helpers are not recognized. Second, toHTML, no reactivity, even when I put everything into a Tracker.autorun(). Third, Blaze.render(...), doesn't work at all.
Is there an easy solution to this?
one possible answer is to use Famodev
var ReactiveTemplate = famodev.ReactiveTemplate;
var reactive = new ReactiveTemplate({
template: Template.mytemplate,
data: Collection.find().fetch(),
properties: {
}
});
Maybe it will be useful in some way http://github.com/dcsan/moflow

How to get multi css rule for ng-style by function?

I need for apply multi css rule to html tag in angular form template.
<div class="form-control" id="data.objectStyle"
ng-model="data.type"
ng-style="getStyle(data.objectStyle)">
{{data.objectStyle.title}}
</div>
getStyle function in controller :
$scope.getStyle = function (taskType) {
return {
background-color:taskType.backColor,
color: taskType.color,
font-size:taskType.fontSize,
font-family:taskType.font
}
)};
taskType object:
{
backColor:'#006',
color:'#56DA',
fontSize:12,
font:'New Times Roman'
}
The getStyle function does not return a style! What to do?
EDIT
The docs specify that you need to wrap your keys in quotation marks so they aren't invalid JSON object keys:
return {
"background-color": taskType.backColor,
"color": taskType.color,
"font-size":taskType.fontSize,
"font-family":taskType.font
}
Old Answer (not using ng-style)
While I never used ng-style, it doesn't seem to take objects. Rather it is an equivalent of ng-class but for single styles.
Try changing your function to:
$scope.getStyle = function (taskType) {
return {
"background-color:"+taskType.backColor+
";color:"+ taskType.color+
";font-size:"+taskType.fontSize+
";font-family:"+taskType.font+";";
}
)};
and the html to use the regular style tag with a bind:
<div class="form-control" id="data.objectStyle"
ng-model="data.type" style="{{getStyle(data.objectStyle)}}">

What is the best way to conditionally apply a class?

Lets say you have an array that is rendered in a ul with an li for each element and a property on the controller called selectedIndex. What would be the best way to add a class to the li with the index selectedIndex in AngularJS?
I am currently duplicating (by hand) the li code and adding the class to one of the li tags and using ng-show and ng-hide to show only one li per index.
If you don't want to put CSS class names into Controller like I do, here is an old trick that I use since pre-v1 days. We can write an expression that evaluates directly to a class name selected, no custom directives are necessary:
ng:class="{true:'selected', false:''}[$index==selectedIndex]"
Please note the old syntax with colon.
There is also a new better way of applying classes conditionally, like:
ng-class="{selected: $index==selectedIndex}"
Angular now supports expressions that return an object. Each property (name) of this object is now considered as a class name and is applied depending on its value.
However these ways are not functionally equal. Here is an example:
ng-class="{admin:'enabled', moderator:'disabled', '':'hidden'}[user.role]"
We could therefore reuse existing CSS classes by basically mapping a model property to a class name and at the same time keep CSS classes out of Controller code.
ng-class supports an expression that must evaluate to either
A string of space-delimited class names, or
An array of class names, or
A map/object of class names to boolean values.
So, using form 3) we can simply write
ng-class="{'selected': $index==selectedIndex}"
See also How do I conditionally apply CSS styles in AngularJS? for a broader answer.
Update: Angular 1.1.5 has added support for a ternary operator, so if that construct is more familiar to you:
ng-class="($index==selectedIndex) ? 'selected' : ''"
My favorite method is using the ternary expression.
ng-class="condition ? 'trueClass' : 'falseClass'"
Note: Incase you're using a older version of Angular you should use this instead,
ng-class="condition && 'trueClass' || 'falseClass'"
I'll add to this, because some of these answers seem out of date. Here's how I do it:
<class="ng-class:isSelected">
Where 'isSelected' is a javascript variable defined within the scoped angular controller.
To more specifically address your question, here's how you might generate a list with that:
HTML
<div ng-controller="ListCtrl">
<li class="ng-class:item.isSelected" ng-repeat="item in list">
{{item.name}}
</li>
</div>
JS
function ListCtrl($scope) {
$scope.list = [
{"name": "Item 1", "isSelected": "active"},
{"name": "Item 2", "isSelected": ""}
]
}
See: http://jsfiddle.net/tTfWM/
See: http://docs.angularjs.org/api/ng.directive:ngClass
Here is a much simpler solution:
function MyControl($scope){
$scope.values = ["a","b","c","d","e","f"];
$scope.selectedIndex = -1;
$scope.toggleSelect = function(ind){
if( ind === $scope.selectedIndex ){
$scope.selectedIndex = -1;
} else{
$scope.selectedIndex = ind;
}
}
$scope.getClass = function(ind){
if( ind === $scope.selectedIndex ){
return "selected";
} else{
return "";
}
}
$scope.getButtonLabel = function(ind){
if( ind === $scope.selectedIndex ){
return "Deselect";
} else{
return "Select";
}
}
}
.selected {
color:red;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.1/angular.min.js"></script>
<div ng-app ng-controller="MyControl">
<ul>
<li ng-class="getClass($index)" ng-repeat="value in values" >{{value}} <button ng-click="toggleSelect($index)">{{getButtonLabel($index)}}</button></li>
</ul>
<p>Selected: {{selectedIndex}}</p>
</div>
I faced a similar problem recently and decided to just create a conditional filter:
angular.module('myFilters', []).
/**
* "if" filter
* Simple filter useful for conditionally applying CSS classes and decouple
* view from controller
*/
filter('if', function() {
return function(input, value) {
if (typeof(input) === 'string') {
input = [input, ''];
}
return value? input[0] : input[1];
};
});
It takes a single argument, which is either a 2-element array or a string, which gets turned into an array that is appended an empty string as the second element:
<li ng-repeat="item in products | filter:search | orderBy:orderProp |
page:pageNum:pageLength" ng-class="'opened'|if:isOpen(item)">
...
</li>
If you want to go beyond binary evaluation and keep your CSS out of your controller you can implement a simple filter that evaluates the input against a map object:
angular.module('myApp.filters, [])
.filter('switch', function () {
return function (input, map) {
return map[input] || '';
};
});
This allows you to write your markup like this:
<div ng-class="muppets.star|switch:{'Kermit':'green', 'Miss Piggy': 'pink', 'Animal': 'loud'}">
...
</div>
The was I recently did that was doing this:
<input type="password" placeholder="Enter your password"
ng-class="{true: 'form-control isActive', false: 'isNotActive'}[isShowing]">
The isShowing value is a value that is located on my controller that gets toggled with the click of a button and the parts between the single parenthesis are classes I created in my css file.
EDIT: I would also like to add that codeschool.com has a free course that is sponsored by google on AngularJS that goes over all of this stuff and then some. There is no need to pay for anything, just signup for an account and get going!
Best of luck to you all!
Ternary operator has just been added to angular parser in 1.1.5.
So the simplest way to do this is now :
ng:class="($index==selectedIndex)? 'selected' : ''"
We can make a function to manage return class with condition
<script>
angular.module('myapp', [])
.controller('ExampleController', ['$scope', function ($scope) {
$scope.MyColors = ['It is Red', 'It is Yellow', 'It is Blue', 'It is Green', 'It is Gray'];
$scope.getClass = function (strValue) {
switch(strValue) {
case "It is Red":return "Red";break;
case "It is Yellow":return "Yellow";break;
case "It is Blue":return "Blue";break;
case "It is Green":return "Green";break;
case "It is Gray":return "Gray";break;
}
}
}]);
</script>
And then
<body ng-app="myapp" ng-controller="ExampleController">
<h2>AngularJS ng-class if example</h2>
<ul >
<li ng-repeat="icolor in MyColors" >
<p ng-class="[getClass(icolor), 'b']">{{icolor}}</p>
</li>
</ul>
<hr/>
<p>Other way using : ng-class="{'class1' : expression1, 'class2' : expression2,'class3':expression2,...}"</p>
<ul>
<li ng-repeat="icolor in MyColors">
<p ng-class="{'Red':icolor=='It is Red','Yellow':icolor=='It is Yellow','Blue':icolor=='It is Blue','Green':icolor=='It is Green','Gray':icolor=='It is Gray'}" class="b">{{icolor}}</p>
</li>
</ul>
You can refer to full code page at ng-class if example
I am new to Angular but have found this to solve my issue:
<i class="icon-download" ng-click="showDetails = ! showDetails" ng-class="{'icon-upload': showDetails}"></i>
This will conditionally apply a class based on a var.
It starts off with a icon-download as a default, the using ng-class, I check the status of showDetails if true/false and apply class icon-upload. Its working great.
Hope it helps.
This works like a charm ;)
<ul class="nav nav-pills" ng-init="selectedType = 'return'">
<li role="presentation" ng-class="{'active':selectedType === 'return'}"
ng-click="selectedType = 'return'"><a href="#return">return
</a></li>
<li role="presentation" ng-class="{'active':selectedType === 'oneway'}"
ng-click="selectedType = 'oneway'"><a href="#oneway">oneway
</a></li>
</ul>
This will probably get downvoted to oblivion, but here is how I used 1.1.5's ternary operators to switch classes depending on whether a row in a table is the first, middle or last -- except if there is only one row in the table:
<span class="attribute-row" ng-class="(restaurant.Attributes.length === 1) || ($first ? 'attribute-first-row': false || $middle ? 'attribute-middle-row': false || $last ? 'attribute-last-row': false)">
</span>
This is in my work multiple conditionally judge:
<li ng-repeat='eOption in exam.examOptions' ng-class="exam.examTitle.ANSWER_COM==exam.examTitle.RIGHT_ANSWER?(eOption.eoSequence==exam.examTitle.ANSWER_COM?'right':''):eOption.eoSequence==exam.examTitle.ANSWER_COM?'wrong':eOption.eoSequence==exam.examTitle.RIGHT_ANSWER?'right':''">
<strong>{{eOption.eoSequence}}</strong> |
<span ng-bind-html="eOption.eoName | to_trusted">2020 元</span>
</li>
Here is another option that works well when ng-class can't be used (for example when styling SVG):
ng-attr-class="{{someBoolean && 'class-when-true' || 'class-when-false' }}"
(I think you need to be on latest unstable Angular to use ng-attr-, I'm currently on 1.1.4)
well i would suggest you to check condition in your controller with a function returning true or false .
<div class="week-wrap" ng-class="{today: getTodayForHighLight(todayDate, day.date)}">{{day.date}}</div>
and in your controller check the condition
$scope.getTodayForHighLight = function(today, date){
return (today == date);
}
partial
<div class="col-md-4 text-right">
<a ng-class="campaign_range === 'thismonth' ? 'btn btn-blue' : 'btn btn-link'" href="#" ng-click='change_range("thismonth")'>This Month</a>
<a ng-class="campaign_range === 'all' ? 'btn btn-blue' : 'btn btn-link'" href="#" ng-click='change_range("all")'>All Time</a>
</div>
controller
$scope.campaign_range = "all";
$scope.change_range = function(range) {
if (range === "all")
{
$scope.campaign_range = "all"
}
else
{
$scope.campaign_range = "thismonth"
}
};
If you are using angular pre v1.1.5 (i.e. no ternary operator) and you still want an equivalent way to set a value in both conditions you can do something like this:
ng-class="{'class1':item.isReadOnly == false, 'class2':item.isReadOnly == true}"
If you having a common class that is applied to many elements you can create a custom directive that will add that class like ng-show/ng-hide.
This directive will add the class 'active' to the button if it's clicked
module.directive('ngActive', ['$animate', function($animate) {
return function(scope, element, attr) {
scope.$watch(attr.ngActive, function ngActiveWatchAction(value){
$animate[value ? 'addClass' : 'removeClass'](element, 'active');
});
};
}]);
More info
Just adding something that worked for me today, after much searching...
<div class="form-group" ng-class="{true: 'has-error'}[ctrl.submitted && myForm.myField.$error.required]">
Hope this assists in your successful development.
=)
Undocumented Expression Syntax : Great Website Link... =)
Check this.
The infamous AngularJS if|else statement!!!
When I started using Angularjs, I was a bit surprised that I couldn’t find an if/else statement.
So I was working on a project and I noticed that when using the if/else statement, the condition shows while loading.
You can use ng-cloak to fix this.
<div class="ng-cloak">
<p ng-show="statement">Show this line</span>
<p ng-hide="statement">Show this line instead</span>
</div>
.ng-cloak { display: none }
Thanks amadou
You can use this npm package. It handles everything and has options for static and conditional classes based on a variable or a function.
// Support for string arguments
getClassNames('class1', 'class2');
// support for Object
getClassNames({class1: true, class2 : false});
// support for all type of data
getClassNames('class1', 'class2', ['class3', 'class4'], {
class5 : function() { return false; },
class6 : function() { return true; }
});
<div className={getClassNames({class1: true, class2 : false})} />
I understand this question id for angular, but if anyone is using React or a React-Based Framework (Amplify, NextJS, Serverless, etc.) The solution is significantly easier. The most performant way is with a ternary operator like so:
<div className={condition ? "classnameiftrue" : "classnameiffalse"}>
You can use this strategy to animate the tree if using useState() as each time the state changes it will reload that conditional with the new value.

Resources