React js select all checkboxes not in react table - javascript

In what way I can check/uncheck all checkboxes if in the set of data there is any boolean field and I'm not using react-table? For single checkbox is working but not for all. Thank you for any tip. I named checkboxes as corresponding name of the data in the table but it is not working.
This is my class:
class Boxes extends React.Component {
constructor(props) {
super(props);
this.state = {
datas: [
{name: "name1", status: 1},
{name: "name3", status: 0},
{name: "name2", status: 2},
],
checkboxes: [],
selectAll: true,
};
this.toggleAllChange = this.toggleAllChange.bind(this);
this.toggleOneChange = this.toggleOneChange.bind(this);
}
toggleAllChange(event) {
let checked = event.target.checked;
console.log(checked);
this.setState({
checkAll: checked,
checkboxes: document.getElementsByClassName("chbx")
});
for (let i in this.state.checkboxes){
let nameAct = this.state.checkboxes.item(i).name;
let checkbox = document.getElementsByName(nameAct);
this.setState({
[nameAct]: checked
});
}
}
toggleOneChange(event) {
const target = event.target;
const value = target.checked;
const name = target.name;
this.setState({
[name]: value
});
}
And my Table in render method:
<div className="input-group mb-3">
<InputGroup className="mb-3">
<input
type="checkbox"
value="checkAll"
defaultChecked={this.state.selectAll}
onChange={this.toggleAllChange.bind(this)}/>
Check/Uncheck All
</InputGroup>
</div>
<Table responsive>
<thead className="text-primary">
<tr>
<th>Data name</th>
<th>Data status</th>
<th>Check</th>
</tr>
</thead>
<tbody>
{this.state.datas.map(data => (
<tr>
<td>{data.name}</td>
<td>{data.status}</td>
<td>
<input
className="chbx"
type="checkbox"
id={"chbx" + data.name}
name={"chbx" + data.name}
defaultChecked={this.state.selectAll}
onChange={this.toggleOneChange.bind(this)}
/>
</td>
</tr>
))}
</tbody>
</Table>

Look at the following example, I've:
Used an object checkBoxObj to manage the state of checkboxes
Used the checked attribute instead of defaultChecked and checkBoxObj:
<input
className="chbx"
type="checkbox"
id={"chbx" + data.name}
name={"chbx" + data.name}
checked={this.state.checkBoxObj["chbx" + data.name]}
onChange={this.toggleOneChange.bind(this)}
/>
Change toggleAllChange and toggleOneChange methods
Live example:
const datas = [
{name: "name1", status: 1},
{name: "name3", status: 3},
{name: "name2", status: 2},
];
const selectAll = true;
const checkBoxObj = datas.reduce((acc, d) => (acc["chbx" + d.name] = selectAll, acc), {});
class Boxes extends React.Component {
constructor(props) {
super(props);
this.state = {
datas,
//allChecked: true,
selectAll,
checkBoxObj,
};
this.toggleAllChange = this.toggleAllChange.bind(this);
this.toggleOneChange = this.toggleOneChange.bind(this);
}
toggleAllChange(event) {
const selectAll = event.target.checked;
const newCheckBoxObj = {};
for(let k in this.state.checkBoxObj) {
newCheckBoxObj[k] = selectAll;
}
this.setState({
checkBoxObj: newCheckBoxObj,
selectAll
});
}
toggleOneChange(event) {
const target = event.target;
const value = target.checked;
const name = target.name;
const newCheckBoxObj = { ...this.state.checkBoxObj, [name]: value };
const selectAll = Object.values(newCheckBoxObj).every(chk => chk);
this.setState({
checkBoxObj: newCheckBoxObj,
selectAll
});
}
render() {
const filteredDatas = this.state.datas;
return (
<div>
<div className="input-group mb-3">
<input
type="checkbox"
value="checkAll"
style={{ marginRight: 5 }}
checked={this.state.selectAll}
onChange={this.toggleAllChange.bind(this)}
/>{" "}
Check/Uncheck All
</div>
<table responsive>
<thead className="text-primary">
<tr>
<th>Data name</th>
<th>Data status</th>
<th>Check</th>
</tr>
</thead>
<tbody>
{filteredDatas.map(data => (
<tr>
<td>{data.name}</td>
<td>{data.status}</td>
<td>
<input
className="chbx"
type="checkbox"
id={"chbx" + data.name}
name={"chbx" + data.name}
checked={this.state.checkBoxObj["chbx" + data.name]}
onChange={this.toggleOneChange.bind(this)}
/>
</td>
</tr>
))}
</tbody>
</table>
</div>)
}
}
ReactDOM.render(<Boxes />, document.getElementById('root'));
<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>
<div id="root"></div>

Related

Passing user input from child functional component to parent functional component

Im creating an invoice generator where the user can add an item, its price, and the quantity. I want to access the user inputs as a state from a child functional component (TableItems.js) into a parent functional component (TableSheet.js) to be able to save the user inputs into a database preferably firestore. I'm having a problem accessing the user input value from the child component to the parent component. I have been struggling with this bug for days, i really hope you guys could help me.
This is the Child component
import React, {useState, useEffect} from 'react'
function TableItems({index, tableItem }) {
const [price, setPrice] = useState(0);
const [qty, setQty] = useState(0);
const [total, setTotal] = useState([]);
useEffect(() => {
//arithmetically add price and qty values
const x = Number(price) * Number(qty)
setTotal(x)
return () => {
//clean up function will be here
};
}, [price, qty, total ]);
return (
<>
<tr>
<td><input type='text' required/></td>
<td><input type='number' value={price} onChange={(e) => setPrice(e.target.value)}/></td>
<td><input type='number' value={qty} onChange={(e) => setQty(e.target.value)}/></td>
<td>{total}</td>
</tr>
</>
)
}
export default TableItems
This is the Parent component
import React, { useState } from 'react'
import TableItems from './TableItems'
function TableSheet() {
const [tableItem, setTableItem] = useState([1]);
//adding a new table cell (table row)
const addCell = () => {
setTableItem((t) => [...t, t + 1])
}
return (
<div>
<table>
<thead>
<th>Item Description</th>
<th>Price</th>
<th>Qty.</th>
<th>Total</th>
</thead>
{
tableItem.map((tableItem, index, setItem) => {
return <TableItems key={index} tableItem={tableItem} setItem={setItem} addCell={addCell}/>
})
}
</table>
<button onClick={addCell}>+</button>
</div>
)
}
export default TableSheet
You tableItem state should contains item objects (quantity and price)
TableItems
function TableItems({ index, tableItem, onChangeItem }) {
return (
<>
<tr>
<td>
<input type="text" required />
</td>
<td>
<input
type="number"
value={tableItem.price}
onChange={(e) => onChangeItem(index, "price", e.target.value)}
/>
</td>
<td>
<input
type="number"
value={tableItem.quantity}
onChange={(e) => onChangeItem(index, "quantity", e.target.value)}
/>
</td>
<td>{Number(tableItem.price) * Number(tableItem.quantity)}</td>
</tr>
</>
);
}
TableSheet
function TableSheet() {
const [tableItem, setTableItem] = useState([
{
price: 0,
quantity: 0
}
]);
const onChangeItem = (index, type, value) => {
const newTable = tableItem.map((item, idx) => {
if (idx === index)
return {
...item,
[type]: value
};
return item;
});
setTableItem(newTable);
};
const addCell = () => {
setTableItem((t) => [
...t,
{
price: 0,
quantity: 0
}
]);
};
const totalPrice = tableItem.reduce((acc, cur) => {
acc += Number(cur.price) * Number(cur.quantity);
return acc;
}, 0);
return (
<div>
<table>
<thead>
<th>Item Description</th>
<th>Price</th>
<th>Qty.</th>
<th>Total</th>
</thead>
{tableItem.map((tableItem, index) => {
return (
<TableItems
key={index}
index={index}
tableItem={tableItem}
onChangeItem={onChangeItem}
/>
);
})}
</table>
<button onClick={addCell}>+</button>
<div>Total: {totalPrice}</div>
</div>
);
}
you can check in my codesandbox. Hope it help!

Multiple input onChange issue

My component like this:
import React, { useState } from 'react';
import { v4 as uuidv4 } from 'uuid';
import './SizeAndColor.css';
const initialData = {
sizes: ['S', 'M', 'L', 'XL'],
data: [
{
rowId: uuidv4(),
color: 'White',
sizes: [
{ fieldId: uuidv4(), sizeName: 'S', qty: 10 },
{ fieldId: uuidv4(), sizeName: 'M', qty: 20 },
{ fieldId: uuidv4(), sizeName: 'L', qty: 30 },
{ fieldId: uuidv4(), sizeName: 'XL', qty: 40 }
]
},
{
rowId: uuidv4(),
color: 'Gray',
sizes: [
{ fieldId: uuidv4(), sizeName: 'S', qty: 50 },
{ fieldId: uuidv4(), sizeName: 'M', qty: 60 },
{ fieldId: uuidv4(), sizeName: 'L', qty: 70 },
{ fieldId: uuidv4(), sizeName: 'XL', qty: 80 }
]
}
]
};
const initialFieldValue = {
id: 0,
initialData: initialData
};
export default function SizeAndColor() {
const [state, setState] = useState(initialFieldValue);
const onChange = (e, rowId, fieldId) => {
const { name, value } = e.target;
const updatedData = state.initialData.data.map(row => {
if (rowId === row.rowId) {
row.sizes.map(item => {
if (fieldId === item.fieldId) {
if (!isNaN(value)) {
item[name] = value;
}
}
return item;
});
}
return row;
});
setState({ ...state, initialData: { ...initialData, data: updatedData } });
};
return (
<div>
<table>
<thead>
<tr>
<td></td>
{state.initialData.sizes.map(size => (
<td key={uuidv4()}>{size}</td>
))}
</tr>
</thead>
<tbody>
{state.initialData.data.map(item => (
<tr key={uuidv4()}>
<td>{item.color}</td>
{item.sizes.map(size => (
<td key={uuidv4()}>
<input
type="text"
name="qty"
value={size.qty}
onChange={e => {
onChange(e, item.rowId, size.fieldId);
}}
/>
</td>
))}
</tr>
))}
</tbody>
</table>
</div>
);
}
When I start typing on any input field, It work only first key press. Than again have to click the input field. Than again after first key press, can not type anything.
I tried it with different scenario. If my initialData object doesn't have nested property, It works fine.
how do i solve this issue, please help me.
Issue
You are generating new React keys each render.
<div>
<table>
<thead>
<tr>
<td></td>
{state.initialData.sizes.map(size => (
<td key={uuidv4()}>{size}</td> // <-- here
))}
</tr>
</thead>
<tbody>
{state.initialData.data.map(item => (
<tr key={uuidv4()}> // <-- here
<td>{item.color}</td>
{item.sizes.map(size => (
<td key={uuidv4()}> // <-- here
<input
type="text"
name="qty"
value={size.qty}
onChange={e => {
onChange(e, item.rowId, size.fieldId);
}}
/>
</td>
))}
</tr>
))}
</tbody>
</table>
When you generate a new React key each render cycle it tells React that these are new components, so the previous ones are unmounted and a new component is instantiated. This is why the inputs lose focus.
Solution
Use the ids generated in your data so the React keys are stable, i.e. they don't change from render to render.
<div>
<table>
<thead>
<tr>
<td></td>
{state.initialData.sizes.map((size, index) => (
// use index since size array likely doesn't change
<td key={index}>{size}</td>
))}
</tr>
</thead>
<tbody>
{state.initialData.data.map(item => (
<tr key={item.rowId}> // <-- use row id
<td>{item.color}</td>
{item.sizes.map(size => (
<td key={size.fieldId}> // <-- use field id
<input
type="text"
name="qty"
value={size.qty}
onChange={e => {
onChange(e, item.rowId, size.fieldId);
}}
/>
</td>
))}
</tr>
))}
</tbody>
</table>
The reason for that is that you generate random keys for input on each render, so React thinks it's a new unrelated field that doesn't need to be focused, you need to replace key={uuidv4()} with key={item.rowId} and key={size.fieldId}
Try to remove the returns, the setState should do the work.

Removing element from table - react

I'm trying to create a CRUD application in react, and I have encountered several problems.
How can I remove an item from the table?
Is it possible to pass id to Info component in render method? How can I later link it to the element?
Why does the e.PreventDefault () method cause an error when I try to delete?
import React, { Component } from 'react';
const Info = ({ index, login, pass }) => (
<>
<thead>
<tr>
<th>ID</th>
<th>LOGIN</th>
<th>PASSWORD</th>
</tr>
</thead>
<tbody>
<tr>
<td key={index}>{index}{alert(index)}</td>
<td>{login}</td>
<td>{pass}</td>
</tr>
</tbody>
<input type="submit" value='X' onClick={() => this.del(index)}></input>
</>
);
class List extends Component {
constructor(props) {
super(props);
this.state = {
data: [],
login: "",
pass: "",
};
this.add = this.add.bind(this);
this.show = this.show.bind(this);
this.del = this.show.bind(this);
}
add(e) {
e.preventDefault();
this.setState({
[e.target.name]: e.target.value,
});
}
show(e) {
e.preventDefault();
if (!this.state.login.length || !this.state.pass.length) {
return;
}
else {
const newUser = {
login: this.state.login,
pass: this.state.pass,
};
this.setState(state => ({
data: state.data.concat(newUser),
}))
}
}
del(index) {
const tab = this.state.data.filter((temp) => temp.index !== index);
this.setState(({
data: tab
}));
}
render() {
return (
<div>
<form onSubmit={this.show}>
<label>Login</label><br></br><input type='text' name='login' onChange={e => this.add(e)}></input><br></br>
<label>Password</label><br></br><input type='text' name='pass' onChange={e => this.add(e)}></input><br></br>
<input type="submit" value="Add"></input>
</form>
<table>
{this.state.data.map((val, index) => (
<>
<thead>
<tr>
<th>ID</th>
<th>LOGIN</th>
<th>PASSWORD</th>
</tr>
</thead>
<tbody>
<tr>
<td key={index}>{index}</td>
<td>{val.login}</td>
<td>{val.pass}</td>
</tr>
</tbody>
<input type="submit" value='X' onClick={() => this.del(index)}></input>
</>
))}
</table>
</div>
)
}
}
export default List;
There are small corrections in your code.
this.del = this.show.bind(this); should be this.del = this.del.bind(this);
You are trying to remove the element from the state data using index (this.state.data.filter((temp) => temp.index !== index);) but the element inside the data doesn't have an index property.
In that case, you can use splice to delete the element from the data.
class List extends React.Component {
constructor(props) {
super(props);
this.state = {
data: [],
login: "",
pass: "",
};
this.add = this.add.bind(this);
this.show = this.show.bind(this);
this.del = this.del.bind(this);
}
add(e) {
e.preventDefault();
this.setState({
[e.target.name]: e.target.value,
});
}
show(e) {
e.preventDefault();
if (!this.state.login.length || !this.state.pass.length) {
return;
}
else {
const newUser = {
login: this.state.login,
pass: this.state.pass,
};
this.setState(state => ({
data: state.data.concat(newUser),
}))
}
}
del(index) {
let {data}=this.state
data.splice(index, 1);
this.setState(({
data
}));
}
render() {
return (
<div>
<form onSubmit={this.show}>
<label>Login</label><br></br><input type='text' name='login' onChange={e => this.add(e)}></input><br></br>
<label>Password</label><br></br><input type='text' name='pass' onChange={e => this.add(e)}></input><br></br>
<input type="submit" value="Add"></input>
</form>
<table>
{this.state.data.map((val, index) => (
<React.Fragment>
<thead>
<tr>
<th>ID</th>
<th>LOGIN</th>
<th>PASSWORD</th>
</tr>
</thead>
<tbody>
<tr>
<td key={index}>{index}</td>
<td>{val.login}</td>
<td>{val.pass}</td>
</tr>
</tbody>
<input type="submit" value='X' onClick={() => this.del(index)}></input>
</React.Fragment>
))}
</table>
</div>
)
}
}
ReactDOM.render(<List />, document.querySelector("#app"))
Here is the demo jsFiddle
Hope it helps :)

state of value is not updated

I have a table where there is one input box in each row. There are 3 rows in total and i need to calculate the total from those three input boxes value. But the state of value is not updating. I only get the initial state of value. For example, there is a state object of agent, hotel, admin. If i initialize the agent value 10, i get 10 in input box but when i try to change the value i only get 10. The value does not gets updated.
Here is the code
const Tbody = ({ roles, states, onChange, onBlur }) => {
const row = roles.map((role, index) => (
<tr key={index}>
<td>{index + 1}</td>
<td>{role.label}</td>
<td>
<TextFieldGroup
id="formControlsText"
type="number"
name={role.name}
value={states[role.name]}
onChange={event => onChange(event)}
onBlur={event => onBlur(event)}
error={states.errors[role.name]}
required
/>
</td>
</tr>
));
return <tbody>{row}</tbody>;
};
class Commission extends React.PureComponent {
state = {
agentCommission: 0,
hotelCommission: 0,
adminCommission: 0,
errors: {},
isSubmitted: false
};
handleChange = event => {
console.log(event.target);
const fieldName = event.target.name;
this.setState(
{ [event.target.name]: parseFloat(event.target.value) },
() => {
this.validateField([fieldName]);
}
);
};
handleBlur = event => {
const fieldName = event.target.name;
this.validateField([fieldName]);
};
validateField = validate => {
const errors = { ...this.state.errors };
let hasError = false;
validate.forEach(field => {
if (
parseFloat(this.state[field]) > 100 ||
parseFloat(this.state[field]) < 0
) {
hasError = true;
errors[field] = 'cannot be less than 0 and more than 100';
} else {
errors[field] = '';
}
});
this.setState({ errors });
return !hasError;
};
render() {
const { agentCommission, adminCommission, hotelcommission } = this.state;
const totalCommission = agentCommission + adminCommission + hotelcommission;
console.log('totalCommission', totalCommission);
return (
<div className="table-responsive">
<table className="table table-striped table-bordered table-condensed">
<thead>
<tr>
<th>S.N</th>
<th>Role</th>
<th>Commission</th>
</tr>
</thead>
<Tbody
roles={[
{ name: 'agentCommission', label: 'Agent' },
{ name: 'hotelCommission', label: 'Hotel Owner' },
{ name: 'adminCommission', label: 'Admin' }
]}
states={{ ...this.state }}
onChange={this.handleChange}
onBlur={this.handleBlur}
/>
<tbody>
<tr>
<td>
<button
className="btn btn-primary"
onClick={this.handleSubmit}
disabled={totalCommission === 100 ? false : true}>
Save Changes
</button>
</td>
</tr>
</tbody>
</table>
</div>
);
}
}
In ReactJS, when you extend a React component class, you must initialize the state in the constructor. Also, you need to call the parent class' constructor via super(props). This is the only way that the React library's class can get access to your state values, as well as provide access in methods such as setState()
https://codepen.io/julianfresco/pen/ybrZNe/
class Commission extends React.PureComponent {
constructor(props, context) {
super(props)
this.state = {
agentCommission: 0,
hotelCommission: 0,
adminCommission: 0,
errors: {},
isSubmitted: false
};
// method instance bindings
this.handleChange = this.handleChange.bind(this)
this.handleBlur = this.handleBlur.bind(this)
this.validateField = this.validateField.bind(this)
}
// ...
// you had 1 typo in the render function, hotelCommission wasn't camel case
render() {
const { agentCommission, adminCommission, hotelCommission } = this.state;
// ...
}
}
The issue is the Commission class, where you are not initializing the state.
Your code should be like the following:
const Tbody = ({ roles, states, onChange, onBlur }) => {
const row = roles.map((role, index) => (
<tr key={index}>
<td>{index + 1}</td>
<td>{role.label}</td>
<td>
<input
id="formControlsText"
type="number"
name={role.name}
value={states[role.name]}
onChange={event => onChange(event)}
onBlur={event => onBlur(event)}
error={states.errors[role.name]}
required
/>
</td>
</tr>
));
return <tbody>{row}</tbody>;
};
class Commission extends React.PureComponent {
constructor(props) {
super(props)
this.state = {
agentCommission: 0,
hotelCommission: 0,
adminCommission: 0,
errors: {},
isSubmitted: false
};
}
handleChange(event) {
console.log(event.target);
const fieldName = event.target.name;
this.setState(
{ [event.target.name]: parseFloat(event.target.value) },
() => {
this.validateField([fieldName]);
}
);
};
handleBlur(event) {
const fieldName = event.target.name;
this.validateField([fieldName]);
};
validateField(validate) {
const errors = { ...this.state.errors };
let hasError = false;
validate.forEach(field => {
if (
parseFloat(this.state[field]) > 100 ||
parseFloat(this.state[field]) < 0
) {
hasError = true;
errors[field] = 'cannot be less than 0 and more than 100';
} else {
errors[field] = '';
}
});
this.setState({ errors });
return !hasError;
};
render() {
const { agentCommission, adminCommission, hotelcommission } = this.state;
const totalCommission = agentCommission + adminCommission + hotelcommission;
console.log('totalCommission', totalCommission);
return (
<div className="table-responsive">
<table className="table table-striped table-bordered table-condensed">
<thead>
<tr>
<th>S.N</th>
<th>Role</th>
<th>Commission</th>
</tr>
</thead>
<Tbody
roles={[
{ name: 'agentCommission', label: 'Agent' },
{ name: 'hotelCommission', label: 'Hotel Owner' },
{ name: 'adminCommission', label: 'Admin' }
]}
states={{ ...this.state }}
onChange={this.handleChange}
onBlur={this.handleBlur}
/>
<tbody>
<tr>
<td>
<button
className="btn btn-primary"
onClick={this.handleSubmit}
disabled={totalCommission === 100 ? false : true}>
Save Changes
</button>
</td>
</tr>
</tbody>
</table>
</div>
);
}
}
Fiddle demo: https://codesandbox.io/s/KO3vDRGjR

Component not rendering

I have a component that won't render it's sub-component. There's no errors in the console. I get the data I need from the web call, no errors with that. Not sure why the Project component isn't rendering anything.
Data Retrieval functions in separate file:
window.getCurrentUsersGroups = function() {
var d = $.Deferred();
var currentUsersBusinessArea = null;
var userGroups = $().SPServices({
operation: "GetGroupCollectionFromUser",
userLoginName: $().SPServices.SPGetCurrentUser()
});
userGroups.then(function(response) {
var groups = [];
$(response).find("Group").each(function() {
var self = $(this);
groups.push(self.attr("Name"))
});
currentUsersBusinessArea = _.filter(groups, function(group) {
return _.startsWith(group, "BusinessArea")
});
d.resolve(getListings(currentUsersBusinessArea[0]))
})
return d.promise();
}
window.getListings = function(businessArea) {
var d = $.Deferred();
var projects = [];
var listings = $().SPServices.SPGetListItemsJson({
listName: "Projects",
CAMLQuery: "<Query><Where><Eq><FieldRef Name='" + businessArea + "'/><Value Type='String'>Unassigned</Value></Eq></Where></Query>"
});
listings.then(function() {
var result = this.data;
result.map(function(project){
projects.push({
id: project.ID,
pID: project.ProjectID,
title: project.Title,
status: project.Status,
created: project.Created,
businessArea: project.BusinessAreaFinanceAccounting,
sponsor: project.SponsoringArea,
comments: project.Comments
})
})
d.resolve({businessArea: businessArea, projects: projects})
})
return d.promise();
}
Listing Component:
class Listings extends React.Component {
constructor(props) {
super(props);
this.state = {
businessArea: null,
projects: [],
};
};
componentDidMount() {
let that = this;
window.getCurrentUsersGroups().then(function(response) {
response.then(function(data){
that.setState({businessArea: data.businessArea})
that.setState({projects: data.projects})
})
})
};
render() {
let {businessArea, projects} = this.state;
console.log(this.state)
return (
<section className="listingsContainer">
<h3>{businessArea}</h3>
<hr></hr>
<table className="ms-Table">
<thead>
<tr>
<th>Edit</th>
<th>Project ID</th>
<th>Project Name</th>
<th>Response Status</th>
<th>Initiated Date</th>
<th>BA Impact</th>
<th>Sponsor</th>
<th>Comments</th>
</tr>
</thead>
<tbody>
{
projects.map( function({project,index}) {
console.log(project.ID)
return <Project key={project.id} project={project} index={index} />
})
}
</tbody>
</table>
</section>
)
}
}
Project Component:
const Project = ({project, index}) => {
return (
<tr key={index + project.ID}>
<td>
<a href={_spPageContextInfo.webAbsoluteUrl + '/SitePages/Business%20Project%20Edit.aspx?ProjectID=' + project.ID}>
<span style="font-size:1em;" className="ms-Icon ms-Icon--editBox"></span>
</a>
</td>
<td>{project.ProjectID}</td>
<td>{project.Title}</td>
<td>{project.Status}</td>
<td>{project.Created}</td>
<td>{project.BusinessAreaFinanceAccounting}</td>
<td>{project.SponsoringArea}</td>
<td>{project.Comments}</td>
</tr>
);
};
Browser Result:
If I output $r in the console, the Listing component state has projects in it. But the react dev tool says the array is 0 and nothing is rendering. Confused.
Seems like you forgot to wrap your project with curly braces:
const Project = ({project}) => {
return (
<tr>
<td>
<a href={_spPageContextInfo.webAbsoluteUrl + '/SitePages/Business%20Project%20Edit.aspx?ProjectID=' + project}>
<span style="font-size:1em;" className="ms-Icon ms-Icon--editBox"></span>
</a>
</td>
<td>{project.ProjectID}</td>
<td>{project.Title}</td>
<td>{project.Status}</td>
<td>{project.Created}</td>
<td>{project.BusinessAreaFinanceAccounting}</td>
<td>{project.SponsoringArea}</td>
<td>{project.Comments}</td>
</tr>
);
};
Here's a nicer way to handle the Component's:
class Listings extends React.Component {
constructor(props) {
super(props);
this.state = {
data: [],
businessArea: null
};
}
componentDidMount() {
let that = this;
let groups = [];
let userGroups = $().SPServices({
operation: "GetGroupCollectionFromUser",
userLoginName: $().SPServices.SPGetCurrentUser()
});
userGroups.then((response) => {
$(response).find("Group").each(function() {
let self = $(this);
groups.push(self.attr("Name"))
});
let currentUsersBusinessArea = _.filter(groups, (group) => _.startsWith(group, "BusinessArea"));
this.setState({businessArea: currentUsersBusinessArea})
}).then(getListings)
function getListings() {
let listings = $().SPServices.SPGetListItemsJson({
listName: "Projects",
CAMLQuery: "<Query><Where><Eq><FieldRef Name='" + that.state.businessArea + "'/><Value Type='String'>Unassigned</Value></Eq></Where></Query>"
});
listings.then(function() {
that.setState({data: this.data});
})
};
}
render() {
let {data, businessArea} = this.state;
return (
<section className="listingsContainer">
<h3>{`Business Area ${businessArea}`}</h3>
<hr></hr>
<table className="ms-Table">
<thead>
<tr>
<th>Edit</th>
<th>Project ID</th>
<th>Project Name</th>
<th>Response Status</th>
<th>Initiated Date</th>
<th>BA Impact</th>
<th>Sponsor</th>
<th>Comments</th>
</tr>
</thead>
<tbody>
{data.map({project,index}) => <Project key={index} project={project} /> }
</tbody>
</table>
</section>
)
}
}
const Project = ({project}) => (
<tr>
<td>
<a href={_spPageContextInfo.webAbsoluteUrl`/SitePages/Business%20Project%20Edit.aspx?ProjectID=${project}`}>
<span style={{'fontSize':'1em'}} className="ms-Icon ms-Icon--editBox"></span>
</a>
</td>
<td>{project.ProjectID}</td>
<td>{project.Title}</td>
<td>{project.Status}</td>
<td>{project.Created}</td>
<td>{project.BusinessAreaFinanceAccounting}</td>
<td>{project.SponsoringArea}</td>
<td>{project.Comments}</td>
</tr>
);
Tip: Never Mix Jquery with React Components
The main reason it wasn't rendering is because of this table cell:
<td>
<a href={_spPageContextInfo.webAbsoluteUrl + '/SitePages/Business%20Project%20Edit.aspx?ProjectID=' + project.ID}>
<span style="font-size:1em;" className="ms-Icon ms-Icon--editBox"></span>
</a>
</td>
The span tag as a style property. Which is preventing it from rendering from what I can see.

Categories

Resources