is there any difference between className = 'name' and className = {'name'} in React? I ofc know that you can use variables in {}, but my question is specifically to string in those brackets {''}. I tried to simulate this in code and it looks to me that are both the same. Can anyone confirm this?
There is no difference in both the notations if you are writing a single class name that is, className="name" is equal and the same as className={'name'}
However, we use this {} notation when we want to give a conditional class. For example:
<p className={this.state.hidden ? "hidden" : ""}>Hello World</p>
The above line gives the <p> tag a class of hidden if the state variable hidden is set to true. We use the the curly braces {} in React when we want to write JavaScript code in the render function. We could use it for concatenation of two string class names or conditional class names.
No, there is no difference. When you write {'name'}, it is interpreted as 'name'. Just like if you write {'name' + ' name2' }, it is interpreted as 'name name2'.
Related
Is there a way to append a property from this.props to an HTML element's attribute that already exists, and to do it inline (in the name of code-simplicity), without any variables/addons?
Something like this (but obviously this one and few other ways that I tried to append didn't work for me):
render() {
return (
<div className="entity" id="ent"+{this.props.index}>bla</div>
);
}
I do know that I could declare a variable before, append the prop to it and then use it as the attribute, but I have many lines like this and it will make my code bigger than I wanted it to be.
Thanks.
You can concatenate attributes as you usually do with strings:
<div className="entity" id={"ent" + this.props.index}>bla</div>
or (es6 syntax)
<div className="entity" id={`ent${this.props.index}`}>bla</div>
id={"ent" + this.props.index}
Or using interpolation instead of string concatenation.
id={`ent${this.props.index}`}
I need to construct the href using the react property and es6 template feature. My code is below however after rendering the subHeader in href is not replaced with its value.
subHeaders = this.props.subHeaders.map((subHeader, i) => {
return <a className="articleSidebar__summaryText" href='#${subHeader}' key={i}>{subHeader}</a>;
});
How can I achieve this?
You're not using the right syntax in the href part.
Are you trying to get an output like #something? In that case, it should be:
href={`#${subHeader}`}
You need to use template literals (``) when you want to do string interpolation. And you need to use {} around the template literal because thats the syntax you need to use in order to set a prop to some JS expression instead of some literal string.
I am currently learning React and Redux. I have forked a boilerplate, and currently I am looking through all of the code to see how it fits together.
While scanning through some React Component files I found something very interesting! When setting className for many of the elements the syntax they use differs. The first time they use the following syntax:
<span className={classes['counter--green']}>
...
</span>
Then this syntax:
<button className='btn btn-default'>
...
</button>
And from there on out they use the following:
<h2 className={classes.counterContainer}>
...
</h2>
At the top of the file they import classes with the following:
import classes from './Counter.scss'
So simply my question is, why are there three different syntax for className, and which one is correct?
Starting with the simple case:
<button className='btn btn-default'>
This just sets the class name to "btn btn-default". You need to set className instead of class since you are writing JSX and that’s equivalent to setting the className DOM property, so you have to use className here.
<span className={classes['counter--green']}>
<h2 className={classes.counterContainer}>
These are both very similar. In JSX, to specify a more complex JavaScript expression, you need to put it inside curly braces. This would be equivalent to setting the className property like this:
someSpan.className = classes['counter--green'];
someH2.className = classes.counterContainer;
Finally, classes as imported using the import classes from './Counter.scss' syntax is a feature called “CSS modules”. It involves a precompiler step that properly sets the class names later and makes sure that the style definitions are rendered to the HTML.
So to answer your final question, all of these are correct. What you want to use depends on where you want to define your styles (or where they are defined). Using CSS modules makes a lot of sense if you are creating independent components that might even get reused elsewhere. Using global CSS is good when you have an existing style sheet which you just want to use (e.g. here, these class names are likely from bootstrap). And of course, you can also mix these, if you have global styles and want to add additional styles to it.
In this case, without seeing the code, i'm guessing the boilerplate is using modular css (scss).
modular css can be imported,in this case as classes. Using modular css gives you css with local scope
all css rules imported from a module as classes are prefixed with the name classes.
and are to be treated as you treat object attributes
so css rule counterContainer is used as
classes.counterContainer
css rule name counter-green cannot use dot notation(because of the hyphen), so must use square bracket and string name notation as for any javascript object attribute
classes['counter-green']
the third example btn btn-default is not imported from a css classes module but is instead imported globally. This is possibly a bootstrap class imported at root level as a link attribute on the index.html
This isn't really unique to className, but for any JSX you can use curly braces {}'s to switch from "JSX mode" back to javascript to use any JS expression. Therefore in the first example they are setting the attribute className by referencing an object called classes by the property counter--green, in the second example they are using a simple JSX string literal 'btn btn-default', and in the third example they are referencing the classes object by the property counterContainer. You can see the definition of the classes object according to the import at the end of your question.
They are all correct, they are simply different ways of doing it. By using JS expressions they are arguably more modular, by using a string literal it is easier to see in front of you what is going on, but less re-usable.
Assume that I have two objects in my model: foo that can take two values Foo1 and Foo2 and object bar with two possible values Bar1 and Bar2.
Now, I would like to apply to my div classes based on values of these objects.
Basically, I would like to apply MyclassFoo1 when foo=Foo1, MyclassFoo2 when foo=Foo2 and similarly for bar.
For instance, if foo=Foo1 and bar=Bar2 I would like to end up with
<div class="MyClassFoo1 MyClassBar2"></div>
The two problems that I am having here are:
the class names are generated dynamically based on object values
Foo classes are independent from Bar classes
I've tried to use the syntax
<div ng-class="{class1: expr1, class2: expr2}"></div>
but it doesn't work, as the dictionary keys cannot be composed as 'MyClass' + foo
The other syntax
ng-class="{expr_val1: class1, expr_val2: class2}[expr]"
does not look promissing either: I would have to put all the foo-bar combinations as expression values.
Is there any other way to achieve my goal?
I've managed to solve the problem entirely in template, using the list notation in the following way:
ng-class="[foo ? 'MyClass' + foo : '', bar ? 'MyClass' + bar : '']"
You can put arbitrary angular expressions into the list.
Have you tried the following?
<div class="MyClass{{model.foo}} MyClass{{model.bar}}">
Even if model.foo or .bar becomes null this will add a non-existing class, which should not matter.
Notice that if you want a minus (-) sign in your class name, you should quote the class name (check out 'second-class').
Also you can bind availability of the class name to a function. Function should return boolean.
<div ng-class="{first: hasFirst, 'second-class': hasSecond(), third: true, fourthClass: obj.property == value}"></div>
I've found another way!
$scope.foo = 'fooClassName';
<div ng-class="foo"></div>
gives you
<div class="fooClassName" ng-class="foo"></div>
This works for me, using array in the View:
just do:
<div ng-class="[class1, class2]"></div>
I have tried this way and it worked but only drawbacks is it will not updates dynamically when you change the modules
<div ng-class="{'{{class1}}': expr1, '{{class2}}': expr2}"></div>
I have the component and have a problem setting the css class to it.
I want it to always have a class of "box", then to have additional classes specified by the directive "class" argument and one conditional class "mini".
Conceptually what I want to achieve is something like this:
<div class="box {{class}}" data-ng-class="{mini: !isMaximized}">
...
</div>
The problem is that when I set the class html attribute, the ng-class attribute is omitted.
How to make my example work without changing the controller? Is it even possible, or should I set the class in the controller instead (which I wish to avoid)?
A quick solution would be define the box class inside ng-class attribute:
<div data-ng-class="{mini: !isMaximized, box: true}"></div>
If you want to include a scope variable as a class, you can't use ng-class:
<div class="{{class}} box {{!isMaximized && 'mini' || ''}}">
Angular expressions do not support the ternary operator, but it can be emulated like this:
condition && (answer if true) || (answer if false)
I needed multiple classes where one was $scope derived and others were literal classes. Thanks to the hint from Andre, below worked for me.
<h2 class="{{workStream.LatestBuildStatus}}"
ng-class="{'expandedIcon':workStream.isVisible, 'collapsedIcon':!workstream.isvisible}">{{workStream.Name}}</h2>
Edit: for newer versions of Angular see Nitins answer as it is the best one atm
For me, this worked (I'm working on AngularJS v1.2.14 at the moment so I guess 1.2.X+ should support this, not sure about the earlier versions):
<div class="box" data-ng-class="{ {{myScopedObj.classesToAdd}}: true, mini: !isMaximized }"></div>
I replaced your {{class}} with {{myScopedObj.classesToAdd}} to show that any scoped variable or even a bit more complex object can be used this way.
So, every DIV element crated this way will have "box" class and any class contained within myScopedObj.classesToAdd (useful when using ng-repeat and every element in the array needs to have a different class applied), and it will have the "mini" class if !isMaximized.
Another way to do this without double curly braces and includes scope variables, tested with angular v1.2+.
<div ng-class="['box',
aClass,
{true:'large': false: 'mini'}[isMaximized]]"></div>
It's also rather nice because the variable can use different types as a index without increasing complexity using ternaries. It can also remove any need for negations ;)
Here is a fiddle link
You can use simple expression given below
ng-class="{'active' : itemCount, 'activemenu' : showCart}"