I have 3 variables that I must evaluate to hide a div if a condition is met between these 3 variables, something like this:
appState.fullResults
appState.someResults
appState.otherResults
So, when appState.fullResults and appState.someResults come empty, but appState.otherResults has something, I need to hide a div, this code snippet is an example:
<div classname='container'>
<div classname='full-some'>
boxes
</div>
<divclassname='others'>
boxes
</div>
</div>
I try something like this, but dont work
className={`${
(!appState.someResults?.length > 0 && otherResults?.length > 0)
? 'container-boxcard'
: 'd-none'
}`}
I always get the same result: if othersResults brings something and someResults brings nothing, the "d-none" is not passed to hide it
https://imgur.com/bZBUGo9
Still evaluates false and applies the d-none class
Hope I have explained well, thank you for your help.
Try this :
const { fullResults, someResults, otherResults } = appState;
const className = !fullResults?.length && !someResults?.length
&& otherResults?.length ? 'd-none' : 'container-boxcard';
<YourComponent className={className} {...props} />
!appState.someResults?.length > 0 is hard to understand, I'd suggest you should change it to !appState.someResults?.length or appState.someResults?.length === 0 (you can choose one of them).
I haven't seen you declared otherResults anywhere else, so I'd assume that otherResults?.length > 0 should be appState.otherResults?.length (or appState.otherResults?.length > 0).
className={`${(!appState.someResults?.length && appState.otherResults?.length)
? 'd-none'
: 'container-boxcard'
}`}
when appState.fullResults and appState.someResults come empty, but appState.otherResults has something
According to your demonstration, you can follow this with 3 conditions
className={`${(!appState.someResults?.length && !appState.fullResults?.length && appState.otherResults?.length)
? 'd-none'
: 'container-boxcard'
}`}
finally it was a problem with the function that created the objects fullResults, someResults & otherResults, it was passing all the answer to the object, creating another object inside, that's why always the object even if it had no data inside, evaluated length greater than 0 because it had something inside,
setAppQuotationState({
loading: false,
fullResults: fullResults?.length > 0 ? [fullResults] : [],
someResults: someResults?.length > 0 ? [someResults] : [],
otherResults: otherResults?.length > 0 ? [otherResults] : [],
})
}
correcting that bug, the solutions that I indicated, worked well.
Related
state = {
count: 1,
};
render() {
let classes = "badge m-5 bg-";
let { count } = this.state;
count === 1 ? (classes += "success") : (classes += "warning");//1st Condition
classes+= (count===1)?"success" : "warning";//2nd Condition
return (
<div className="container">
<span style={this.styles} className={classes} id="bad">
Hello!
</span>
</div>
);
}
I understood how that if condition works(condition ? true: false), but in the 2nd condition how it is possibly working even after placing the classes+= even before mentioning the condition?
Let's break it down. Remember, our initial value of count is 1.
let classes = "badge m-5 bg-";
...
classes+= (count===1)?"success" : "warning";
Firstly what'll happen is that count===1 will be checked for strict equality (it takes precedence), which will yield true. Since our condition is true, and we're using ternary operator, the expression returns "success" string, i.e.,
this:
classes+= (count===1)?"success" : "warning";
becomes this:
classes+= "success";
"success" will be appended to the classes string, therefore classes will become badge m-5 bg-success
In 2nd Condition, tt related to javascript operator precedence. ?: before +=
In Javascript, ternary operator (?...:) takes precedence over assignment (+=), so the right hand of the += resolves first and append either "success" or "warning" to classes.
Reference: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence#table
I have a scenario like showing text as well adding class togathered. it look like i require to add multiple times with same elements nearly. what would be the correct approach for this kind of scenarios?
here is my template:
<span><a className={this.state.showMore ? 'active' : ''} onClick={this.showMore}>{this.state.showMore ? 'read less' : 'read more'}</a></span>
i have added the state showMore both a tag and the text inside. is there any simple way to handle same conditions across page?
Thanks in advance.
I'd create a component to handle read-more, and pass the props from where it's used if there's any, So same functionality is same across my application and if there's any improvements I can handle by it in one single place.
here is a demo
EX: functional component
export const ReadMore = ({ text, truncateLength = 10 }) => {
const [showMore, setShowMore] = useState(false);
const getText = () => {
if (showMore) {
return text;
}
const truncatedText = text.substring(0, truncateLength);
if (text.length > truncateLength) {
return `${truncatedText}...`;
}
return truncatedText;
};
return (
<span>
{getText()}
<a
className={showMore ? "active" : ""}
onClick={() => setShowMore(!showMore)}
>
{text.length > truncateLength && (showMore ? "read less" : "read more")}
</a>
</span>
);
};
and use it like this props could be:
text: is the text that should be read-less or more.
truncateLength: is the length that should show if the text length is
greater, and optional prop, if this isn't provided ReadMore
component will set the value to 10 by default, (check the props of
ReadMore)
<ReadMore
text="this is the text that should do the react-more and read-less"
truncateLength={10}
/>
{this.state.showmore ?
<span><a className={'active'} onClick={this.showMore}>read less</a></span>
:
<span><a onClick={this.showMore}>read more</a></span>
}
should be a more readable and clearer way of doing this. Basically when you have >1 thing depending on the same condition, take the condition outside would be my way to go!
I've been struggeling with this basic stuff for a while now, but I cant seem to get it to work.
I'm getting data from our backend and if there're any deliveries objects it will be displayed with this:
<Expandable>
<ObjectDisplay
key={id}
parentDocumentId={id}
schema={schema[this.props.schema.collectionName]}
value={this.props.collection.documents[id]}
/>
</Expandable>
But if there is no deliveries I'd like to display a message like there's no deliveries. I can use .length and !deliveries (I get that), but it seems like my conditional isn't working:
render() {
console.log(this.props.collection.ids.length) //Getting how many deliveries there are with their id
return (
<div>//Struggling with this:
{!this.props.collection.ids && this.props.collection.ids.length < 1
? <p>No deliviers</p>
: <div className="box">
{this.props.collection.ids
.filter(
id =>
// note: this is only passed when in top level of document
this.props.collection.documents[id][
this.props.schema.foreignKey
] === this.props.parentDocumentId
)
.map(id => {
return (
<Expandable>
<ObjectDisplay
key={id}
parentDocumentId={id}
schema={schema[this.props.schema.collectionName]}
value={this.props.collection.documents[id]}
/>
</Expandable>
)
})}
</div>}
</div>
)
}
I bet my problem is super basic, but I just can't get it to work.. Help is much appreciated!!
Change your && to ||. You want to render "no delivers" if you have no ids (first test) OR if your ids.length is < 1
Your problem seems indeed to be with your condition.
!this.props.collection.ids && this.props.collection.ids.length < 1
!this.props.collection.ids is only true when the array is falsy. However, an empty array is not falsy - it's truthy.
this.props.collection.ids.length < 1 is true when the array is empty.
Since you are doing && you require the array to be falsy and empty at the same time, which can never happen.
So simply change the condition from && to || and it should work. In other words:
!this.props.collection.ids || this.props.collection.ids.length < 1
though I think this is prettier:
!this.props.collection.ids || !this.props.collection.ids.length
Your condition throws an error. See here
!this.props.collection.ids && this.props.collection.ids.length < 1
^
!false && undefined
Change your condition to
this.props.collection.ids && this.props.collection.ids.length > 1
and put your placeholder in the else block of your ternary.
I was wondering of a good way to conditionnally render a list of items. Basically I want to render a warning message, if there's a warning, I want to render message to contain a list of all the problems, here is my current approach :
text = (
<div>Orange fields are not mandatory, are you sure you want to submit without :
<ul>
{(() => {
if (e.infos.error === "warning")
return <li>informations</li>
})()}
{(() => {
if (e.links.error === "warning")
return <li>links</li>
})()}
{(() => {
if (e.file.error === "warning")
return <li>file</li>
})()}
</ul>
</div>);
that's ugly, but I wanted to test something, so another approach I took was something like that :
function optionalWarning(props) {
if (props.error === "warning")
return <li>{props.message}</li>;
return null;
}
....
text = (
<div>Orange fields are not mandatory, are you sure you want to submit without :
<ul>
<optionalWarning error="e.infos.error" message="informations" />
<optionalWarning error="e.links.error" message="links" />
<optionalWarning error="e.file.error" message="file" />
</ul>
</div>);
This is prettier, but I don't like the fact that I have to make an external functions to do that, I suppose the best practise is the second one, but are there other ways to do that ?
Use logical operators - the right hand side of these statements will only be used if the left hand side is truthy.
Otherwise, if the left hand side is false, undefined or null, React won't render anything.
<div>Orange fields are not mandatory, are you sure you want to submit without :
<ul>
{e.infos.error === "warning" && <li>informations</li>}
{e.links.error === "warning" && <li>links</li>}
{e.file.error === "warning" && <li>file</li>}
</ul>
</div>
You have to be careful to always ensure a false, undefined or null result when your check fails - e.g. if you're checking the length of a list with {list.length && <Something/>}, when the list is empty this will evaluate to 0 and React will render it as text, whereas a check like {list.length > 0 && <Something/>} will work as you expect.
Use ternary operator for conditional rendering, it will be easy to write conditions inside JSX.
Like this:
<div>Orange fields are not mandatory, are you sure you want to submit without :
<ul>
{e.infos.error === "warning" ? <li>informations</li> : null }
{e.links.error === "warning" ? <li>links</li> : null}
{e.file.error === "warning" ? <li>file</li> : null}
</ul>
</div>
I would go for:
<ul>
{ e.infos.error === "warning" && <li>informations</li> }
{ e.links.error === "warning" && <li>links</li> }
{ e.file.error === "warning" && <li>file</li> }
</ul>
I'm fetching data using a REST API and one of the attributes returned can be any of 3 options;
The options are; Negative, Warning, Success.
I want to set a class using ng-class based on the value returned;
I'm able to do this but only for one;
Code below;
<div class="alert" ng-class="restaurantNotice(restaurant[0].notice)" ng-if="restaurant[0].notice.length">
<div class="alert-inner inner-large" ng-bind="restaurant[0].notice"></div>
</div>
$scope.restaurantNotice = function(a) {
return (a = Negative) ? 'negative' : '';
};
As you can see, if a = Negative then a class negative is applied else nothing is applied.
Now I want to check for all three options and apply 3 different classes respectively
Instead of function in ng-class, use object
ng-class="{'negative' : restaurant[0].notice == 'Negative', 'warning' : restaurant[0].notice == 'Warning', 'success' : restaurant[0].notice == 'Success'}"
You can try
<div class="alert" ng-class="{'negative' : restaurant[0].notice.length, 'warning' : restaurant[1].notice.length, 'success' : restaurant[2].notice.length}">
<div class="alert-inner inner-large" ng-bind="restaurant[0].notice"></div>
</div>
duplicate of Adding multiple class using ng-class
In this way:
<p ng-class="{a: deleted, b: important, c: error}">Example</p>
if a is true, apply class deleted, and so on.
If you are just going to set the same notice type (Negative, Warning, Success) as class then just convert to lower case and return from the function instead of putting conditions.
$scope.restaurantNotice = function(a) {
return a.toLowerCase();
};
OR
<div class="alert" class="{{restaurant[0].notice | lowercase}}" ng-if="restaurant[0].notice.length">