Appending a prop to an already existing attribute inline - reactjs

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}`}

Related

React classname definition

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'.

Does having too much whitespace in class in html cause any problems / performance issues?

I am assigning multiple conditional classes to an element in jsx. The line gets too long, it is not readable, so I break it into multiple lines.
Since I am using a template literal, the whitespaces due to linebreaks are also part of the resulting string.
The template:
<span
className={`${classes.voucherStatus}
${statusTypes.ok.includes(voucherStatus) ? classes.voucherSuccessMessage : ''}
${statusTypes.error.includes(voucherStatus) ? classes.voucherErrorMessage : ''}`}
>
{voucherStatus}
</span>
Which will look like as rendered html:
I think my 'solution' is more readable than the ones others have suggested.
My question is: are there any drawbacks associated with creating a class the way I did?
The only drawback I can think of is in the event that you try to use the attribute selector to access the class attribute.
For example:
<span class="classOne classTwo"></div>
/* doesn't work */
[class='classOne classTwo'] {
}
/* this works */
[class='classOne classTwo'] {
}

Constructing string using react property and es6 template feature

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.

Angular 2 component dynamic name

How i can set dynamic name to angular 2 component?
I have next code in my template:
<{{component} [data]="data" [anotherData]="anotherData"></{{component}}>
And I want do define componentName in my class
component: string = 'component';
Because now i have next error:
Uncaught (in promise): Template parse errors:
Unexpected closing tag "{{component}" ("
<div [ngSwitch]="contactService.contact.cat">
<div *ngSwitchWhen="'person'">
<persons-edit [primary]="true"></persons-edit>
</div>
<div *ngSwitchWhen="'business'">
<businesses-edit [primary]="true"></businesses-edit>
</div>
<div *ngSwitchWhen="'place'">
<places-edit [primary]="true"></places-edit>
</div>
</div>
This is what I use in my app. I have the three components defined, and use a switch to show the one I want. I get the selection here from a service, but you could get it from your root component. Something like this:
#Component {
selector: 'dynamic-component',
....
}
export class DynamicComponent{
#Input selectedcomponent : string;
}
Then use it in a template:
<dynamic-component [selectedcomponent]="person"></dynamic-component>
And instead of using a service, switch on "selectedcomponent".
The Answer is simply You Can't !!
While defining your component you must have to declare name of that component(i.e selector property) as well as class name. without declaring component name you can't create component.
so in your case there are option is either you create no. of components and call whenever you need of that component or create dynamic input value of that component so as per need set your dynamic value and get usng #Input. because for each component there is diff. template and logic as well, so better is to create new components and use as per need.
yes no doubt you can set dynamically data to that component like ID's ,name, custom input etc etc.
hope it clears everything if not comment here !
You cannot dynamically assign names to components the way you try to do it.
However, you can dynamically assign ids to your elements with [attr.id]="id_string_expression"
Most likely you can solve your problem that way.
Something like:
<my-component [attr.id]="name+number" [data]="data" [anotherData]="anotherData"></my-component>

Applying multiple classes using ng-class

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>

Resources