React inline logic in render() - javascript

I just wonder how apply inline templates logic in React.
I mean in case when I need change class of element how to do that easily?
class RegisterForm extends Component {
...
render() {
let email = this.state.email.error; //true or false
return (<div {email ? className="has-error" : className="regular"}></div>)
}
Then I have an error:
Syntax error: C:/project/components/signup/index.js: Unexpected token, expected ... (107:22)
How to perform that?
Or it's only possible to wrap in if/else full div block only?

You could do a couple things:
<div className={email ? "has-error" : "regular"}> </div>
Or to keep it cleaner
let email = this.state.email.error;
let divClass = email ? "has-error" : "regular";
return <div className={divClass}> </div>

Assign the value conditionally not attribute. Define className attribute and assign its value on the basis of email value.
Write it like this:
<div className = { email ? "has-error" : "regular"}> </div>

Related

Return multiple values from a function in Angular and use those values inside HTML div tag. The return values can't be assigned to variable in TS file

I have a function which returns a string, a css class and a boolean like this [false, green_box]. I want to utilise this values in below HTML but unfortunately I am unable to do so. How can I access the values? Since the function is called multiple times inside the HTML file I cannot assign the return values in a variable in typescript file.
Please note that I can use different function to return boolean value but the goal is to find a way to utilize multiple values returned from a function in HTML.
Below is my HTML
<div *ngIf="getClass('investing', 'plan')[0]"
class="prio_box dnd_move"
data-drag="list-1"
data-drag-index="0">
<span [ngClass]="getClass('investing', 'plan')[1]"
class="dnd_move clr-box">
</span>
<span class="drag_content dnd_move">Plan</span>
</div>
Here is my function,
getClass(component: string, value: any) {
component = component.toLowerCase();
value = value.replace(/\s/g, "");
let pathValue = this.control[component]
? this.control[component.toLowerCase()][value]
: null;
this.allGreen.add(pathValue);
return [pathValue == Status.Yes
? "green_box"
: pathValue == Status.DontKnow
? "yellow_box"
: "red_box",
pathValue == Status.Yes
? false
: pathValue == Status.DontKnow
? true
: true];
}
Try doing something like this:
<ng-container *ngIf="getClass('investing', 'plan') as class">
<div *ngIf="class[0]"
class="prio_box dnd_move"
data-drag="list-1"
data-drag-index="0">
<span class="dnd_move clr-box {{class[1] || ''}}">
</span>
<span class="drag_content dnd_move">Plan</span>
</div>
</ng-container>
Using this way, you can prevent function from being called multiple times.

Conditionally render a badge for active/inactive User

I am trying to render conditionally a badge, based on the logged condition of a user. If the props coming from the server is true, then the badge is green, else grey.
I have tried various solutions, from basic if/else in the JSX, to classNames but the badge isn't being render.
My Code:
{user.loggedIn ? (
<div
className={classNames('badge badge-pill', {
'badge-success': user.loggedIn,
'badge-danger': !user.loggedIn
})}
/>
I don't see anything wrong with the code. I mean the item should have rendered, with multiple solutions. Any ideas, what I am doing wrong.
<span
className={
user.loggedIn ? 'badge badge-pill badge-success' : 'badge badge-pill badge-muted'
}
/>
I have tried this as well.
I can see the element in the React-Dev-Tools, being render correctly, witht the right prop, but I cannot see it render in the screen.
Your contents will only get rendered if user is loggedIn. Also the div tag must be closed inside the condition { isLoggedIn }
you should try something like this:
{user.loggedIn ? (
<div className={'badge badge-pill badge-success'}>ENTER YOUR CONTENT HERE</div>) : (
<div className={'badge badge-pill badge-danger'}>ENTER YOUR CONTENT HERE</div>
)}
but since the div is self-closing and has no contents, it doesn't display it, so add some content too
The badge for logged out user will never be displayed as you put a rendering condition around all the div with user.loggedInd ? (yourComponent...)
If user.loggedIn is boolean, then you can just write
<div
className={
classNames('badge badge-pill', {
'badge-success': user.loggedIn,
'badge-danger': user.loggedIn
})
}
/>
I think it's better to avoid conditional in jsx directly. You can do something like this:
let attachClass = ['badge', 'badge-pill']
if(user.loggedIn){
attachClass = [...attachClass, 'badge-success'].join(' ');
}else{
attachClass = [...attachClass, 'badge-danger'].join(' ');
}
Than you can just return one div with className attach class:
<div className={attachClass}></div>
The issue look into the user.loggedIn is not defined or return false
const loggedIn = true;
<span className={loggedIn ? 'badge-success' : 'badge-muted'}>
Css Change </span>
Codepen

what is the equevalant for getelementbyid in angular 2 [duplicate]

I have a code:
document.getElementById('loginInput').value = '123';
But while compiling the code I receive following error:
Property value does not exist on type HTMLElement.
I have declared a var: value: string;.
How can I avoid this error?
Thank you.
if you want to set value than you can do the same in some function on click or on some event fire.
also you can get value using ViewChild using local variable like this
<input type='text' id='loginInput' #abc/>
and get value like this
this.abc.nativeElement.value
here is working example
Update
okay got it , you have to use ngAfterViewInit method of angualr2 for the same like this
ngAfterViewInit(){
document.getElementById('loginInput').value = '123344565';
}
ngAfterViewInit will not throw any error because it will render after template loading
(<HTMLInputElement>document.getElementById('loginInput')).value = '123';
Angular cannot take HTML elements directly thereby you need to specify the element type by binding the above generic to it.
UPDATE::
This can also be done using ViewChild with #localvariable as shown here, as mentioned in here
<textarea #someVar id="tasknote"
name="tasknote"
[(ngModel)]="taskNote"
placeholder="{{ notePlaceholder }}"
style="background-color: pink"
(blur)="updateNote() ; noteEditMode = false " (click)="noteEditMode = false"> {{ todo.note }}
</textarea>
import {ElementRef,Renderer2} from '#angular/core';
#ViewChild('someVar') el:ElementRef;
constructor(private rd: Renderer2) {}
ngAfterViewInit() {
console.log(this.rd);
this.el.nativeElement.focus(); //<<<=====same as oldest way
}
A different approach, i.e: You could just do it 'the Angular way' and use ngModel and skip document.getElementById('loginInput').value = '123'; altogether. Instead:
<input type="text" [(ngModel)]="username"/>
<input type="text" [(ngModel)]="password"/>
and in your component you give these values:
username: 'whatever'
password: 'whatever'
this will preset the username and password upon navigating to page.
Complate Angular Way ( Set/Get value by Id ):
// In Html tag
<button (click) ="setValue()">Set Value</button>
<input type="text" #userNameId />
// In component .ts File
export class testUserClass {
#ViewChild('userNameId') userNameId: ElementRef;
ngAfterViewInit(){
console.log(this.userNameId.nativeElement.value );
}
setValue(){
this.userNameId.nativeElement.value = "Sample user Name";
}
}

JSX with a HTML tag from a variable

I have a React component defined in JSX which returns a cell using either td or th, e.g.:
if(myType === 'header') {
return (
<th {...myProps}>
<div className="some-class">some content</div>
</th>
);
}
return (
<td {...myProps}>
<div className="some-class">some content</div>
</td>
);
Would it be possible to write the JSX in such a way that the HTML tag is taken from a variable? Like:
let myTag = myType === "header" ? 'th' : 'td';
return (
<{myTag} {...myProps}>
<div className="some-class">some content</div>
</{myTag}>
);
The above code returns an error:
"unexpected token" pointing at {.
I am using Webpack with the Babel plugin to compile JSX.
Try setting your component state and rendering like so:
render: function() {
return(
<this.state.tagName {...myProps}>
<div className="some-class">some content</div>
</this.state.tagName>
);
},
You can do something like:
const content = <div> some content </div>
return (
{myType === 'header'
? <th>{content}</th>
: <td>{content}</td>
}
)
Note that this does not really solve your question about "dynamic tag" but rather the problem you seem to have.
The first answer did not work for my case so I solved it in another way.
From React documentation each element converts to pure JS like this.
So it is possible to create elements for React component that are dynamic like this:
let myTag = myType === "header" ? 'th' : 'td';
React.createElement(
myTag,
{className: 'some-class'},
<div className="some-class">some content</div>
)

Passing JSX to components vs dangerouslySetInnerHTML

I've been working through react examples, and I've been hacking away building some components. Now I feel i'm running into a fundamental "Brain Fart", regarding component structure and nesting.
What I'm after:
Input component with Optional Labels and help text.
What I have right now: ( which does work )
Input.js
//...//
var MyInput = React.createClass( {
render: function() {
//...//
var helpText = null;
if( typeof this.props.helpText !== 'undefined' ){
helpText = <p className="help-block" > {this.props.helpText} </p>;
}
return (
<div className={ className }>
<MyLabel showLabel={ this.props.showLabel} htmlFor={ this.props.name }>
{ this.props.title }
</MyLabel>
<input
type={ this.props.type || 'text' }
name={ this.props.name }
onChange={ this.changeValue }
value={ this.getValue() }
checked={ this.props.type === 'checkbox' && this.getValue() ? 'checked' : null }
placeholder={ this.props.title }
/>
<span className='validation-error'>{ errorMessage }</span>
{helpText}
</div>
);
}
});
module.exports = MyInput;
LoginForm.js
//...//
var LoginForm = React.createClass({
// ... //
render: function() {
return (
<Form className=" col-sm-11 col-lg-10 block-center loginFrm" >
<div className="row">
<FrmInput value =""
name="username"
title="Username"
className="col-sm-5"
showLabel={false}
helpText= { <span> Help text with link </span>}
required />
<FrmInput value =""
type="password"
name="password"
title="Password"
className="col-sm-5"
showLabel={false}
required />
<button type="submit"
className="btn btn-default input-sm "
>
Sign In
</button>
</div>
<div className="row">
<div className="pull-right" >
<FrmCheckbox name="rememberMe"
title="Remember Me"
/>
</div>
</div>
</Form>
);
},
});
module.exports = LoginForm;
Making the label optional was easy. I use a BOOL showLabel property on the <MyInput/> component and pass that into the MyLabel component. showLabel is assumed TRUE, so the label is shown unless you set showLabel to false as seen above ( then <MyLabel/> just returns NULL ).
I first tried a similar method with a <help/> component to add the optional help text after the input inside <MyInput/>. Everything worked until I added a link inside the help text. Researching I found dangerouslySetInnerHTML as a means to pass HTML content into a component. While testing I also found the code above appears to work also, though I'm not exactly sold on why and how "good" this approach is.
In short it appears I'm just passing JSX objects into my component for rendering. inside <Form> (from LoginForm.js ) on the <FrmInput/> component there is a property named helpText set as follows
helpText= { <span> Help text with link </span> }
inside the <MyInput/> component I'm testing/listening for the helpText property and setting it to a variable when found (Again wrapping with JSX)
var helpText = null;
if( typeof this.props.helpText !== 'undefined' ){
helpText = <p className="help-block" > {this.props.helpText} </p>;
}
Then in the Render Method I have { helpText }
All in all it looks like I'm just passing javascript objects ( via JSX ) on through untill the final render method. I have not seen the above used in tutorials or documentation, so I'm just looking for a professional opinion.
Is the above "good" practice or how could this better be handled.
There's nothing 'wrong' with your approach. A few suggestions that can help stream line a bit.
You can shorten this block to a simple inline ternary:
var helpText = null;
if( typeof this.props.helpText !== 'undefined' ){
helpText = <p className="help-block" > {this.props.helpText} </p>;
}
You can remove the above and in your render replace {helpText} with:
{ this.props.helpText ? this.props.helpText : null }
In form input remove the inline helpText html and move to a variable using parens for the JSX.
const helpTextContent = ( <span> Help text with link </span> );
Then inline: helpText = { helpTextContent }
Lastly if you're using ES6 you can use the following syntax to make using props less cumbersome:
let { helpText, someOtherProp, anotherProp } = this.props;
Then you can just refer to helpText or someOtherProp directly without the this.prop every time.
Hope that helps!

Categories

Resources