I have a plus sign which onClick switches to Minus sign. With that, a list of grades is also displayed based on toggle.
Currently when I click on the plug sign, all the elements expand displaying list for all students. I want to only toggle the list for the specific student.
The data is being pulled from an API then being displayed.
class Home extends Component {
constructor(props) {
super(props);
this.state = {
students: [],
search: "",
display: false
};
}
_iconOnClick = event => {
this.state.display ? this.setState({ display: false }) : this.setState({ display: true })
;
};
_renderDataFromAPI = () => {
//search filter
let filteredName = this.state.students.filter(student => {
return (
student.firstName
.toLowerCase()
.includes(this.state.search.toLowerCase()) ||
student.lastName.toLowerCase().includes(this.state.search.toLowerCase())
);
});
return filteredName.map((student,i) => {
let average =
student.grades.reduce((x, y) => parseInt(x) + parseInt(y)) /
student.grades.length;
return (
<div key={i}>
<div className="data">
<img className="img" src={student.pic} align="left" />
{this.state.display ? (
<FontAwesomeIcon
style={{
float: "right",
fontSize: "30px",
marginRight: "40px"
}}
icon="minus"
onClick={this._iconOnClick}
/>
) : (
<FontAwesomeIcon
style={{
float: "right",
fontSize: "30px",
marginRight: "40px"
}}
icon="plus"
onClick={this._iconOnClick}
/>
)}
<h1>
{student.firstName.toUpperCase()} {student.lastName.toUpperCase()}
</h1>
<p>Email: {student.email}</p>
<p>Company: {student.company}</p>
<p>Skill: {student.skill}</p>
<p>Average: {average}%</p>
<br />
{this.state.display ? (
<div >
{student.grades.map((grade, i) => {
return (
<p key={i}>
Test {i + 1}: {grade}%
</p>
);
})}
</div>
) : (
<div />
)}
</div>
<hr style={{ borderColor: "#e2e1e1" }} />
</div>
);
});
};
Move the display to each student.
let dataFromAPI = getDataFromAPI();
this.setState({
students: dataFromAPI.map(
student => Object.assign(student, { display: false })
});
Display the list...
{student.display ? (
<div >
{student.grades.map((grade, i) => { ...
Toggle the show/hide
_iconOnClick = id => {
let students = this.students.map(s => {
if (id == s.id) {
return Object.assign(s, { display: !s.display });
}
return s;
});
this.setState({ students });
};
...
<FontAwesomeIcon
style={{
float: "right",
fontSize: "30px",
marginRight: "40px"
}}
icon="minus"
onClick={this._iconOnClick(student.id)} />
Related
I am not able to select multiple checkboxes only one checkbox check at a time please look into the code
import { React, AllWidgetProps, jsx, BaseWidget, Animation } from 'jimu-core'
import { Checkbox, Radio, Label, Button, LoadingType, Loading, ControlledTemplate } from 'jimu-ui'
import { loadArcGISJSAPIModules } from 'jimu-arcgis'
import { Animation } from 'jimu-core'
import { ChangeEvent } from 'react'
export default class Widget extends BaseWidget<AllWidgetProps<any>, State> {
Geoprocessor: __esri.geoprocessor
public tableArray = []
public chevalue
public result
public _gpJobId
public array
public unique
public updateJobStatus
public params
public stringUrl
public gpUrl1
public gpUrl2
public gpUrl
public isVisible
public workflowInfoPrams
public tableArray1 = []
public checkBoxArray = []
public exportName = []
public hardCoadedWorkflowName = 'Various Location Maintenance Project'
public hardCoadedProjectID = '1D341BED-C4BC-4375-B1E1-5F1CBA4C56A3'
constructor (props) {
super(props)
const cloneWorkflowInfo = JSON.parse(JSON.stringify(this.props.config))
this.workflowInfoPrams = Object.assign({}, cloneWorkflowInfo)
this.gpUrl2 = JSON.parse(JSON.stringify(this.props.config.urlFGBB))//fetching FGDB url from json.config file
this.gpUrl1 = JSON.parse(JSON.stringify(this.props.config.urlCSV))// fetching CSV url from json.config file
this._workFlowInfoData()
for (let i = 0; i < this.workflowInfoPrams.exportInfo.length; i++) {
this.exportName.push(this.workflowInfoPrams.exportInfo[i].exportTypeName)//for radio buttons
}
console.log(this.exportName)
for (let i = 0; i < this.workflowInfoPrams.workflow_info.length; i++) {
if (this.workflowInfoPrams.workflow_info[i].WorkflowName === this.hardCoadedWorkflowName) { //comparing the workflow name
this.array = this.tableArray.join(',').split(',') //join and split funtion used to put the output into new line
} else {
this.array = this.workflowInfoPrams.workflow_info[i].Tables
}
}
// this.array = this.tableArray.join(',').split(',') //join and split funtion used to put the output into new line
this.unique = [...new Set(this.array)]//seprate the unique value
console.log(this.unique)
//stringify
// console.log(this.params)
this.state = {
apiLoaded: false,
workflow_info: [],
exportType: ExportType.FGDB,
result: '',
updateJobStatus: this.updateJobStatus,
isVisible: this.isVisible,
cheq: Boolean,
isChecked: false
}
}
onSelectAll = e => { //select all checkbox function
if (e.target.checked) {
const cheq = e.target.value
this.checkBoxArray.push(cheq)
for (let i = 0; i < this.unique.length; i++) {
this.checkBoxArray.push(this.unique[i]) //this.checkBoxArray used to collect the user input
}
this.setState({ cheq: cheq })
console.log(this.checkBoxArray)
this._workFlowInfoData()
// alert('checked')
} else {
this.setState({ cheq: false })
}
}
onCheckboxChange = (e, id) => { //function used for multiple check box selection ******* not working properly select only one checkbox ********
if (e.target.checked) {
const cheq = e.target.value as HTMLInputElement
this.chevalue = (e.target.value)
this.checkBoxArray.push(cheq)
this._workFlowInfoData()
this.setState(prevState => ({ cheq: this.checkBoxArray, [id]: cheq}))
console.log(this.checkBoxArray)
// }
// alert('checked')
} else {
const indexs = this.checkBoxArray.indexOf(this.chevalue)
if (indexs > -1) {
this.checkBoxArray.splice(indexs, 1)
}
console.log(this.checkBoxArray)
this._workFlowInfoData()
this.setState({ cheq: false })
// alert('not checked')
}
}
render () {
return <div className="widget-use-feature-layer" style={{ width: '100%', height: '100%', maxHeight: '800px', overflow: 'auto', marginLeft: '10px' }}>
{/* <Checkboxs></Checkboxs> */}
<h5 style={{ color: '#979292' }}>
Choose Export Format.
</h5>
<Radio
aria-label="Radio"
style={{ cursor: 'pointer' }} value={ExportType.FGDB} checked={this.state.exportType === ExportType.FGDB} onChange={this.onRadioButtonChange}
/> <Label
size="default"
>
FGDB
</Label>
<br></br>
<Radio
aria-label="Radio"
style={{ cursor: 'pointer' }} value={ExportType.CSV} checked={this.state.exportType === ExportType.CSV} onChange={this.onRadioButtonChange}
/> <Label
size="default"
>
CSV
</Label>
<Label
id='message'
> </Label>
{/* <br></br>
{/* */}
{this.exportName.map((option, index) => { //map function used to itrate the table and create the dynamic cheq box
return <Label
centric
className="ml-2 d-flex"
>
<Radio
aria-label="Radio"
style={{ cursor: 'pointer' }} value={option} checked={this.state.exportType === option} onChange={this.onRadioButtonChange}
/> {option}
</Label>
})}
{/* */}
<>
<h6 style={{ color: '#979292' }}>
Choose table(s) to be exported
</h6>
<Label style={{ color: 'red' }}>Tables listed below are a unique list of tables from all project workflows in the grid.</Label>
<div
aria-label="Tables listed below "
role="group"
>
<Label
centric
className="d-flex"
style={{ color: '#14558f' }}
>
<Checkbox
name="allSelect"
checked
className="mr-2"
indeterminate
style={{ cursor: 'pointer' }}
onChange={this.onSelectAll}
/>
All Table
</Label>
<div
style={{
display: 'flex',
flexDirection: 'column',
height: 120,
marginLeft: 20,
overflow: 'auto',
width: 350,
background: 'rgb(235 242 251)'
}}
>
<Animation
ref={{
// current: '[Circular]'
}}
// configType="DEFAULT"
// direction="TOP"
onAnimationEnd={function noRefCheck(){}}
onAnimationStart={function noRefCheck(){}}
style={{
flexShrink: 0,
height: 115,
marginTop: 10
}}
trigger="MANUAL"
// type="FADE_IN"
>
<div
style={{
height: '100%',
width: '100%'
}}
>
{this.state.isVisible
? <Loading type={LoadingType.Secondary}
></Loading>
: null}
<div>
{this.unique.map((option, index) => { //map function used to itrate the table and create the dynamic cheq box
return <Label
centric
className="ml-2 d-flex"
style = {{ color: 'rgb(95 92 92)' }}
>
<Checkbox
key={index}
name={option}
value={option}
id={index}
// disabled={false}
className="mr-2"
// checked = {this.unique[index]}
checked = {this.chevalue === option}
onChange = {this.onCheckboxChange}
// onClick = {this.onCheckboxChange}
// checked={option?.isChecked || false}
// onChange={(e) => this.isCheckboxChecked(index, e.target.checked)}
/>
{option}
</Label>
})}
</div>
</div>
</Animation>
</div>
</div>
</>
<br></br>
<div className='widget-starter jimu-widget' style={{ alignContent: 'left', overflow: 'auto', maxHeight: '30px' }}>
<Button
size="sm"
style={{ backgroundColor: 'red', borderRadius: '10%', color: 'white', marginLeft: '160px', width: '100px' }}
>
Cancel
</Button>
<Button
size="sm"
onClick={this.jobURl}
style={{ width: '100px', borderRadius: '10%', background: 'green', color: 'white' }}
>
OK
</Button>
</div>
<br></br>
<Label
centric
className='m1-2 d-flex'>
{this.updateJobStatus}
</Label>
</div>
}
}
I'm using firebase to create a collection of questions and sub-collection of answers. I've been able to render the collection and sub-collection successfully with react. The issue happens when I'm trying to grab the ID of a post from firebase in order to reference it so a user can edit or delete answers. For some reason it always grabs the oldest post's ID.
Here is some of the functionality code in order to give a better picture:
function Post({
answers,
questionId,
question,
timestamp,
buildFaastUser,
category,
})
{
const user = useSelector(selectUser);
const [openModal, setOpenModal] = useState(false);
const [anchorEl, setAnchorEl] = useState(null);
const [answer, setAnswer] = useState("");
const isMenuOpen = Boolean(anchorEl);
const handleAnswer = (e) => {
e.preventDefault();
if (user) {
db.collection("questions")
.doc(questionId)
.collection("answer")
.add({
questionId: questionId,
timestamp: firebase.firestore.FieldValue.serverTimestamp(),
answer: answer,
user: {
displayName: user.displayName,
email: user.email,
uid: user.uid,
},
});
}
setOpenModal(false);
};
const handleDeletePost = (answerId) => {
console.log("id", answerId);
};
const handleMenuClose = () => {
setAnchorEl(null);
};
const handleAnswerMenuOpen = (event) => {
setAnchorEl(event.currentTarget);
};
const answerMenuId = "primary-answer-account-menu";
const answerRenderMenu = (answerId) => (
<Menu
anchorEl={anchorEl}
anchorOrigin={{ vertical: "top", horizontal: "right" }}
id={answerMenuId}
keepMounted
transformOrigin={{ vertical: "top", horizontal: "right" }}
open={isMenuOpen}
onClose={handleMenuClose}
>
<MenuItem onClick={handleMenuClose}>Edit</MenuItem>
<MenuItem
onClick={handleMenuClose}
onClick={() => handleDeletePost(answerId)}
>
{console.log(answerId)}
Delete
</MenuItem>
</Menu>
);
Here is the JSX code for where it's implemented:
return (
<div className="post">
<div className="post__info">
<Avatar src={buildFaastUser ? buildFaastUser.photo : Avatar} />
<h5>
{buildFaastUser.displayName
? buildFaastUser.displayName
: buildFaastUser.email}
</h5>
<small>{new Date(timestamp?.toDate()).toLocaleString()}</small>
<small>{category}</small>
</div>
<div className="post__body">
<div className="post__question">
<p>{question}</p>
<Modal...
</div>
<div className="post__answer">
{answers.map(
({ answer, answerId, questionId: qId, timestamp, user }) => (
<p
key={answerId}
style={{ position: "relative", paddingBottom: "20px" }}
>
{questionId === qId ? (
<span>
<span
style={{
marginTop: "20px",
color: "black",
fontSize: "medium",
fontWeight: "bold",
display: "flex",
textDecorationLine: "underline",
paddingBottom: "10px",
}}
>
{user.displayName ? user.displayName : user.email}{" "}
answered on{" "}
{new Date(timestamp?.toDate()).toLocaleString()}
<br />
<div className="post__answerMenu">
<IconButton
edge="end"
aria-label="post options"
aria-controls={answerMenuId}
aria-haspopup="true"
onClick={handleAnswerMenuOpen}
color="inherit"
>
<MoreVertIcon />
</IconButton>
{answerRenderMenu(answerId)}
</div>
</span>
{parse(answer)}
<br />
<span
style={{
position: "absolute",
color: "gray",
fontSize: "small",
display: "flex",
right: "0px",
}}
></span>
</span>
) : (
""
)}
</p>
)
)}
</div>
</div>
<div className="post__questionAnswer">
<Button onClick={() => setOpenModal(true)} className="post__btnAnswer">
Answer
</Button>
</div>
</div>
);
}
I suspect the issue is how the answerId is referenced but I could be wrong.
The issue here was the last document id for the answers database in firebase was being grabbed as it was being looped through.
So the solution here was to create a component for each answer within the posts.
return (
<div className="post__answer">
{answers.map(
({ answer, answerId, questionId: qId, timestamp, user }) => (
<AnswerItem
answer={answer}
answerId={answerId}
answerQuestionId={qId}
questionId={questionId}
timestamp={timestamp}
user={user}
/>
)
)}
</div>
);
That solved it.
class CriteriaSetValue extends Component {
state = {
count: 0,
tableName: "",
fieldName:"",
tables: [],
fields: [],
addLine: [],
addField: []
};
onSubmit = e => {
e.preventDefault();
const addField = this.state.addField;
const size = addField.length + 1;
addField.push(size);
this.setState({
addField
});
addNewLine = event => {
event.preventDefault();
const addLine = this.state.addLine;
const size = addLine.length + 1;
const nextLine = this.state.count + 1;
addLine.push(size);
this.setState({
count: nextLine,
addLine
});
};
render() {
const {showForm, tableName, fieldName } = this.state;
const { props, state } = this;
return (
<React.Fragment>
<div className="form-wrapper">
<div className="row">
<div className="col-10 container">
<form onSubmit={this.submit} className="card">
<div className="card-header">
<h3 className="card-title">
Criteria Set
{/* <Locale value="std.formupload" /> */}
</h3>
</div>
<div className="card-body">
<div className="row">
<div className="col-md-7 col-lg-8">
<div className="add-line">
<Button
icon
labelPosition="left"
onClick={this.addNewLine}
>
Add Line
<Icon name="plus" />
</Button>
{this.state.addLine.map(index => {
return (
<div
className="field-line"
style={{ marginTop: "30px" }}
key={index}
id={index}
>
<h4 className="field-button">Line {index}</h4>
<Button
className="field-button"
icon
onClick={this.toggleForm}
>
<Icon name="box" />
</Button>
</div>
);
})
}
{
this.state.addField.map(index => {
return (
<React.Fragment>
<div
className="field-button"
style={{
marginTop: "20px",
paddingLeft: "20px"
}}
key={index}
id={index}
>
<h4
className="field-button"
onclick={this.addCriteriaValue}
>
<span>
table.field
</span>
</h4>
<Button
className="field-button"
icon
onClick={this.toggleDelete}
>
<Icon name="delete calendar" />
</Button>
</div>
<br></br>
</React.Fragment>
);
})
}
</div>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
</React.Fragment>
);
}
};
This is kind of related to what I am trying to achieve:
https://codesandbox.io/s/3vqyo8xlx5
But I want the child to appear under the preference of where the "Add child" button is clicked, not on the last one.
I am working on making multiple fields to appear under each line when a button beside line1, line2 and so on is clicked, but currently, the field jump to last lines when a button is clicked, it is not appearing on the appropriate line.
I have been able to show lines when the "Add Line" button is clicked and I have also been able to show the field when the button beside "Line #1" is clicked.
I want the fields for "Line #1" to show under the line1 when the field button is clicked, the field for "Line #2" to show under the line2 when the field button beside it is clicked and so on
You can try something like this:
const AddButton = ({ label, onClick }) => (
<button onClick={onClick}>
{label} [+]
</button>
)
const FieldData = ({ label, criterias, onAdd, onDelete }) => (
<React.Fragment>
<div
className='field-button'
style={{
marginTop: '20px',
paddingLeft: '20px'
}}
>
<h4 className='field-button'>
<AddButton
label='Add criteria'
onClick={onAdd}
/>
<span>
{label}
</span>
</h4>
{criterias.map((item, idx) => (
<p key={idx}>{item.id}</p>
))}
<button
className='field-button'
onClick={onDelete}
>
Del [-]
</button>
</div>
<br />
</React.Fragment>
)
class App extends React.PureComponent {
state = {
lines: []
}
handleSubmit = e => {
e.preventDefault()
console.log('DATA TO SAVE ' + JSON.stringify(this.state.lines))
}
handleAddLine = event => {
event.preventDefault()
this.setState(prevState => ({
...prevState,
lines: [
...prevState.lines,
{
id: (prevState.lines.length + 1),
fields: []
}
]
}))
}
handleAddField = lineId => e => {
e.preventDefault()
this.setState(prevState => {
const newLines = [ ...prevState.lines ]
const curLine = newLines[newLines.findIndex(({ id }) => id === lineId)]
curLine.fields.push({
id: curLine.fields.length + 1,
criterias: []
})
return {
...prevState,
lines: newLines
}
})
}
handleAddCriteria = (lineId, fieldId) => event => {
event.preventDefault()
this.setState(prevState => {
const newLines = [ ...prevState.lines ]
const curLine = newLines[newLines.findIndex(({ id }) => id === lineId)]
const curField = curLine.fields[curLine.fields.findIndex(({ id }) => id === fieldId)]
curField.criterias.push({
id: curField.criterias.length + 1
})
return {
...prevState,
lines: newLines
}
})
}
handleDeleteField = (lineId, fieldId) => event => {
event.preventDefault()
this.setState(prevState => {
const newLines = [ ...prevState.lines ]
const curLine = newLines[newLines.findIndex(({ id }) => id === lineId)]
curLine.fields = curLine.fields.filter(item => item.id !== fieldId)
return {
...prevState,
lines: newLines
}
})
}
render() {
const { lines } = this.state
return (
<React.Fragment>
<div className='form-wrapper'>
<div className='row'>
<div className='col-10 container'>
<form
onSubmit={this.handleSubmit}
className='card'
>
<div className='card-header'>
<h3 className='card-title'>
Criteria Set
</h3>
</div>
<div className='card-body'>
<div className='row'>
<div className='col-md-7 col-lg-8'>
<div className='add-line'>
<AddButton
label='Add Line'
onClick={this.handleAddLine}
/>
{lines.map((line, idx) => {
return (
<React.Fragment key={idx}>
<div
className='field-line'
style={{ marginTop: '30px' }}
>
<h4 className='field-button'>
Line {idx+1}
</h4>
<AddButton
label='Add field'
onClick={this.handleAddField(line.id)}
/>
</div>
{line.fields.map((lField, idx) => (
<FieldData
label={idx+1}
criterias={lField.criterias}
onAdd={this.handleAddCriteria(line.id, lField.id)}
onDelete={this.handleDeleteField(line.id, lField.id)}
/>
))}
</React.Fragment>
)
})}
</div>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
</React.Fragment>
)
}
}
ReactDOM.render(
<App />,
document.getElementById('app')
)
<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="app"></div>
I defined a new data structure for the state, so It is better to think about nested data, and I refactored the code a little.
I have a react component, which renders some block with another component based on the state. How could I render both HTML-like JSX and component inside of JS?
class Feedback extends Component {
constructor(props) {
super(props);
this.state = {
storeInputShow: true
};
}
render() {
return (
<div>
{ this.state.storeInputShow ?
<div className="form_field" style={{ marginBottom: '4px' }}>
<Text textTag="div">
Select shop
</Text>
</div>
<Autocomplete
items={this.state.storeList}
shouldItemRender={(item, value) => item.label && item.label.toLowerCase().indexOf(value.toLowerCase()) > -1}
getItemValue={item => item.label}
renderItem={(item, highlighted) =>
<div
key={item.id}
style={{ backgroundColor: highlighted ? '#eee' : '#ffffff', ...selectItemStyle }}
>
{item.label}
</div>
}
value={store}
onChange={e => this.setState({ store: e.target.value, storeId: e.target.id })}
onSelect={(store,storeCard) => this.setState({ store, storeId: storeCard.id })}
inputPlaceholder="Shop"
wrapperStyle={selectWrapperStyle}
menuStyle={selectMenuStyle}
/>
: null
}
</div>
);
}
Right now the error is the following:
SyntaxError: Adjacent JSX elements must be wrapped in an enclosing tag
at the <Autocomplete tag.
The error is self-explanatory, you should wrap both components inside one to make your conditional work.
<div>
<div className="form_field" style... />
<Autocomplete items={this.state.storeList} should... />
</div>
You could use a React.Fragment instead of <div />
BONUS: You could use the following syntax to remove the end null case
<div>
{ this.state.storeInputshow && <YourComponents /> }
</div>
That way you will only render if storeInputShow is available in the state without needing to return null if not.
You can't put if into a return, but you can put a variable.
class Feedback extends Component {
constructor(props) {
super(props);
this.state = {
storeInputShow: true
};
}
render() {
let form;
if (this.state.storeInputShow)
form = <div className="form_field" style={{ marginBottom: '4px' }}>
<Text textTag="div">
Select shop
</Text>
</div>
<Autocomplete
items={this.state.storeList}
shouldItemRender={(item, value) => item.label && item.label.toLowerCase().indexOf(value.toLowerCase()) > -1}
getItemValue={item => item.label}
renderItem={(item, highlighted) =>
<div
key={item.id}
style={{ backgroundColor: highlighted ? '#eee' : '#ffffff', ...selectItemStyle }}
>
{item.label}
</div>
}
value={store}
onChange={e => this.setState({ store: e.target.value, storeId: e.target.id })}
onSelect={(store,storeCard) => this.setState({ store, storeId: storeCard.id })}
inputPlaceholder="Shop"
wrapperStyle={selectWrapperStyle}
menuStyle={selectMenuStyle}
/>;
return (
<div>{ form }</div>
);
Problem in your code is, with in the if-condition, for true case you are returning two elements(,) but in JSX it expects every return to be one element(which can have any number of child's). So just wrap your elements in if-condition with wrapper.
class Feedback extends Component {
constructor(props) {
super(props);
this.state = {
storeInputShow: true
};
}
render() {
return (
<div>
{ this.state.storeInputShow ?
<div>
<div className="form_field" style={{ marginBottom: '4px' }}>
<Text textTag="div">
Select shop
</Text>
</div>
<Autocomplete
items={this.state.storeList}
shouldItemRender={(item, value) => item.label && item.label.toLowerCase().indexOf(value.toLowerCase()) > -1}
getItemValue={item => item.label}
renderItem={(item, highlighted) =>
<div
key={item.id}
style={{ backgroundColor: highlighted ? '#eee' : '#ffffff', ...selectItemStyle }}
>
{item.label}
</div>
}
value={store}
onChange={e => this.setState({ store: e.target.value, storeId: e.target.id })}
onSelect={(store,storeCard) => this.setState({ store, storeId: storeCard.id })}
inputPlaceholder="Shop"
wrapperStyle={selectWrapperStyle}
menuStyle={selectMenuStyle}
/>
</div>
: null
}
</div>
);
}
I am trying to show different html body on same tab having two toggle buttons. I have two toggle buttons with one as pre-configured. I want to show different html on two different buttons, for doing this I have added one functions named getBody for rendering html.
But I'm not getting how to call this function with certain condition in toggle button. For doing this I have added one variable flag. And I am not getting how to use toggle button . It should be something like EbLog will be by default pre-configured and after that one can use CloudLog.
export default class ResourceLog extends React.Component {
constructor(props) {
super(props);
this.state = {
streamData: {},
streamMessage: "",
interval: 5000,
showDatePicker: false,
selectionConfigs: [
{
name: "1 Hr",
cssClass: "btn btn-info btn-sm",
duration: 300,
startTime: -1,
endTime: -1,
diff: 3600
},
{
name: "3 Hr",
cssClass: "btn btn-info btn-sm",
duration: 300,
startTime: -1,
endTime: -1,
diff: 10800
}
],
params: {},
show: "EbLog",
value: 1
};
}
streamLogs = () => {
if (this.props.resource.status === "ACTIVE") {
this.setState({ streamMessage: "loading logs.." });
axios.instance
.get("api/resources/" + this.props.resource.id + "/log/stream")
.then(resp => {
this.setState({ streamData: resp.data, streamMessage: "" });
})
.catch(err => {
this.setState({ streamMessage: "" });
NotificationManager.error("unable to fetch logs");
});
} else {
this.setState({
streamMessage: "Resource is not Active cannot fetch/stream logs..."
});
}
};
onCloud = () => {
let endTime = this.state.params.endTime;
if (endTime === -1) {
endTime = new Date().getTime();
}
let startTime = this.state.params.startTime;
if (startTime === -1) {
startTime = endTime - this.state.params.diff * 1000;
}
let filter = this.state.params.duration;
if (filter === -1) {
filter = "";
}
let params = Object.assign(
{},
{ startTime: startTime, endTime: endTime, filter: period }
);
this.setState({ streamMessage: "loading stats.." });
axios.instance
.get("api/resources/" + this.props.resource.id + "/cloud/log", {
params: params
})
.then(resp => {
this.setState({ data: resp.data, streamMessage: "" });
})
.catch(error => {
NotificationManager.error(`Failed to fetch stats-`, "Error");
});
};
render() {
return (
<div>
//<button style={edit} onClick={this.streamLogs}>
EbLog
</button>
//<button style={edit} onClick={this.onCloud}>
CloudLog
</button>
<ButtonToolbar>
<ToggleButtonGroup type="checkbox" defaultValue={[1]}>
<ToggleButton value={1}>EBLog</ToggleButton>
{}
<ToggleButton value={2}>CloudLog</ToggleButton>
</ToggleButtonGroup>
</ButtonToolbar>
{this.getBody()}
</div>
);
}
getBody = () => {
if (this.state.show == "EbLog") {
return (
<div className="row" style={{ margin: "15px" }}>
<div className="col-md-12">
<h3 style={{ display: "inline" }}>
Logs
<span
style={{ marginLeft: "10px", cursor: "pointer" }}
title={"Download"}
>
<a
target="_blank"
href={`api/resources/${this.props.resource.id}/log`}
>
<i className="fa fa-download" />
</a>
</span>
<span
style={{ marginLeft: "10px", cursor: "pointer" }}
title={"Refresh"}
>
<i onClick={this.streamLogs} className="fa fa-refresh" />
</span>
</h3>
</div>
<div className="clearfix" />
<br />
<div className="col-md-12">
<div>{this.state.streamMessage}</div>
{mapObject(this.state.streamData, (k, v) => (
<div>
<pre>{v.join("\n")}</pre>
</div>
))}
</div>
</div>
);
} else if (this.state.show == "CloudLog") {
return (
<div className="row" style={{ margin: "20px", textAlign: "center" }}>
<div>
<span
className={this.state.selectionConfigs[0].cssClass}
onClick={() =>
this.updateStatsConf(this.state.selectionConfigs[0])
}
>
{this.state.selectionConfigs[0].name}
</span>
<span
style={{ marginLeft: "10px" }}
className={this.state.selectionConfigs[1].cssClass}
onClick={() =>
this.updateStatsConf(this.state.selectionConfigs[1])
}
>
{this.state.selectionConfigs[1].name}
</span>
<span
style={{ marginLeft: "10px" }}
className={this.state.selectionConfigs[2].cssClass}
onClick={() =>
this.updateStatsConf(this.state.selectionConfigs[2])
}
>
{this.state.selectionConfigs[2].name}
</span>
</div>
<div className="row" style={{ margin: "20px" }}>
<div className="col-md-12">
<div>{this.state.streamMessage}</div>
{mapObject(this.state.streamData, (k, v) => (
<div>
<pre>{v.join("\n")}</pre>
</div>
))}
</div>
</div>
</div>
);
} else {
<h1> please click a Button </h1>;
}
};
}
Please refer this link. I have used this link as reference for creating ToggleButton under section Controlled
From what I understand, you need to create a simple method to change state on click. Say something like;
toggleButton = (text) => {
this.setState({show: text});
}
And then use onClick attribute in your ToggleButton element;
<ToggleButtonGroup type="checkbox" defaultValue={[1]}>
<ToggleButton value={1} onClick={this.toggleButton.bind(this, "EbLog")}>EBLog</ToggleButton>
{}
<ToggleButton value={2} onClick={this.toggleButton.bind(this, "CloudLog")}>CloudLog</ToggleButton>
</ToggleButtonGroup>
From what i understood from the problem, please refer the following example to render different views according to toggle button click.
The toggle button should be as follows
<ToggleButton onClick = {this.toggleButton}/>
The method should update the state
toggleButton(value){
value ? this.setState(show:'CloudLog') : this.setState(show:'EbLog')
}
The render method can be as
render() {
return(
this.state.show ==='CloudLog' ? <div>View 1</div> : <div>View 2</div>
)
}