This question already has answers here:
ES6 array map doesn't return anything: ReactJS
(2 answers)
Closed 4 years ago.
I am trying to create a reactJs page that allows an admin add a user to a platform. Now, instead of submitting the form for each new user, I want the admin to be able to add as many users as possible before submitting the form. By default, one table row containing input fields is displayed and then on click of the add button, a new row is added and the admin can fill the necessary details. However, I can't get my page to show the default row and the add button does not work either and unfortunately, my page throws no error. Here is my code:
export default class Admins extends React.Component{
constructor(props){
super(props);
this.state = {
errors : '',
success : '',
rows : [1]
}
this.addRow = this.addRow.bind(this);
this.fetchRows = this.fetchRows.bind(this);
}
addRow(){
var last = this.state.rows[this.state.rows.length-1];
var current = last + 1;
this.setState({
rows : this.state.rows.concat(current)
});
}
fetchRows(){
this.state.rows.map((row, index) => (
//console.log(row, index)
<tr key={row}>
<td className="text-center">
<button type="button" data-toggle="tooltip" className="btn btn-xs btn-danger"
data-original-title=""><i className="fa fa-trash"></i>
</button>
</td>
<td>
<input type="text" className="form-control"/>
</td>
<td>
<input type="text" className="form-control"/>
</td>
<td>
<input type="text" className="form-control"/>
</td>
</tr>
));
}
render(){
return(
<div>
<Top/>
<SideBar/>
<div className="breadcrumb-holder">
<div className="container-fluid">
<ul className="breadcrumb">
<li className="breadcrumb-item"><Link to="/">Dashboard</Link></li>
<li className="breadcrumb-item active">Admins</li>
</ul>
</div>
</div>
<section className="forms">
<div className="container-fluid">
<header>
<h3 className="h5 display">Admins</h3>
</header>
<div className="row">
<div className="col-lg-6">
<h5 className="text-danger">{this.state.errors}</h5>
<h5 className="text-success">{this.state.success}</h5>
</div>
</div>
<div className="row">
<div className="col-lg-6">
<div className="card">
<div className="card-header d-flex align-items-center">
<h5></h5>
</div>
<div className="card-body">
<table className="table table-bordered">
<thead>
<tr>
<th width="5%">Actions</th>
<th>Name</th>
<th>Email</th>
<th>Password</th>
</tr>
</thead>
<tbody>
{this.fetchRows()}
<tr>
<td className="text-center">
<button type="button" onClick={this.addRow} data-toggle="tooltip" className="btn btn-xs btn-primary"
data-original-title=""><i className="fa fa-plus"></i>
</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</section>
</div>
);
}
}
You are not returning anything from fetchRows. Return it or simply put it directly in the render method and it will work as expected.
Example
class Admins extends React.Component {
state = {
errors: "",
success: "",
rows: [1]
};
addRow = () => {
var last = this.state.rows[this.state.rows.length - 1];
var current = last + 1;
this.setState({
rows: this.state.rows.concat(current)
});
};
render() {
return (
<div>
<div className="breadcrumb-holder">
<div className="container-fluid">
<ul className="breadcrumb">
<li className="breadcrumb-item active">Admins</li>
</ul>
</div>
</div>
<section className="forms">
<div className="container-fluid">
<header>
<h3 className="h5 display">Admins</h3>
</header>
<div className="row">
<div className="col-lg-6">
<h5 className="text-danger">{this.state.errors}</h5>
<h5 className="text-success">{this.state.success}</h5>
</div>
</div>
<div className="row">
<div className="col-lg-6">
<div className="card">
<div className="card-header d-flex align-items-center">
<h5 />
</div>
<div className="card-body">
<table className="table table-bordered">
<thead>
<tr>
<th width="5%">Actions</th>
<th>Name</th>
<th>Email</th>
<th>Password</th>
</tr>
</thead>
<tbody>
{this.state.rows.map((row, index) => (
//console.log(row, index)
<tr key={row}>
<td className="text-center">
<button
type="button"
data-toggle="tooltip"
className="btn btn-xs btn-danger"
data-original-title=""
>
<i className="fa fa-trash" />
</button>
</td>
<td>
<input type="text" className="form-control" />
</td>
<td>
<input type="text" className="form-control" />
</td>
<td>
<input type="text" className="form-control" />
</td>
</tr>
))}
<tr>
<td className="text-center">
<button
type="button"
onClick={this.addRow}
data-toggle="tooltip"
className="btn btn-xs btn-primary"
data-original-title=""
>
<i className="fa fa-plus" />
</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</section>
</div>
);
}
}
Related
I have created small function can't get props value, I am using map function but I could not send props used this props NewState={this.props.empname} could not send props this component ModalDelete. How do I solve this.
ViewEmpList.js
{this.props.filteredEmployee.map((emps, index) => {
return (
<tr key={index}>
<th scope="row">{emps.empid}</th>
<td>{emps.empname}</td>
<td>{emps.empid}</td>
<td>{emps.email}</td>
<td>{emps.mobile}</td>
<td style={{ color: "green" }}>
<div className="divtext">Active</div>
<div className="divshow"></div>
</td>
<td>
<BiEditAlt
className="fontcolor"
style={{ fontSize: 35 }}
/>
</td>
<td>
{/* <RiDeleteBin2Fill
className="fontcolor"
style={{ fontSize: 35 }}
/> */}
{/* <ModalDelete onClick={()=>{this.takeValue(emps)}}/> */}
<ModalDelete NewState={this.props.empname}/>
</td>
</tr>
);
})}
ModalDelete.js
<div className="modal fade col-md-12 col-sm-12" id="staticBackdrop" >
<div className="modal-dialog modal-dialog-centered ">
<div className="modal-content">
<div className="modal-header">
<h5 className="modal-title btn-title" id="staticBackdropLabel">Are You sure want to delet it?</h5>
<TiDeleteOutline Style="color:#fff;font-size:18px;" type="button" />
</div>
<div className="modal-body">
{this.props.NewState}
</div>
<div className="modal-footer">
<button type="button" className="btn-delet" data-bs-dismiss="modal">Delete</button>
</div>
</div>
</div>
The modal opens. The "Id" value is displayed in the readonly textbox with id = "Id". But the Description value does not display in the readonly textbox with the id = "Description". I stepped through the code and the correct value is present in the function on the master view. However, it is not displaying in the modal. Am I missing something? Why is the value not passing to the Description id in the partial?
Partial
#model AutoClickItOnline.Models.AdminViewModels.DeleteSubTypeViewModel
#{
Layout = null;
}
#using (Html.BeginForm("DeleteSubType", "Admin", FormMethod.Post, new { #class = "form-horizontal", role = "form" }))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true, null, new { #class = "text-danger" })
<div class="form-group">
<div class="col-md-12">
<label for="Id" class="text-dark">Subscription Type ID</label>
#Html.TextBoxFor(m => m.SubTypeId, new { #class = "form-control", #readonly = true, id = "Id" })
<label for="Name" class="text-dark pt-2">Descripiton</label>
#Html.TextBoxFor(m => m.Description, new { #class = "form-control", #readonly = true, id = "Description" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<button type="submit" class="btn btn-success">Delete Subscription Type</button>
</div>
</div>
}
Javascript:
#section Scripts{
<script type="text/javascript" charset="utf8" src="https://cdn.datatables.net/1.10.21/js/jquery.dataTables.min.js"></script>
<script type="text/javascript">
$(document).ready(function () {
$('#user_table').DataTable({
"scrollY": "50vh",
"scrollX": true,
"autowidth": false
});
});
function DeleteSubType(id, Description) {
$('#Id').val(id);
$('#Description').val(Description);
$('#DeleteSubTypeModal').modal('show')
}
</script>
}
Main View:
#model AutoClickItOnline.Models.AdminViewModels.SubscriptionTypeTableViewModel
#{
ViewBag.Title = "SubTypes";
Layout = "~/Views/Shared/_AdminLayout.cshtml";
}
<section>
<div class="container">
<div class="row py-5">
<div class="col">
<div class="modal fade" id="newSubTypeModal">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h2 class="modal-title">New Subscription Type Entry</h2>
</div>
<div class="modal-body">
#{
Html.RenderPartial("/Views/Admin/AddSubTypePartial.cshtml", new SubscriptionType());
}
</div>
</div>
</div>
</div>
<div class="modal fade" id="DeleteSubTypeModal">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h2 class="modal-title">Delete Subscription</h2>
</div>
<div class="modal-body">
#{
Html.RenderPartial("/Views/Admin/DeleteSubTypePartial.cshtml", new AutoClickItOnline.Models.AdminViewModels.DeleteSubTypeViewModel());
}
</div>
</div>
</div>
</div>
<div class="d-flex flex-row">
<h2 class="pr-2">Subscription Type Manager</h2>
<a class="btn btn-sm btn-primary ml-auto my-2 text-light text-center d-none d-md-block" href="#" data-toggle="modal" data-target="#newSubTypeModal"><i class="fa fa-plus text-light pr-1"></i>Add New Subscription Type</a>
<a class="btn btn-sm btn-primary ml-auto my-2 text-light text-center d-sm-none" style="max-height:50px;" href="#" data-toggle="modal" data-target="#newSubTypeModal">ADD NEW</a>
</div>
#if (Model.Message != null)
{
<div class="text-danger">
#Html.DisplayFor(modelItem => Model.Message, null, new { #class = "text-danger" })
</div>
}
<hr />
<table id="user_table" class="display small-table table-bordered border-dark" style="width:100%;">
<thead>
<tr>
<th style="font-size:11px; min-width:195px;">Id</th>
<th style="font-size:11px;">Description</th>
<th style="font-size:11px;">Length</th>
<th style="font-size:11px;">Cost</th>
<th style="font-size:11px;">Active</th>
<th style="font-size:11px; min-width:100px;">Date/Time Created</th>
<th style="font-size:11px; min-width:60px;">Created By</th>
<th style="font-size:11px; min-width:105px;">Date/Time Modified</th>
<th style="font-size:11px; min-width:65px;">Modified By</th>
<th style="font-size:11px;">Delete</th>
</tr>
</thead>
<tbody>
#foreach (var item in Model.SubscriptionTypes)
{
<tr>
<td style="font-size:11px">#Html.DisplayFor(modelItem => item.SubscriptionTypeId)</td>
<td style="font-size:11px">#Html.DisplayFor(modelItem => item.Description)</td>
<td style="font-size:11px">#Html.DisplayFor(modelItem => item.Length)</td>
<td style="font-size:11px">$#Html.DisplayFor(modelItem => item.Cost)</td>
#if (item.Active)
{
<td style="font-size:11px">Yes</td>
}
#if (!item.Active)
{
<td style="font-size:11px">No</td>
}
<td style="font-size:11px">#Html.DisplayFor(modelItem => item.DateTimeCreated) UTC</td>
<td style="font-size:11px">#AdminHelpers.GetUsersName(item.CreatedBy)</td>
<td style="font-size:11px">#Html.DisplayFor(modelItem => item.DateTimeModified) UTC</td>
<td style="font-size:11px">#AdminHelpers.GetUsersName(item.ModifiedBy)</td>
<td>
<input type="button" class="btn btn-sm btn-danger" value="X" onclick="DeleteSubType('#item.SubscriptionTypeId', '#item.Description'); return false;" />
</td>
</tr>
}
</tbody>
</table>
</div>
</div>
</div>
</section>
I try to update my recipe which has collection of ingredients(formArray) and i have problem with that because of formArray.
I have error on console:
ERROR Error: formArrayName must be used with a parent formGroup directive
When i update recipe without formArray(ingredients) it's working fine.
Could you give me a hint ?
It's my first time when i'm working with formArrays..
My code:
Component.ts
export class RecipeEditComponent implements OnInit {
#ViewChild('editForm') editForm: NgForm;
recipe: IRecipe;
photos: IPhoto[] = [];
ingredients: IIngredient[] = [];
uploader: FileUploader;
hasBaseDropZoneOver = false;
baseUrl = environment.apiUrl;
currentMain: IPhoto;
constructor(private route: ActivatedRoute, private recipeService: RecipeService,
private toastr: ToastrService) { }
ngOnInit(): void {
this.loadRecipe();
}
Html
<div class="container mt-4 border" *ngIf="recipe">
<form #editForm="ngForm" id="editForm" (ngSubmit)="updateRecipe(recipe.id)" >
<h5 class=" text-center mt-2">Recipe details:</h5>
<div class="form-group mt-3">
<label for="city">Name</label>
<label for="city">{{recipe.id}}</label>
<input class="form-control" type="text" name="name" [(ngModel)]="recipe.name">
</div>
<div class="form-group">
<div formArrayName="ingredients"
*ngFor="let ingredient of recipe.ingredients; let i = index;">
<div formGroupName= {{i}} class="row">
<div class="form-group col-6">
<app-text-input formControlName="name" [label]='"Name"' name="ingredient[i].name"></app-text-input>
</div>
<div class="form-group col-6">
<app-text-input formControlName="amount" [label]='"Amount"' [type]="'number'" name="ingredient[i].amount"></app-text-input>
</div>
</div>
</div>
</div>
<h5 class=" text-center mt-4">Description</h5>
<angular-editor cols=100% rows="6" [placeholder]="'Your description'" [(ngModel)]="recipe.description" name="description"></angular-editor>
</form>
<h3 class="text-center">Photos</h3>
<div class="row">
<div class="col-sm-2" *ngFor="let photo of recipe.recipePhotos">
<img src="{{photo.url}}" class="img-thumbnail p-1" alt="">
<div class="text-center">
<button type="button" class="btn btn-sm mr-1 mb-2"
(click) = "setMainPhoto(photo)"
[disabled]="photo.isMain"
[ngClass] = "photo.isMain ? 'btn-danger active' : 'btn-secondary'"
>Main</button>
<button type="button" class="btn btn-sm btn-danger mb-2"
(click)="deletePhoto(photo.id)" >
<i class="fa fa-trash-o"></i></button>
</div>
</div>
</div>
<div class="row justify-content-md-center mt-5 border">
<div class="col col-sm-4">
<div class="mt-4 text-center">
Multiple
<input type="file" ng2FileSelect [uploader]="uploader" multiple="true" /><br/>
Single
<input type="file" ng2FileSelect [uploader]="uploader" />
</div>
</div>
<div class="col col-sm-6">
<div ng2FileDrop
[ngClass]="{'nv-file-over': hasBaseDropZoneOver}"
(fileOver)="fileOverBase($event)"
[uploader]="uploader"
class="card bg-faded p-3 text-center mt-3 mb-3 my-drop-zone">
<i class="fa fa-upload fa-3x"></i>
Drop Photos Here
</div>
</div>
</div>
<div class="col-md-6 mt-5" style="margin-bottom: 40px" *ngIf="uploader?.queue?.length">
<h3 class="text-center">Upload queue</h3>
<p>Queue length: {{ uploader?.queue?.length }}</p>
<table class="table">
<thead>
<tr>
<th width="50%">Name</th>
<th>Size</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let item of uploader.queue">
<td><strong>{{ item?.file?.name }}</strong></td>
<td *ngIf="uploader.options.isHTML5" nowrap>{{ item?.file?.size/1024/1024 | number:'.2' }} MB</td>
<td *ngIf="uploader.options.isHTML5">
</tr>
</tbody>
</table>
<div>
<div>
Queue progress:
<div class="progress mb-4" >
<div class="progress-bar" role="progressbar" [ngStyle]="{ 'width': uploader.progress + '%' }"></div>
</div>
</div>
<button type="button" class="btn btn-success btn-s"
(click)="uploader.uploadAll()" [disabled]="!uploader.getNotUploadedItems().length">
<span class="fa fa-upload"></span> Upload
</button>
<button type="button" class="btn btn-warning btn-s"
(click)="uploader.cancelAll()" [disabled]="!uploader.isUploading">
<span class="fa fa-ban"></span> Cancel
</button>
<button type="button" class="btn btn-danger btn-s"
(click)="uploader.clearQueue()" [disabled]="!uploader.queue.length">
<span class="fa fa-trash"></span> Remove
</button>
</div>
</div>
<button [disabled]="!editForm.dirty" form="editForm" class="btn btn-success btn-block mb-5 mt-5">Save changes</button>
</div>
This is how my recipe looks like with properties:
Problem Description
The directive formArrayName is a ReactiveForm directive and for it to work you must have below satisfied
Must have a parent formGroup
You must have imported ReactiveFormModule in your module
Solution
You may have to do some changes to implement this, see below
See Demo On Stackblitz
name = 'Angular ' + VERSION.major;
recipe = {
id: 1,
name: 'Test Recipe',
ingredients: [{
name: 'Chicken',
amount: 5
},
{
name: 'Pasta',
amount: 50
}],
description: 'Test Description'
}
ngForm = this.fb.group({
description: [this.recipe.description],
name: [this.recipe.name],
ingredients: this.fb.array(
this.recipe.ingredients.map(
ingredient => this.fb.group({
name: [ingredient.name],
amount: [ingredient.amount]
})
)
)
})
updateRecipe() {
}
<form [formGroup]="ngForm" id="editForm" (ngSubmit)="updateRecipe()">
<h5 class=" text-center mt-2">Recipe details:</h5>
<div class="form-group mt-3">
<label for="city">Name</label>
<label for="city">{{recipe.id}}</label>
<input class="form-control" type="text" formControlName='name'>
</div>
<div class="form-group">
<div formArrayName="ingredients" *ngFor="let ingredient of recipe.ingredients; let i = index;">
<div formGroupName={{i}} class="row">
<div class="form-group col-6">
<app-text-input formControlName="name" [label]='"Name"' name="ingredient[i].name">
</app-text-input>
</div>
<div class="form-group col-6">
<app-text-input formControlName="amount" [label]='"Amount"' [type]="'number'"
name="ingredient[i].amount"></app-text-input>
</div>
</div>
</div>
</div>
<h5 class=" text-center mt-4">Description</h5>
<angular-editor cols=100% rows="6" [placeholder]="'Your description'"
formControlName='description'></angular-editor>
</form>
Instead of using FormArrays in your template, try using NgModel for input data-binding:
<div class="form-group" *ngFor="let ingredient of recipe.ingredients; let i = index;">
<div class="form-group col-6">
<input [(ngModel)]="ingredient.name" />
</div>
<div class="form-group col-6">
<input [(ngModel)]="ingredient.amount" />
</div>
</div>
I am looking for some help with conditional rendering inside of the return of my ReactJS page.
Here is what my code looks like:
import React from "react";
import NoActiveTracker from "../components/NoActiveTracker.js";
import NoCompletedTracker from "../components/NoCompletedTracker.js";
var bg = {
background: "#6F42C1"
}
class TrackerGeneralPage extends React.Component {
state = {
id: '',
active: [],
completed: [],
completedDateNow: '',
newStatus: 'Complete'
};
render() {
const { active, completed } = this.state
// if this.state.active.length > 0 ? { ---- I can do this with the return and set an else that will work fine but I am trying to do it for each table
return (
<>
<div>
{/* Active Trackers */}
<div id="toggle-active" className="">
<div className="my-4">
<table className="table table-hover table-bordered mb-3">
<thead className="thead-dark">
<tr>
<th scope="col" className="h5">Active</th>
<th scope="col">Name</th>
<th scope="col">Regulation</th>
<th scope="col">Due On</th>
<th scope="col">Assigned</th>
<th scope="col">Status</th>
</tr>
</thead>
<tbody>
{/* Need to perform conditional rending here with <NoActiveTrackers /> */}
{active.map(item => (
<>
<tr key={item.id}>
<th scope="row" className="dropdown">
<a className="btn btn-dark" data-toggle="collapse" href={"#a" + item.id} role="button" aria-expanded="false" aria-controls="item">Expand</a>
</th>
<td>{item.name}</td>
<td>{item.reg}</td>
<td>{item.dateDue}</td>
<td>{item.assigned}</td>
<td>{item.status}</td>
</tr>
<tr>
<td id={"a" + item.id} className="collapse hiddenRow" colSpan="6" rowSpan="1">
<div class="row">
<div class="col-sm">
<div class="card text-white text-center" style={bg}>
<div class="card-body">
<h5 class="card-title text-white font-weight-bold">Occurrence</h5>
<p class="card-text">{item.occurrence}</p>
<p>Next Expected Occurrence: Unknown</p>
</div>
</div>
</div>
<div class="col-sm">
<div class="card bg-light text-center">
<div class="card-body">
<h5 class="card-title font-weight-bold">Completed By</h5>
<p class="card-text">{item.completer} on {item.dateCompleted}</p>
<button className="btn btn-dark" onClick={() => this.handleUpdateTracker(item)} >Mark as Complete <img src="https://icon.now.sh/done_all/ffffff" width="25" height="25" className="d-inline-block align-top" alt="Complete Tracker" /></button>
</div>
</div>
</div>
<div class="col-sm">
<div class="card text-center">
<div class="card-body text-white bg-dark">
<h5 class="card-title text-white font-weight-bold">Description</h5>
<p class="card-text">{item.description}</p>
<button className="btn btn-light ml-1" onClick={() => this.handleDeleteTracker(item.id)} >Delete Tracker<img src="https://icon.now.sh/delete_forever" width="25" height="25" className="d-inline-block align-top" alt="Delete Tracker" /></button>
</div>
</div>
</div>
</div>
</td>
</tr>
</>
))}
</tbody>
</table>
</div> {/* End Table Section */}
</div> {/* End Active Toggle */}
{/* Completed Trackers */}
<div id="toggle-active" className="">
<div className="my-4">
<table className="table table-hover table-bordered mb-3">
<thead className="thead-dark">
<tr>
<th scope="col" className="h5">Completed</th>
<th scope="col">Name</th>
<th scope="col">Regulation</th>
<th scope="col">Due On</th>
<th scope="col">Assigned</th>
<th scope="col">Status</th>
</tr>
</thead>
<tbody>
{/* Need to perform conditional rending here with <NoCompleteTrackers /> */}
{completed.map(item => (
<>
<tr key={item.id}>
<th scope="row" className="dropdown">
<a className="btn btn-dark" data-toggle="collapse" href={"#a" + item.id} role="button" aria-expanded="false" aria-controls="item">Expand</a>
</th>
<td>{item.name}</td>
<td>{item.reg}</td>
<td>{item.dateDue}</td>
<td>{item.assigned}</td>
<td>{item.status}</td>
</tr>
<tr>
<td id={"a" + item.id} className="collapse hiddenRow" colSpan="6" rowSpan="1">
<div class="row">
<div class="col-sm">
<div class="card text-white text-center" style={bg}>
<div class="card-body">
<h5 class="card-title text-white font-weight-bold">Occurrence</h5>
<p class="card-text">{item.occurrence}</p>
</div>
</div>
</div>
<div class="col-sm">
<div class="card bg-light text-center">
<div class="card-body">
<h5 class="card-title font-weight-bold">Completed By</h5>
<p class="card-text">{item.completer} on {item.dateCompleted}</p>
</div>
</div>
</div>
<div class="col-sm">
<div class="card text-center">
<div class="card-body text-white bg-dark">
<h5 class="card-title text-white font-weight-bold">Description</h5>
<p class="card-text">{item.description}</p>
</div>
</div>
</div>
</div>
</td>
</tr>
</>
))}
</tbody>
</table>
</div> {/* End Table Section */}
</div> {/* End Completed Toggle */}
{/* Conditional Rendering Components are here just so I can visually seem them at the bottom of the page no matter way, will be removed once I figure out the conditional rendering of them */}
<NoActiveTracker />
<NoCompletedTracker />
</div> {/* End Container */}
</>
)
}
}
export default TrackerGeneralPage;
I can do if this.state.active.length > 0 ? { with the entire return ( and an else after that contains one of my components like NoActiveTrackers but since I have two tables, that means I would need a 4x if statement: one return if both trackers had items, one return if active had items but completed did not, one return if completed had items but active did not, and one return if both trackers did not have items.
How can I do conditional rendering directly before the map(s)?
Regards
Because you have 2 cases that have the same logic for displaying components, you can abstract this logic into a different component, for eg. a List component that takes your ListItem and NoItems as a prop and renders it.
const { render } = ReactDOM;
function Active() {
return <p>Definition of an active List item here</p>
}
function Completed() {
return <p>Definition of an active Completed item here</p>
}
function NoActive() {
return <p>No active list items to see here</p>
}
function NoCompleted() {
return <p>No completed list items to see here</p>
}
function List({
array,
listItem: ListItem, /*has start with capital letter */
noItems: NoItems,
}) {
if(array.length) {
return array.map((item, index) => <ListItem key={index} />);
} else {
return <NoItems />
}
}
function App() {
const activeItems = [1, 2];
const completedItems = [];
return (
<main>
<List array={activeItems} listItem={Active} noItems={NoActive} />
<List array={completedItems} listItem={Completed} noItems={NoCompleted} />
</main>
)
}
render(<App />, document.getElementById("root"))
<div id="root" />
<script crossorigin src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
I think you are looking for something like this. active.length &&.
If active array is empty, active.map will not be run here.
{/* Need to perform conditional rending here with <NoActiveTrackers /> */}
{active.length && active.map(item => ( ...
My data in the table is coming from back-end or user can manually enter the values in the table. Now my question is 'how to map those values again into the form, from which user was able to enter values into the table using jquery'? This back mapping of data from table to form is done on click of edit link which is present in front of every entry of my data in the table.
<html>
<head>
<style>
.dropdown>a:after {
display: none;
}
.glyph-ok-size, .glyph-remove-size {
font-size: 15px;
}
</style>
<script type="text/javascript">
$(document).ready(function() {
$(".add_edit_panel").hide();
$("#addNew").click(function() {
$(".add_edit_panel").slideToggle();
});
});
function edit(paramID){
$(".add_edit_panel").slideDown();
}
</script>
</head>
<body>
<cu:secured hasPermission="CORE_CUSTOMER_DATES_CREATE"
var="canCreateOrgDates"></cu:secured>
<cu:secured hasPermission="CORE_CUSTOMER_DATES_UPDATE"
var="canUpdateOrgDates"></cu:secured>
<cu:taskView taskFlowData="${taskFlowData}"
taskFlowDefinition="${taskFlowDefinition}" id="dateRange"
renderTasks="false"
title="task.title.organization.daterange"
tasks="${taskFlowData.availableTasks}">
</cu:taskView>
<div class="row">
<form action="save.action" method="post">
<div class="col-sm-6">
<div class="panel add_edit_panel">
<div class="panel-heading">${fmt:message('dateRange.panel.add.edit') }</div>
<core:text name="orgDateObj.periodName"
label="${fmt:message('org.daterange.name') }"
required="false"
maxlength="20"
placeholder="${fmt:message('org.daterange.name') }">
</core:text>
<div class="row">
<div class="col-sm-6">
<core:date id="startDate" name="orgDateObj.startDate" label="${fmt:message('org.daterange.startdate')}"
placeholder="${fmt:message('org.daterange.startdate')}"
primary="false" required="true" />
</div>
<div class="col-sm-6">
<core:date id="endDate" name="orgDateObj.endDate" label="${fmt:message('org.daterange.enddate')}"
placeholder="${fmt:message('org.daterange.enddate')}"
primary="false" required="true" />
</div>
</div>
<div class="row">
<div class="col-sm-12">
<label class="default" style="float=left"><core:checkbox
name="orgDateObj.isDefault" id="isDefault"
label="${fmt:message('org.daterange.defaultdate')}"
checked="true" indicator="true"
disabled="false"
title="${fmt:message('org.daterange.describe.defaultdate')}" />
</label>
<div class="btn-panel-margin">
<button id="save" type="submit" class="btn btn-ar btn-primary" data-allow-dirty="allow">
${fmt:message('button.save')}
</button>
</div>
</div>
</div>
</div>
</div>
</form>
</div>
<div class="row">
<div class="col-sm-6">
<div class="panel">
<div class="panel-heading">${fmt:message('dateRange.panel.listing') }</div>
<div class="row">
<div class="col-sm-12" style="overflow-x: scroll">
<table data-grid-sortable class="table table-striped table-condensed table-responsive sort-display-table">
<thead>
<tr>
<th data-column-sortable class="column-md sorted"><fmt:message key="table.date.name"/>
<span class="caret column-sort-direction"/>
</th>
<th data-column-sortable class="column-md"><fmt:message key="table.startdate"/>
<span class="caret column-sort-direction"/>
</th>
<th data-column-sortable class="column-md"><fmt:message key="table.enddate"/>
<span class="caret column-sort-direction"/>
</th>
<th data-column-sortable class="column-sm"><fmt:message key="table.default"/>
<span class="caret column-sort-direction"/>
</th>
<th data-column-sortable class="column-sm"></th>
</tr>
</thead>
<tbody id="tbody">
<c:forEach var="orgDate" items="${orgDates}">
<tr>
<td class="column-md">${orgDate.periodName}</td>
<td class="column-md">${orgDate.startDate}</td>
<td class="column-md">${orgDate.endDate}</td>
<td class="column-sm">
<c:choose>
<c:when test="${orgDate.isDefault == '1'}">
<span class="glyphicon glyphicon-remove glyph-remove-size"></span>
</c:when>
<c:otherwise>
<span class="glyphicon glyphicon-ok glyph-ok-size"></span>
</c:otherwise>
</c:choose>
</td>
<td class="column-sm">
<div class="row">
<div class="col-sm-12">
<div class="dropdown">
Action<b class="caret"></b>
<ul class="pull-right dropdown-menu">
<li>
<a href="#" id="editButtonId" onclick="edit(${orgDate.orgDateId})" >
<i class="glyphicon glyphicon-pencil margin-right-5"></i>Edit
</a>
</li>
<li>
<a href="#" id="deleteButtonId${orgDate.orgDateId}"><i class="glyphicon glyphicon-trash margin-right-5"></i>Delete
</a>
</li>
</ul>
</div>
</div>
</div>
</td>
</tr>
</c:forEach>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-sm-6">
<div class="btn-panel-margin">
<button id="addNew" type="button" class="btn btn-ar btn-primary" data-allow-dirty="allow">
${fmt:message('button.addnew')}
</button>
</div>
</div>
</div>
</body>
</html>
enter image description here
in edit button give the row index as class and get the value of that row by mapping array index value of 1st row of table equals to array[0] access the array[0] values and place the value of array in form text box i.e
$('#textbox1').val=array[0]['name'];
you can do stuff like this
$('#edit').onclick(function (){
$('#name').val=array[0]['name'];
$('#startDate').val=array[1]['S-Date'];
$('#endDate').val=array[2]['E-Date'];
$('#checkbox').val=array[3]['Checkval'];
});
I wanted to know how your data is formed from Database
In jquery use
x=0;
objectdata.forEach(function(value,indexname,arr), thisValue) {
tabledata['col'+x][indexname]=value;
x++;
}