Conditional Rendering is not working in the tbody in react - javascript

I am trying to render one conditional JSX.So, I am not able to render that
Here I have the fixed height of the tbody.
maxHeight : 120px;
<tbody className="text-center" style={jobsHeight}>
{props.jobList && props.jobList.length > 0 && props.jobList.map((item, key) => {
return areJobsPresent ? (
<tr key={key}>
<td className="noborder">{item.technology}</td>
<td className="font-weight-bold noborder">{item.resumeCount}</td>
<td title={item.jobTitle} className="noborder">
{item.jobTitle}
</td>
<td className="font-weight-bold noborder">{item.totalScore}</td>
<td className="font-weight-bold noborder">{item.avgScore}</td>
</tr>
) :
<tr>
<td>
No Jobs Found. please create a Job
</td>
</tr>
})}
So here before render I am computing the areJobSabsent flag.
const areJobsPresent = props.jobList.length > 0
So, here I tried with this way. if there is not data present then I want to show a tr with the message. So, where I am wrong ? can anyone help me with this ?

The reason your code doesn't work is because you have already checked for the condition before calling map, so map never executes and the internal condition never gets checked. You have to use a ternary expression outside the map call
<tbody className="text-center" style={jobsHeight}>
{props.jobList && props.jobList.length > 0 ? props.jobList.map((item, key) => <tr key={key}>
(<td className="noborder">{item.technology}</td>
<td className="font-weight-bold noborder">{item.resumeCount}</td>
<td title={item.jobTitle} className="noborder">
{item.jobTitle}
</td>
<td className="font-weight-bold noborder">{item.totalScore}</td>
<td className="font-weight-bold noborder">{item.avgScore}</td>
</tr>)
) :
<tr>
<td>
No Jobs Found. please create a Job
</td>
</tr>
}

Related

Edit method not working properly in angular

I have displayed the data from API. But I can't edit the data properly. When I try to edit a single row it will automatically hide the others row. Here is my code. Please check
HTML
<thead>
<tr>
<th><strong>Name</strong></th>
<th><strong>Consent Type</strong></th>
<th><strong>Updated At</strong></th>
<th><strong>Status</strong></th>
<th><strong>Content</strong></th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<tr *ngFor="let consent of SystemConsent">
<td *ngIf="!editorStatus">{{consent.fileName}}</td>
<td *ngIf="editorStatus && consent.consentFileId === selectedEditCellId"><input type="text" value="{{consent.fileName}}" class="form-control"></td>
<td *ngIf="!editorStatus">{{consent.type}}</td>
<td *ngIf="editorStatus && consent.consentFileId === selectedEditCellId"><input type="text" value="{{consent.type}}" class="form-control"></td>
<td>{{consent.updatedAt}}</td>
<td *ngIf="!editorStatus">{{consent.status}}</td>
<td *ngIf="editorStatus && consent.consentFileId === selectedEditCellId"><input type="text" value="{{consent.status}}" class="form-control"></td>
<td *ngIf="!editorStatus" [innerHTML]="consent.content"></td>
<td *ngIf="editorStatus && consent.consentFileId === selectedEditCellId">
<ckeditor name="htmlEditor" [config]="config" [editor]="Editor" [(ngModel)]="consent.content" skin="moono-lisa" language="en">
</ckeditor>
</td>
<td><button class="btn trans-btn list-head-btn ng-star-inserted btn-gradient" (click)="changeEditor(consent.consentFileId)">Edit</button></td>
<td><button [disabled]="!editorStatus" class="btn trans-btn list-head-btn ng-star-inserted btn-gradient" (click)="getEditorValue(consent.consentFileId)">Save</button></td>
</tr>
</tbody>
Typescript
SystemConsent: any = [];
public selectedEditCellId;
getAdminSystemPrefrences() {
this.adminDashboardService.getSystemPreferences().then(resp => {
this.SystemConsent = resp['data'].consent;
});
}
changeEditor(cellId) {
this.selectedEditCellId = cellId;
this.editorStatus = true;
console.log(this.selectedEditCellId);
}
getEditorValue(cellId) {
this.selectedEditCellId = cellId;
this.editorStatus = false;
}
Please help me to reach out this issue..
This is because when you click 'edit', the editorStatus gets set to true and the selectedEditCellId gets set to the id of the item / row that is currently being edited.
If we look at these lines:
<td *ngIf="!editorStatus">{{consent.fileName}}</td>
<td *ngIf="editorStatus && consent.consentFileId === selectedEditCellId"><input type="text" value="{{consent.fileName}}" class="form-control"></td>
We notice that for the items that are NOT being edited, neither of these *ngIfs evaluate to true - because:
editorStatus is set to true
consent.consentFileId is not equal to the selectedEditCellId for the row item.
This is also the reason why the {{consent.updatedAt}} is being displayed for the other rows.
A possible fix to the problem would be to change:
<td *ngIf="!editorStatus">{{consent.fileName}}</td>
to
<td *ngIf="!editorStatus || consent.consentFileId !== selectedEditCellId">{{consent.fileName}}</td>

Iterate over array in React

I want to iterate over an array that contains the end of a url so I can then 'concatenate' to the main site domain with the aim to gain a fully functional url (ie. www.mainUrlDomain.com/some-url)
This is my code:
<div>
<table>
<tbody>
<tr>
<th>Name</th>
<th>City</th>
<th>Code</th>
<th>Symbol</th>
</tr>
{data.map(data => (
<tr key={data.code}>
<td>
<Image
src={`${mainUrlDomain}/${data.code.toLowerCase()}.png`}
width={30}
height={20}
/>
</td>
{landingPagesKeys.includes(`${data.code}`)
?
<Link
href={`${mainUrlDomain}/${landingPages}`}
>
<td>
<a>{data.name}</a>
</td>
</Link> : <td>{data.name}</td>}
<td>{data.code}</td>
<td>{data.symbol}</td>
</tr>
))})
</tbody>
</table>
</div>
I have tried to add a way to iterate over the landingPages array like this:
{landingPagesKeys.includes(`${data.code}`)
?
{landingPages.map(data => (
<Link
href={`${mainUrlDomain}/${data`}
>
<td>
<a>{data.name}</a>
</td>
</Link> )} : <td>{data.name}</td>}
<td>{data.code}</td>
<td>{data.symbol}</td>
</tr>
))})
Unfortunately it didn't show me the array data as expected which contains the end of the desired url (ie. some-url) and landingPages after the url domain as the first example of code shows the entire array.
How to map through the array and obtain each individual url that landingPages contains?
You can use filter function to filter the data in an array.
landingPages.filter(data => landingPagesKeys.includes(`${data.code}`)).map(data => <div>...</div>)

Only one function getting result

I have this two funcions being called, but only the second one is showed on the table.
<table className="tableList tableList--space">
<thead>{this.tableHead()}</thead>
<tbody>
{this.state.products.map((item) =>
this.tableBody(item) && this.tableBodyComplements(item)
)}
</tbody>
</table>
Functions:
tableBody = (item) => (
<tr key={item.title}>
<td className="text-left">
{item.title}
</td>
<td className="text-left"> - </td>
<td className="text-right">R$ {item.price}</td>
<td className="text-center">{item.quantity}X</td>
<td className="text-right">R$ {item.total}</td>
<td className="text-left"></td>
</tr>
);
tableBodyComplements = (item) => (
<tr>
<td className="text-right">
{item.ComplementCategories.map(aux => {
return aux.Complements[0].title
})}
</td>
<td className="text-right"> - </td>
<td className="text-right"> - </td>
<td className="text-right">
{item.ComplementCategories.map(aux => {
return aux.Complements[0].quantity
})}
</td>
<td className="text-right">R$ {item.total}</td>
<td className="text-right"></td>
</tr>
);
Why is it only the second one is getting the desire result? I dont know if only the second one is being called or it is overlapping the first one in the table, How can I understand this better and fix it?
Your current implementation is performing what's called a "short-circuit", basically as long as the first value evaluates to a truthy value, the second will be returned, else it probably returns undefined.
To fix your implementation this is what it should look like:
<table className="tableList tableList--space">
<thead>{this.tableHead()}</thead>
<tbody>
{this.state.products.map((item) => (
<React.Fragment>
{this.tableBody(item)}
{this.tableBodyComplements(item)}
</React.Fragment>
)
)}
</tbody>
</table>
In javascript, any expression of the form
a && b
or
a || b
will only evaluate to either a or b. Never both. In fact it's not even clear what evaluating to "both a and b" would even mean in general.
In your case, you want to render both elements as JSX - so simply put them after each other, wrapping in a Fragment so that it's a legal React element:
{this.state.products.map((item) =>
<React.Fragment>
{this.tableBody(item)}
{this.tableBodyComplements(item)}
</React.Fragment
)}
The && operator actually doesn't return both. It returns the second argument if the first argument is true, otherwise it returns false. For example:
function Example() {
return (
<div>
{"Word1" && "Word2"}
</div>
) // this displays ONLY "Word2", since "Word1" is not a false value.
}
To fix this, wrap them in a fragment:
{this.state.products.map((item) =>
<React.Fragment>
{this.tableBody(item)}
{this.tableBodyComplements(item)}
</React.Fragment>
)}

Can not .map 2 different arrays in same table row, <tr>

I am trying to map an entry to the table. In that entry, there is a column which can have more than one value.In that case, a sub-row will be created in the same row. I have attached an example below image. Here is the code I have tried which messes the table up completely.
{intake.map((value) => {
return (
<tr>
<th className="text-center" scope="row">{value}</th>
</tr>
)
})}
{attendanceIds.map((val, i) => {
return (
<tr>
<td className="text-center">{date[i]}</td>
<td className="text-center">{duration[i]}</td>
<td className="text-center">{module[i]}</td>
<td className="text-center">{start[i]}</td>
<td className="text-center">{topic[i]}</td>
<td className="text-center">{studentsPresent[i]}</td>
<td className="text-center">{totalStudents[i]}</td>
<td className="text-center"><button className="button" id={val}>Details</button></td>
</tr>
)
})}
This is what I desire to get
This is what I get from the code above
This is the data I have. (One attendance ID has multiple intakes)
The data looks like it belongs on the same row semantically, so you shouldn't use a new row, you should add your multiple entries as e.g. div (or whatever suits) in your <td>. Then use CSS to style as required.
From your question, it isn't entirely clear what your data structure is in your component, but assuming your attendanceIds map in the way that your image shows, you can do something like this:
{attendanceIds.map((val, i) => {
return (
<tr>
<td className="text-center">{
val.intake.length === 1
? {val.intake[0]}
: val.intake.map(item=>
<div>{item}</div>)
}
}</td>
// add the rest of the <td>s here
</tr>
)
})}
(Note that I've left the rest of the mapping up to you as the way you've done it isn't clear to me.)

Error: A valid React element (or null) must be returned (Checked Return() and Render())

I have been getting the following error after refactoring some code...
PartnersIteration.render(): A valid React element (or null) must be
returned. You may have returned undefined, an array or some other
invalid object.
Everything that I have read so far has told me to look at the syntax of my return and render functions. I have checked it all, I just dont see where the error is coming from! Any chance someone could point it out to me? Thanks!
PS. I have put debuggers in all over the place and have access to all of my declared variables, from state, props or otherwise defined locally in my render() function
render() {
let newAllPartners = this.props.newAllPartners;
let dynamicPartnerList = this.state.dynamicPartnerList;
let count = this.state.count;
let lastLetter = this.props.lastLetter;
let firstLetter;
let randomNumber;
if(newAllPartners != null && newAllPartners != undefined && (Object.keys(newAllPartners).length != 0)){
dynamicPartnerList.map(function(object) {
randomNumber = Math.floor(Math.random() * (300-10000 + 1) + 1000);
if(object.name != undefined) {
firstLetter = object.name.charAt(0);
if(firstLetter === lastLetter) {
firstLetter = '';
showImage(object.id, object.urlPicture);
return(
<tbody>
<tr className="row clickable" key={object.id} onClick={() => this.rowClick(object.id)}>
<td>
<table>
<tbody>
<tr className="row">
<td className="child col s4 m3 l2">
<img id={object.id} height="56px" />
</td>
<td className="col s8 m9 l10">
<table>
<tbody>
<tr>
<td className="columnwithTitleSubtile">
<p className="producerName">{object.name}</p>
<p className="subtitle">{object.countSIF} {<FormattedMessage id="navbar.slaughterhouses"/>}</p>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
)
}
else {
lastLetter = firstLetter;
return(
<tbody>
<tr key={randomNumber}>
<td className="firstLetter">{firstLetter}</td>
</tr>
</tbody>
)
}
}
else {
return(
<tbody>
<tr>
<td>
{<FormattedMessage id="msgempty.default"/>}
</td>
</tr>
</tbody>
)
}
})
}
}
You have 3 if statements and only 2 else's. this means not all condition blocks returns a valid react object.
It seems like the first if condition lacks an else block, so i added one for you to check:
if (newAllPartners != null && newAllPartners != undefined && (Object.keys(newAllPartners).length != 0)) {
dynamicPartnerList.map(function (object) {
randomNumber = Math.floor(Math.random() * (300 - 10000 + 1) + 1000);
if (object.name != undefined) {
firstLetter = object.name.charAt(0);
if (firstLetter === lastLetter) {
firstLetter = '';
showImage(object.id, object.urlPicture);
return (
<tbody>
<tr className="row clickable" key={object.id} onClick={() => this.rowClick(object.id)}>
<td>
<table>
<tbody>
<tr className="row">
<td className="child col s4 m3 l2">
<img id={object.id} height="56px" />
</td>
<td className="col s8 m9 l10">
<table>
<tbody>
<tr>
<td className="columnwithTitleSubtile">
<p className="producerName">{object.name}</p>
<p className="subtitle">{object.countSIF} {<FormattedMessage id="navbar.slaughterhouses" />}</p>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
)
}
else {
lastLetter = firstLetter;
return (
<tbody>
<tr key={randomNumber}>
<td className="firstLetter">{firstLetter}</td>
</tr>
</tbody>
)
}
}
else {
return (
<tbody>
<tr>
<td>
{<FormattedMessage id="msgempty.default" />}
</td>
</tr>
</tbody>
)
}
})
}
else{ // this was missing
return <tbody></tbody>
}
Check you all else..if statements and the main problem - you don't return anything in render. You have returns in map, but you need to return your map too:
return <div>{dynamicPartnerList.map(function (object) {...})} </div>

Categories

Resources