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
)}
Related
Instagram clone:
I want to check if I follow my follower then display <button>unfollow</button> or if not display <button>follow</button>
var IfollowAndHeFollowMe;
myfollowers.map(follower => {
return(
<div>
<div>{follower.userName}</div>
{ IfollowAndHeFollowMe =
myfollowings.filter((following) => following.userName == follower.userName)
}
// this doesn't work
{ IfollowAndHeFollowMe.length > 0 ? return( <button>unfollow</button>): return(<button>follow</button>) }
// and this also doesn't work
{ return IfollowAndHeFollowMe.length > 0 ? <button>unfollow</button> : <button>follow</button>}
</div>
)
})
//https://instagram-app-clone.netlify.app/ --- just for phone ---
JSX Code inside {} should be written as statements.
https://reactjs.org/docs/conditional-rendering.html
const followers = ['John', 'Hanna'];
function RenderMap() {
return (
<React.Fragment>
{followers.map(follower => (
<div>
<span>{follower}</span>
{followers.length > 0 ? (
<button>unfollow</button>
) : (
<button>follow</button>
)}
</div>
))}
</React.Fragment>
);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
// now dont have errors but its allways display button with follow text
{Data[2][0].followers.map(follower => {
idFollowers++;
return (
<div className="follower" id={idFollowers} >
<img src={follower.profilna} className="profilnaFollower" alt="" />
<div className="userInfoFollower">
<h3>{follower.userName}</h3>
<p>{follower.name}</p>
</div>
{dbFollow = Object.entries(Data[2][0].following).filter(following => following.userName == follower.userName)}
{dbFollow.length > 0 ? (<button>unfoldasdaslow</button>) : (<button>fodsadsllow</button>)}
</div>
)
})}
</div>
I have an array of files and I want certain ones to be displayed and hyperlinked. I'm using the map method and when only 1 file displays, it links properly. I need some help with the syntax when multiple files must be displayed.
render() {
const mappings = {
'P1011': 'http://192.168.191.128:8080/Pickering-P1011-May-Verified_Results5.xls',
'P1511': 'http://192.168.191.128:8080/PNGS-1511-Verified_Results_2.xls',
'P1711': 'http://192.168.191.128:8080/PNGS-P1711_Verified_Results_3.xlsx',
'P1911': 'http://192.168.191.128:8080/PLGS_Unit_1-PL1911_VerifiedResults2.xlsx',
}
if (this.props.channelSelectedData.length >= 1){
return(
<div className="channel-detail-box">
<p>Outages:
<a href={mappings[this.props.channelSelectedData.map(inspection => {
return inspection.outage
})]}>
{this.props.channelSelectedData.map(inspection => {
return inspection.outage + ' '
})}</a>
</p>
</div>
)
}
else {
return (
<div>
<p>No data found</p>
</div>
)
}
}
}
Is this what you are looking for ?
render() {
const mappings = {
'P1011': 'http://192.168.191.128:8080/Pickering-P1011-May-Verified_Results5.xls',
'P1511': 'http://192.168.191.128:8080/PNGS-1511-Verified_Results_2.xls',
'P1711': 'http://192.168.191.128:8080/PNGS-P1711_Verified_Results_3.xlsx',
'P1911': 'http://192.168.191.128:8080/PLGS_Unit_1-PL1911_VerifiedResults2.xlsx',
}
const { channelSelectedData } = this.props
if (channelSelectedData.length === 0) {
return <div>
<p>No data found</p>
</div>
}
return <div className="channel-detail-box">
<p>Outages: {channelSelectedData.map(({ outage }) => <a href={mappings[outage]}>{outage}</a>)}</p>
</div>
}
const mappings = {
'P1011': 'http://192.168.191.128:8080/Pickering-P1011-May-Verified_Results5.xls',
'P1511': 'http://192.168.191.128:8080/PNGS-1511-Verified_Results_2.xls',
'P1711': 'http://192.168.191.128:8080/PNGS-P1711_Verified_Results_3.xlsx',
'P1911': 'http://192.168.191.128:8080/PLGS_Unit_1-PL1911_VerifiedResults2.xlsx',
};
if (!channelSelectedData || channelSelectedData.length <= 0) {
return (
<div>
<p>No data found</p>
</div>
);
}
const links = channelSelectedData.map(({ outage }) => (
<a href={mappings[outage]}>{outage}</a>
));
return (
<div className="channel-detail-box">
<p>Outages: {links}</p>
</div>
);
If I am understanding the rest of your question correctly, I believe your issue is just using map at the incorrect point. What map does is returns an array of values which in this case would be an array of applicable tags.
render() {
const mappings = {
'P1011': 'http://192.168.191.128:8080/Pickering-P1011-May-Verified_Results5.xls',
'P1511': 'http://192.168.191.128:8080/PNGS-1511-Verified_Results_2.xls',
'P1711': 'http://192.168.191.128:8080/PNGS-P1711_Verified_Results_3.xlsx',
'P1911': 'http://192.168.191.128:8080/PLGS_Unit_1-PL1911_VerifiedResults2.xlsx',
}
if (this.props.channelSelectedData.length >= 1){
return(
<div className="channel-detail-box">
<p>Outages:
<>
{
this.props.channelSelectedData.map(chanel=>{
return (
<a href={mappings[chanel]}>
{chanel+' '}
</a> )
})
}
</>
</p>
</div>
)
}
else {
return (
<div>
<p>No data found</p>
</div>
)
}
}
I'm trying to make a components props(sideBarInfo) details show up on the left column of a Page after clicking on a corresponding component(thumbnail) on the right column of the same Page.
Please note that all imports and exports are used in the main project(i removed them here).
I've also imported all components into the main (Page.js). Yet i keep getting a Type error for the onClick.
This is the first component - Thumbnail
class Thumbnail extends React.Component {
render(){
return (
<div className="Work" onClick={(e) => this.props.click(this.props.work)} >
<div className="image-container">
<img src={this.props.work.imageSrc} alt={this.props.work.imageSrc}/>
</div>
<div className="Work-information">
<p> {this.props.work.work}</p>
</div>
</div>
);
} }
This is the ThumbnailList
class ThumbnailList extends React.Component {
constructor(props){
super(props);
this.state= {
works: [
{
id: 0,
work: 'Work 1',
imageSrc: W1,
view: '#',
selected: false
},
{
id: 1,
work: 'Work 2',
imageSrc: W2,
view: '#',
selected: false
},
]
}
}
handleCardClick = (id,card) => {
console.log(id);
let works= [...this.state.works];
works[id].selected = works[id].selected ? false : true ;
works.forEach(work=>{
if(work.id !== id){
work.selected = false;
}
});
this.setState({
works
})
}
makeWorks = (works) => {
return works.map(work => {
return <Thumbnail work={work} click={(e => this.handleCardClick(work.id,e ))} key={work.id} />
})
}
render(){
return(
<div>
<div className="scrolling-wrapper-flexbox">
{this.makeWorks(this.state.works)}
</div>
</div>
);
}
}
This is the sidebarInfo
function SidebarInfo(props) {
return (
<img width="370" height="370" src= {props.imageSrc} />
<p> {props.work} </p>
);}
This is the problematic Page - the boldened keeps giving a Type error(cannot read property 'selected' of undefined.)
class Page extends React.Component {
render() {
return (
<span>
<div className="column left">
<div className="">
**{this.props.work.selected && <SidebarInfo imageSrc={this.props.imageSrc} /> }**
</div>
</div>
<div className="column right" >
<div>
<ThumbnailList />
</div>
</div>
</span>
)
}
}
You may need to add a check in this.props.work.selected like this this.props.work && this.props.work.selected
To ensure that this.props.work is defined before checking on this.props.work.selected
I was able to answer this for anyone interested.
there were some foundational errors in my file arrangement which have been corrected.
After refactoring, i was able to achieve what i wanted using 3 classes/functions in; App.js, Thumbnail.js and SideBarInfo.js
see one working solution with styling on this sandbox: https://codesandbox.io/s/modern-sky-y9d3c
See Solution below;
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
works: [
{
id: 0,
work: "Work 1",
imageSrc:
"https://images.unsplash.com/photo-1584608168573-b6eec7a04fd7?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=701&q=80",
view: "#",
selected: false
},
{
id: 1,
work: "Work 2",
imageSrc:
"https://images.unsplash.com/photo-1581665269479-57504728e479?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=701&q=80",
view: "#",
selected: false
}
]
};
this.handleCardClick = this.handleCardClick.bind(this);
this.makeWorks = this.makeWorks.bind(this);
this.showWorks = this.showWorks.bind(this);
}
handleCardClick = (id, Thumbnail) => {
console.log(id);
let works = [...this.state.works];
works[id].selected = works[id].selected ? false : true;
works.forEach((work) => {
if (work.id !== id) {
work.selected = false;
}
});
this.setState({
works
});
};
makeWorks = (works) => {
return works.map((work) => {
return (
<Thumbnail
work={work}
click={(e) => this.handleCardClick(work.id, e)}
key={work.id}
/>
);
});
};
showWorks = (works) => {
let i = 0;
var w = [];
while (i < works.length) {
if (works[i].selected) {
w = works[i];
}
i++;
}
return ( <SidebarInfo imageSrc={w.imageSrc} work={w.work} /> );
};
render() {
return (
<div className="App">
<span>
<div> { this.showWorks(this.state.works)} </div>
<div className="">
<div className="scrolling-wrapper-flexbox">
{this.makeWorks(this.state.works)}
</div>
</div>
</span>
</div>
);
}
}
class Thumbnail extends React.Component {
render() {
return (
<div>
<div className="column left">
{/* this.props.work.selected && <SidebarInfo work={this.props.work.work} imageSrc={this.props.work.imageSrc}/> */}
</div>
<div className="column right">
<div className="Work" onClick={(e) => this.props.click(this.props.work)}>
<div className="image-container">
<img src={this.props.work.imageSrc} alt={this.props.work.imageSrc} />
</div>
<div className="Work-information">
<p> {this.props.work.work}</p>
</div>
</div>
</div>
</div>
);
}
}
export default Thumbnail;
function SidebarInfo(props) {
return (
<div className="one">
<div className="Work">
<h1> NAME </h1>
<div className="image-container">
<img
width="370"
height="370"
src={props.imageSrc}
alt={props.imageSrc}
/>
</div>
<p> {props.work} </p>
<p> {props.view} </p>
</div>
</div>
);
}
export default SidebarInfo;
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>
)
}
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>
);
}