I have a functional component in my React app that makes an API call and gets back a response featuring two contact methods Phone Number and Email and displays them next to their respective icon.
Some responses may only have one or the other contact method or neither.
In the event that a response doesn't have a contact method listed I still want to display the icon and place '--' where the data would be.
Here's my first pass at the logic where I tried writing out a few quick ternary methods, but right now all that renders on each row is [object Object][object Object]
let renderContactDetails = methods.map(method => {
return (
<div>
{
method.contactMethodType === "M" ? `${<span><PhoneSvg /> {method.number}</span>}` : `${<span><PhoneSvg /> -- </span>}`
}
{
method.contactMethodType === "E" ? `${<span><AtSymbolSvg /> {method.emailAddress}</span>}` : `${<span><AtSymbolSvg /> -- </span>}`
}
</div>
);
});
Any suggestions?
You only need to define JavaScript inside template literals and let JSX convert the html tags for you like this:
let renderContactDetails = methods.map(method => {
const number = method.contactMethodType === "M" ? `${method.number}` : `--`;
const email = method.contactMethodType === "E" ? `${method.emailAddress}` : `--`;
return (
<div>
<span><PhoneSvg /> {number}</span>
<span><PhoneSvg /> {email}</span>
</div>
);
});
You mixed up template strings with jsx syntax. Just do:
let renderContactDetails = methods.map(method => {
return (
<div>
{
method.contactMethodType === "M" ? <span><PhoneSvg /> {method.number}</span> : <span><PhoneSvg /> -- </span>
}
{
method.contactMethodType === "E" ? <span><AtSymbolSvg /> {method.emailAddress}</span> : <span><AtSymbolSvg /> -- </span>
}
</div>
);
});
And then render it.
return (
{renderContactDetails}
)
You don't need to wrap everything in a string, that is making your components to call toString() method, turning into [object Object]. Try doing something like this:
let renderContactDetails = methods.map(method => {
return (
<div>
{
method.contactMethodType === "M" ?
<span><PhoneSvg /> {method.number}</span>} :
<span><PhoneSvg /> -- </span>
}
{
method.contactMethodType === "E" ?
<span><AtSymbolSvg /> {method.emailAddress}</span> :
<span><AtSymbolSvg /> -- </span>
}
</div>
);
});
Related
I am using a BlueprintJS button and my code look something like this:
<Button
text={`${user.name} (${user.invoicesCount?.unresolved ?? 0})
${user.resolvingUsers.length > 0 ? "| " +
user.resolvingUsers.map((u: any) => {
return u.name;
}).join(", ")
: "" }`}
/>
I want to wrap the user.resolvingUsers.map() in a span tag so I could style it. I tried to wrap it as such:
<Button
text={`${user.name} (${user.invoicesCount?.unresolved ?? 0})
${user.resolvingUsers.length > 0 ? "| " +
<span>
{user.resolvingUsers.map((u: any) => {return u.name;}).join(", ")}
</span>
: "" }`}
/>
However, this return me a [object Object] and I am not sure why this is happening. I thought that by using join(), it would be converted into string?
It depends if your Button text prop accepts Elements but it would be something like:
text={<div>
{`${user.name} (${user.invoicesCount?.unresolved ?? 0})`}
{user.resolvingUsers.length > 0 ? (
<>
<span> | </span>
<span>{user.resolvingUsers.map((u) => u.name).join(", ")}</span>
</>
) : (
0
)}
</div>}
I am having an error with if else question mark in react.
let skillSetStr = useSkillset(userInfo.Skills);
// In some cases the db returns the userInfo in different objects.
// For now this fixes the problem.
if (userInfo.Skills === undefined) {
skillSetStr = skillStr;
}
{skillSetStr ?
<div className="user-preview-info">
<div className="grid-item">Skillsets:</div>
<div className="grid-item user-preview-info_data">
{userInfo.Skills ?
<div>
{userInfo.Skills.map(
(skillName, index) => <div key={index} className="user-skill"> {skillName.skill} </div>
)}
</div>
: <div>Unspecified</div>}
</div>
</div> : ""}
So in if else condition it's suppose return "Unspecified" for in but instead it's return null.
Here is how my project look like:
How can I fix this error?
If it is saying that the array is undefined you can check it isn't empty before getting its length with "option chaining".
It would look like this:
userInfo?.Skills?.length > 0 this removes the need to do two checks.
when I type 1sport1 I see the results.
when I type 1sport12 I dont see any results.
so that type I need to show no dta found.
and on clear all it should clear the text box.
but the problem is this line console.log("resp.json()--->", resp.json().[[PromiseValue]]);
I thought when length is 0 I will show the no data found.
but I am getting this error./src/searchbar.js: Unexpected token (31:48)
I am commenting the below lines so that you can see output in the browser
// console.log("resp.json()--->", resp.json().[[PromiseValue]]);
// display: this.state.noData ? "" : "none"
can you tell me how to show no data found when there is no data coming from api.
providing my code snippet and sandbox below.
https://codesandbox.io/s/jovial-cdn-14o1w
getQuery = async (type = "", search_tag = "") => {
var url = "https://hn.algolia.com/api/v1/search?tags=";
const resp = await fetch(`${url}${type}&query=${search_tag}`);
// console.log("resp.json()--->", resp.json().[[PromiseValue]]);
return resp.json();
};
render() {
console.log("this.state.noData--->", this.state.noData);
return (
<div>
<input type="text" onChange={this.searchByKeyword} />
<p
style={
{
// display: this.state.noData ? "" : "none"
}
}
>
No data found
<p>clear all</p>
</p>
{/* <Scroll /> */}
</div>
);
You can achieve this using conditional rendering on JSX.
Change your code to following and it will work.
<SearchBar onFetch={this.onFetch} />
{this.state.data && this.state.data.length > 0 ?
this.state.data.map((item) => <div key={item.objectID}>{item.title}</div>) :
<p>no data</p>}
I forked the sandbox and is here
LONG STORY SHORT: I would like for it to load the object in the nested array IF it is not equal to undefined but react throws typeError
I have this component that takes props from a parent component. Essentially I have an array that contains chat information and when I try to access it in this child component I get some very strange behaviour.
for example if I console log(props.conversations) I get my array which looks like this: conversations[{host, members[{ username }], log[{ author, content, timestamp }]}].
if I console log (props.conversations[0]) ill get the first object in that array. But if I console log (props.conversations[0].log) I get undefined. And thats fine because at the start the state will not be defined or contain anything, so I put a ternary operator as shown below in the code props.conversations[props.index].log[0] == null ?
but all i get is TypeError: Cannot read property 'log' of undefined at the ternary function.
Maybe I am not understanding this correctly or maybe it how react functions?
Again I would like for it to load the object in the nested array IF it is not equal to undefined.
Highly appreciate the help. The most important part is the friends component. I only show the other ones to show the state being passed down.
function Friends(props) {
console.log(props.conversations[props.index]);
return (
<div className="friend">
<img className="friendavatar" src={require("./static/bobby.jpg")}></img>
<div className="friendname">{props.username}</div>
<span className="iswatchingtitle"> is watching <strong>{props.watching}</strong></span>
<div className="friendchat" onClick={props.togglechat}>
{props.conversations[props.index].log[0] == null ?
<div>undefined</div>
:
<div>defined!</div>
}
</div>
</div>
)
}
social component
function Social(props) {
return (
<div>
<div className="userquickdash row">
<div className="usernamedash">{props.username}</div>
<div className="logout"><a href="/users/logout" onClick={props.fetchlogout}>logout</a></div>
</div>
<div>
<form className="search-form-flex" method="GET" action="/search">
<input className="user-search" id="search" type="search" placeholder=" Search users..." name="usersearch"></input>
</form>
</div>
<div className='friendchatcontainer' refs='friendchatcontainer'>
{/* Append friends from social bar state (props.friends). For each friend return appropriate object info to build Friends div using Friends(props) function above. */}
{props.friends.map(function(friend, index) {
// Shortens length of video title if length of string is over 48.
let friendWatching = function friendWatchingLengthSubstring() {
if (friend.watching.length > 57) {
let friendWatching = friend.watching.substring(0, 54) + '...';
return friendWatching;
} else {
friendWatching = friend.watching;
return friendWatching;
}
};
return (
<Friends username={friend.username}
watching={friendWatching()}
key={index}
index={index}
togglechat={props.togglechat}
conversations={props.conversations}
/>
)
})}
</div>
</div>
)
}
socialbar component
class Socialbar extends Component {
constructor(props) {
super(props);
this.state = { isLoggedIn: (cookies.get('loggedIn')),
sidebarximgSrc: sidebarcloseimg,
sidebarStatus: 'open',
username: cookies.get('loggedIn'),
friends: friends,
users: {},
conversations: [],
};
}
// function to run when mongodb gets information that state has changed.
// test if the current state is equal to new object array.
// then do something.
appendFriends() {
}
componentDidMount() {
if (this.state.sidebarStatus === 'open') {
document.getElementsByClassName('maindash')[0].classList.add('maindashwide');
this.openSideBar();
} else {
document.getElementsByClassName('maindash')[0].classList.remove('maindashwide');
this.closeSideBar();
}
// check for user logged in cookie, if true fetch users.
if (this.state.isLoggedIn) {
this.fetchUsers();
}
this.getFriendConversations();
};
getFriendConversations() {
// build loop function that updates state for conversations based on length of friends array in state.
var conversationsArray = this.state.conversations;
for (var i = 0; i < friends.length; i++) {
console.log(aconversationbetweenfriends[i]);
conversationsArray.push(aconversationbetweenfriends[i]);
}
this.setState({conversations: conversationsArray});
}
render() {
let sidebar;
const isLoggedIn = this.state.isLoggedIn;
if (!isLoggedIn) {
sidebar = <Login />
} else {
sidebar = <Social username={this.state.username} friends={this.state.friends} fetchlogout={this.fetchlogout} togglechat={this.togglechat} conversations={this.state.conversations} />
}
return (
<div>
<div className="sidebar sidebar-open" ref="sidebar">
<div className="sidebarcontainer">
{sidebar}
</div>
</div>
<div className="sidebarx sidebarxopen" ref="sidebarx" onClick={this.toggleSideBar}>
<img className="sidebaropenimg" src={this.state.sidebarximgSrc} ref='sidebarximg'></img>
</div>
</div>
);
}
};
It is not a good idea to access the element directly before validation.
Use something like this:
props.conversations[props.index] && props.conversations[props.index].log[0]
Tip: User object destructuring and default props.
You need to compare for undefined like this :
{props.conversations[props.index].log[0] === undefined ?
<div>undefined</div>
:
<div>defined!</div>
}
Also, You can go to below link for sandbox running example.
Sandbox link for example to show how you should check for undefined
Hi first of all check your {props.index} print this value. if it is proper then try this out.
{
props.conversations[props.index] ?
props.conversations[props.index].log[0] ? <div>defined!</div>:<div>Undefined</div>
:
<div>Undefined</div>
}
This will check if props.conversations[props.index] is defined then and then only try to process props.conversations[props.index].log[0]. So you will not get TypeError: Cannot read property 'log' of undefined at the ternary function.
In my react render function, I am using array.map to return some JSX code in an array and then rendering it. This doesn't seem to work, I read a few questions here that suggested using return statement inside if/else block but that won't work in my case. I want to check whether round and duration are set on each array element and only then pass it in the JSX code.Could someone tell me a different approach please.
render() {
var interviewProcessMapped = interviewProcess.map((item, index) => {
return
{item.round ?
<div className="row title">
<div className="__section--left"><span className="section-title">Round {index + 1}</span></div>
<div className="__section--right">
<h3>{item.round}</h3>
</div>
</div>
: null
}
{
item.durationHours > 0 || item.durationMinutes > 0 ?
<div className="row">
<div className="__section--left">Duration</div>
<div className="__section--right border">
{item.durationHours > 0 ? <span>{item.durationHours} Hours</span> : null} {item.durationMinutes > 0 ? <span>{item.durationMinutes} Minutes</span> : null}
</div>
</div>
: null
}
});
return <div>{interviewProcessMapped}</div>
}
{ not required here:
return {item.round ?
If you use it that means you are returning an object.
Another issue is alone return means return; (automatic semicolon insertion) so either put the condition in same line or use ().
Write it like this:
render() {
let a, b;
var interviewProcessMapped = interviewProcess.map((item, index) => {
a = item.round ?
<div className="row title">
....
</div>
: null;
b = (item.durationHours > 0 || item.durationMinutes > 0) ?
<div className="row">
....
</div>
: null;
if(!a || !b)
return a || b;
return [a, b];
});
return (....)
}
You should probably use a combination of Array.prototype.map() and Array.prototype.filter()
No need for if at all
Here the pseudo code:
interviewProcess.filter(() => {
// return only if round and duration set
}).map(() => {
// transform the filtered list
});