Conditionally add element based on prop - javascript

How are you supposed to conditionally add a element like I have below? I only want <div className='next-field__connected-wrapper'> to be exist within if the withFilter prop is true.
render: function () {
if (this.props.withFilter) {
return (
<div>
<div className='next-card next-card__section next-card__section--no-bottom-spacing'>
<div className='next-field__connected-wrapper'>
{ this.props.children }
</div>
</div>
</div>
)
} else {
return (
<div>
<div className='next-card next-card__section next-card__section--no-bottom-spacing'>
{ this.props.children }
</div>
</div>
)
}
}

Keep in mind that JSX elements are just JavaScript objects and you can assign them to variables and pass them around like any other:
render: function () {
let inner = this.props.children;
if (this.props.withFilter) {
inner = (
<div className='next-field__connected-wrapper'>
{inner}
</div>
);
}
return (
<div>
<div className='next-card next-card__section next-card__section--no-bottom-spacing'>
{inner}
</div>
</div>
);
}

Related

Function doesn't do anything

Basically, I am sending an array of objects into my function as a parameter, but the function doesn't do anything. When I want to print out my array of objects, I can show all items on the console, however, I cannot render them.
renderComment() function doesn't work or doesn't return anything. Also you can take a closer look at my render method, you will see that commented code to print out the expected output of renderComment in the console.
class DishDetails extends Component {
renderDish(dish) {
if (dish) {
return (
<div>
<Card className="col-12 col-md-5 m-1">
<CardImg width="100%" src={dish.image} alt={dish.name} />
<CardBody>
<CardTitle>{dish.name}</CardTitle>
<CardText>{dish.description}</CardText>
</CardBody>
</Card>
</div>
)
} else {
return (
<div></div>
)
}
}
renderComments(comments) {
comments.map(comment => {
return (
<li key={comment.id}>
<p>{comment.comment}</p>
<p>{comment.author}</p>
</li>
)
})
}
render() {
const selected = this.props.selectedDish;
/* if(selected) {
this.props.selectedDish.comments.map(comment => {
console.log(comment.comment)
})
} */
return (
<div>
{selected &&
<div>
{this.renderDish(this.props.selectedDish)}
{this.renderComments(this.props.selectedDish.comments)}
</div>
}
</div>
)
}
}
export default DishDetails
The renderComment function does not return anything because there is no return statement in the function. There is a return in the map (which is still required), but that is not the return for the function.
To fix this, add a return at the top of renderComment, like this:
renderComment(comments) {
return comments.map(comment => {
return (
<li key={comment.id}>
<p>{comment.comment}</p>
<p>{comment.author}</p>
</li>
)
}
}

Conditional rendering on React.js

render() {
const tableStyle = this.getTableStyle();
const tableSettings = this.getTableSettings();
return (
<div style={tables}>
<TablePosition
contextMenuOn={true}
step={this.props.step}
pdfData={this.props.pdfData}
tableSettings={tableSettings}
tableStyle={tableStyle}
fileName={this.state.fileName}
tableSize={this.getTableSize()}
tableOffset={this.state.tableOffset}
desiredWidth={700}
updateXOffset={x => this.updateXOffset(x)}
updateYOffset={y => this.updateYOffset(y)}
markTable={() => this.markTable()}
setOutputLabels={(row, col, val) => this.setOuputLabels(row, col, val)}
/>
</div>
);
if (!this.props.isThirdStep) {
return (
<div>
<div style={sideBySide}>
<PDFViewer
isThirdStep={this.props.isThirdStep}
paginationCallback={this.handlePageChange}
pdfData={this.state.pdfData}
desiredWidth={600}
selectedPage={this.props.savedPageNo}
/>
</div>
</div>
);
} else {
return (
<div>
<ReferenceMenu />
</div>
);
}
}
In my component's render, I try to render several components based on certain conditions.
So, basically, the TablePoisition always stays there, and the PDFViewer and ReferenceMenu renders conditionally.
However, what I see on both conditions is only the TablePosition component.
Is this not supposed to work?
As explained since you want to combine two components you should change your render logic. One component will be sit there always and the other one will be rendered conditionally. So, you need to render that last component with the sticky one in the same return. I would do something like this:
renderPDFViewer = () => (
<div>
<div style={sideBySide}>
<PDFViewer
isThirdStep={this.props.isThirdStep}
paginationCallback={this.handlePageChange}
pdfData={this.state.pdfData}
desiredWidth={600}
selectedPage={this.props.savedPageNo}
/>
</div>
</div>
);
render() {
const tableStyle = this.getTableStyle();
const tableSettings = this.getTableSettings();
return (
<div>
<div style={tables}>
<TablePosition
contextMenuOn={true}
step={this.props.step}
pdfData={this.props.pdfData}
tableSettings={tableSettings}
tableStyle={tableStyle}
fileName={this.state.fileName}
tableSize={this.getTableSize()}
tableOffset={this.state.tableOffset}
desiredWidth={700}
updateXOffset={x => this.updateXOffset(x)}
updateYOffset={y => this.updateYOffset(y)}
markTable={() => this.markTable()}
setOutputLabels={(row, col, val) => this.setOuputLabels(row, col, val)}
/>
</div>
{
!this.props.isThirdStep
? this.renderPDFViewer()
: ( <div><ReferenceMenu /></div> )
}
</div>
);
}
You need to place your conditional renders inside variables or something similar.
var conditionContent1 = null;
var conditionContent2 = null;
if(condition1){
conditionContent1 = <div>conditional content 1</div>;
}
if(condition2){
conditionContent2 = <div>conditional content 2</div>;
}
return (
<div id="wrapper">
<div>
content
</div>
{conditionContent1}
{conditionContent2}
</div>
);
I added a wrapper div; because, I believe render's return doesn't like having multiple root elements.
If the variables are null; then, it won't affect the overall render.

Filtering Object into two groups by matched object key value

Lets say that I have the following object
var transformers = [
{
name: 'Optimus Prime',
form: 'Freightliner Truck',
team: 'Autobot'
},
{
name: 'Megatron',
form: 'Gun',
team: 'Decepticon'
},
{
name: 'Bumblebee',
form: 'VW Beetle',
team: 'Autobot'
},
{
name: 'Soundwave',
form: 'Walkman',
team: 'Decepticon'
}
];
How can I render two groups depending on the team value
<div>
<h1>Autobot Team</h1>
... //Here goes the corresponding matches
</div>
<div>
<h1>Decepticon Team</h1>
... //Here goes the corresponding matches
</div>
I tried this with no luck
renderTeam(){
transformers.map(team =>{
if(team.team === "Autobot"){
return(
<div>{team.name}</div>
)
}
if(team.team === "Decepticon"){
return(
<div>{team.name}</div>
)
}
})
}
<div>
<h1>Autobot Team</h1>
{this.renderTeam()}
</div>
<div>
<h1>Autobot Team</h1>
{this.renderTeam()}
</div>
Your function renderTeam could take a string parameter that allows you to filter and map the array:
renderTeam(team) {
return transformers
.filter(transformer => transformer.team === team)
.map(transformer => (<div key={transformer.name}>{transformer.name}</div>);
}
render() {
return (
<div className="transformer-teams">
<div>
<h1>Autobot Team</h1>
{renderTeam('Autobot')}
</div>
<div>
<h1>Decepticon Team</h1>
{renderTeam('Decepticon')}
</div>
</div>
);
}
To achieve that pass a parameter to renderTeam method that will contain any one team name, and it will return the ui elements. Don't forgot to return the result from that renderTeam method.
Also assign unique key to each element inside loop.
Like this:
<div>
<h1>Autobot Team</h1>
{this.renderTeam('Autobot')}
</div>
<div>
<h1>Autobot Team</h1>
{this.renderTeam('Decepticon')}
</div>
renderTeam(team){
let items = [];
transformers.forEach((item,i) => {
if(item.team === team)
items.push(<div key={i}>{item.name}</div>);
})
return items;
}
But with this approach you need to run the same loop again, so to avoid that you can write it like this also:
renderTeam(){
let team1 = [], team2 = [];
transformers.forEach((item,i) => {
if(item.team === 'Autobot')
team1.push(<div key={i}>{item.name}</div>);
else if(item.team === 'Decepticon')
team2.push(<div key={i}>{item.name}</div>);
})
return (
<div>
<div>
<h1>Autobot Team</h1>
{team1}
</div>
<div>
<h1>Autobot Team</h1>
{team2}
</div>
</div>
)
}
render(){
return(
<div>
{this.renderTeam()}
</div>
)
}

React: How to show message when result is zero in react

How to show No Result message when the search result is empty with in map() ?
export class Properties extends React.Component {
render () {
const { data, searchText } = this.props;
const offersList = data
.filter(offerDetail => {
return offerDetail.city.toLowerCase().indexOf(searchText.toLowerCase()) >= 0;
})
.map(offerDetail => {
return (
<div className="offer" key={offerDetail.id}>
<h2 className="offer-title">{offerDetail.title}</h2>
<p className="offer-location"><i className="location-icon"></i> {offerDetail.city}</p>
</div>
);
});
return (
<main>
<div className="container">
<h1>Main {offersList.length}</h1>
{ offersList }
</div>
</main>
);
}
}
With a ternary operator:
<main>
<div className="container">
<h1>Main {offersList.length}</h1>
{ offersList.length ? offersList : <p>No result</p> }
</div>
</main>
If offersList array is empty, it's length will equal to 0. You can make easy condition:
<div className="container">
<h1>Main {offersList.length}</h1>
{ offersList.length ? offersList : <p>No Result</p> }
</div>
{offersList.length ? (
// html markup with results
) : (
// html markup if no results
)}

Render JSX element based on condition

So I have a simple component within a web app I have been working on and I was wondering if there is a way I could render an element within this component based on the value of this.props.item.
here is my JSX:
var React = require("react"); var actions = require("../actions/SchoolActions");
module.exports = React.createClass({
deleteSchool: function(e){
e.preventDefault();
actions.deleteSchool(this.props.info);
},
render:function(){
return(
<div className="panel panel-default">
<div className="panel-heading">
{this.props.info.name}
<span className="pull-right text-uppercase delete-button" onClick={this.deleteSchool}>×</span>
</div>
<div className="panel-body">{this.props.info.tagline}</div>
</div>
)
} })
I wanted to be able to do something like this:
render:function(){
return(
code blah blah...
if (this.props.info = "nothing"){
<div className="panel-body">{this.props.info.tagline}</div>
}
...code blah blah
But I cannot write javascript withing the render function itself. Does anyone know how I could do this? Any help or advice is appreciated, thank you in advance.
You can use conditionally render using if and return the appropriate jsx
render(){
if(something){
return(<MyJsx1/>)
}else{
return(<MyJsx2/>)
}
}
You can chaage your component to:
render:function(){
return(
<div className="panel panel-default">
<div className="panel-heading">
{this.props.info.name}
<span className="pull-right text-uppercase delete-button" onClick={this.deleteSchool}>×</span>
</div>
{this.props.info = "nothing"?
(<div className="panel-body">{this.props.info.tagline}</div>)
:null}
</div>
)
} })
https://facebook.github.io/react/docs/conditional-rendering.html
Single line example
{(this.state.hello) ? <div>Hello</div> : <div>Goodbye</div>}
or
{(this.state.hello) ? <div>Hello</div> : false}
I often create an explicit function to to this, to avoid clutter in the main render:
var ChildComponent = React.createClass({
render: function () {
return (<p>I am the child component</p>)
}
});
var RootComponent = React.createClass({
renderChild: function () {
if (this.props.showChild === 'true') {
return (<ChildComponent />);
}
return null;
},
render: function () {
return(
<div>
{ this.renderChild() }
<p>Hello World!</p>
</div>
)
}
});
http://reactkungfu.com/2016/11/dynamic-jsx-tags/
For many React developers using JSX it is not clear how to make a
dynamic JSX tag. Meaning that instead of hardcoding whether it is
input or textarea or div or span (or anything else) we would like to
keep it in a variable.

Categories

Resources