ReactJS: Get multiple checkboxes value with material-ui - function

How to get multiple checkboxes value ? Ref not working in material ui checkbox, no idea why.
<Checkbox key={i} label={catagory.name} ref="categories" value={catagory_name} name="category" />
for example : example
Without material-ui you can get the value by ref, but with material-ui it require another method to get checkbox value.
I get the data from API, so it will add more from time to time. How to get the value? What function I should write? Anyone know ?

You can use build-in Material UI checkbox function - onChange. It will return the specified category and it's value.
app.js
class App extends Component {
result = new Set();
handleCheckbox(event, isChecked, value) {
console.log(isChecked, value);
this.res.add(value);
if (this.res.size === 3) console.log(this.res);
}
labelList = [{id: 1, category: 'a'}, {id: 2, category: 'b'}, {id: 3, category: 'c'}]; // your data
render() {
return (
<div className="App">
{this.labelList.map(element => (
<CheckboxField
key={element.id}
label={element.category}
category={element.category}
onChange={this.handleCheckbox}
/>
))}
</div>
)
}
}
Checkbox.js
export class CheckboxField extends React.PureComponent {
handleCheck = (event, isInputChecked) => {
this.props.onChange(event, isInputChecked, this.props.category);
};
render() {
return (
<Checkbox
label={this.props.category}
iconStyle={{fill: '#000'}}
value={this.props.category}
onCheck={this.handleCheck}
/>
)}
}

Related

Passing parameters to component in react through map React

I'm relatively new to React and Typescript.
I used a map function to create a list, li, in typescript. I tried passing a parameter to a function with info from the mapped object, but it doesn't seem to happen. it seems like the same argument is mapped to all the elements, like so:
state = {
groups: new Array<IGroups>(),
showGroup: false,
groupId: 0
};
showMembers(groupId: number) {
this.setState({ showGroup: true, groupId: groupId });
}
render() {
return (
<div>
<ul>
{this.state.groups.map(group => <li>{group.name} from {group.cityName} <button onClick={() => this.showMembers(group.groupId)}>For members</button></li>)}
{this.state.showGroup && <GroupMembers groupId={this.state.groupId}></GroupMembers>}
</ul>
</div>
)
}
the same "groupId" is being passed to the component every time.
what am I doing wrong?

React-Admin: How to open "Drawer" on the same page/route as the "List"?

I'm trying to reproduce the React-Admin DEMO with functionality on how the review list functions.
In there, is a List of items and once a row is clicked, the Show view appears on the right. Notice below that my code snippet is very similar to the demo example, but the Drawer doesn't open and instead the Show view opens on a new page.
Please note a key difference:
My List and Datagrid fetch data via different resources, and am able to combine the two using a ReferenceManyField.
The List render employees, and the Show should render a list of the employee's timesheet.
// I think my problem is that, this always returns "false"
const isMatch = !!(
match &&
match.params &&
match.params.id !== 'create'
);
Here's my code, and thanks for any help:
class NestedTimesheetList extends React.Component {
handleClose = () => {
this.props.push('/timesheets');
};
render() {
const { push, classes, ...props } = this.props;
return (
<div className={classes.root}>
<Route path="/timesheets/show/:id">
{({ match }) => {
const isMatch = !!(match && match.params && match.params.id !== 'create');
let details = (id, basePath, record) => (
// triggered by rowClick
linkToRecord('/TimesheetSummary', record.id, 'show') +
`?employeeId=${props.id}&employeeCode=${props.record.employeeCode}`
);
return (
<Fragment>
<List
{...props}
className={classnames(classes.list, {[classes.listWithDrawer]: isMatch})}
sort={{ field: "name", order: "ASC" }}
>
<ReferenceManyField
{...props}
sort={{ field: "startTime", order: "DESC" }}
reference="TimesheetSummary"
source="employeeCode"
target="employeeCode"
label={false}
>
<Datagrid rowClick={details} {...props}>
<TextField
label="Timesheet ID"
source="timesheetID"
sortable={false}
/>
<FunctionField
label="Start Time"
source="startTime"
render={record => `${dateFormat(record.startTime)}`}
sortable={false}
/>
</Datagrid>
</ReferenceManyField>
</List>
<Drawer
variant="persistent"
open={isMatch}
anchor="right"
onClose={this.handleClose}
classes={{ paper: classes.drawerPaper }}
>
{/* To avoid any errors if the route does not match,
we don't render at all the component in this case */}
{ isMatch ? (
<TimesheetsummaryShow
{...props}
id={match.params.id}
onCancel={this.handleClose}
/>
) : null}
</Drawer>
</Fragment>
);
}}
</Route>
</div>
);
}
The Admin resource definition for this:
import TimesheetSummary from './timesheets/index';
<Resource name="TimesheetSummary" {...TimesheetSummary} />
Here is the timesheet index:
import TimesheetsummaryShow from './timesheetShow';
import TimesheetCreate from './TimesheetCreate';
export default {
create: TimesheetCreate,
show: TimesheetsummaryShow
};

State element does not appear on react simple map with react-tooltip

The code is working with the property 'name', names appear correctly on the map.
I wanted to enrich the json file with datas coming from my mysql database (like, add the name of countries in french or spanish for example).
I added a state 'countries' which will be initialized with json file converted in object. I fetch data from my sql database and then I set the state 'countries' with data I wanted to add.
Here is the code :
import React, { Component } from "react"
import {
ComposableMap,
ZoomableGroup,
Geographies,
Geography,
} from "react-simple-maps"
import ReactTooltip from "react-tooltip"
import jsonWorldMap from "./maps/world-50m.json"
const wrapperStyles = {
width: "100%",
height: "100%",
backgroundColor: "#0565A1"
}
class WorldMap extends Component {
constructor(){
super()
this.state = {
zoom: 1,
color: "#39464E",
countries: jsonWorldMap
}
}
componentDidMount() {
//get all countries in db
fetch('http://localhost:3001/countries')
.then(res => res.json())
.then(body =>
body.data.forEach(function(elementSql){
jsonWorldMap.objects.units.geometries.forEach(function(elementJson){
if(elementSql.alpha3 == elementJson.id)
{
elementJson.properties.nameFr = elementSql.name_fr;
}
})
})
)
this.setState({ countries: jsonWorldMap }, () => console.log(this.state.countries))
}
render() {
return (
<div style={wrapperStyles}>
<ComposableMap>
<ZoomableGroup center={[0,20]}>
<Geographies geography={this.state.countries}>
{(geographies, projection) => geographies.map((geography, i) => geography.id !== "ATA" && (
<Geography
className="Geography"
key={i}
data-tip={geography.properties.nameFr}
geography={geography}
projection={projection}
/>
))}
</Geographies>
</ZoomableGroup>
</ComposableMap>
<ReactTooltip />
</div>
)
}
}
export default WorldMap
So you can see that I added a component to have a console.log at the end of the component. See what console.log gives :
So you can see that the property 'nameFr' is present in the state object 'countries'. But, If I try to display it as tooltip, it doesn't work. And it works perfectly with property 'name' (in data-tip)
If data-tip={geography.properties.name} works fine but data-tip={geography.properties.nameFr} does not, then it seems that the problem is with state.
See your componentDidMount method. You are updating state with jsonWorldMap at the end of this method.
But as fetch is async , at that moment jsonWorldMap may not be updated yet. So I think you should move that line inside fetch. please see below:
componentDidMount() {
const _this = this; // hold this inside _this
//get all countries in db
fetch('http://localhost:3001/countries')
.then(res => res.json())
.then(body => {
body.data.forEach(function(elementSql){
jsonWorldMap.objects.units.geometries.forEach(function(elementJson){
if(elementSql.alpha3 == elementJson.id)
{
elementJson.properties.nameFr = elementSql.name_fr;
}
})
});
_this.setState({ countries: jsonWorldMap }, () => console.log(this.state.countries)); //making sure setting updated jsonWorldMap to state
}
)
}
hope it helps.
thanks
Wrap Geography with an element that uses data-tip as a props.
<div data-tip={geography.properties.nameFr}>
<Geography ... />
</div>
In order to <Geography data-tip={props.nameFr}/> work, Geography component need to use the data-tip property internaly, something like:
function Geography(props) {
return <h1 data-tip={props['data-tip']}>I'm a map</h1>;
}
To solve your problem you need to attach data-tip property to Geography wrapper, for example:
function Geography(props) {
return <h1>I'm a map</h1>;
}
function ComponentWithTooltip({ props }) {
return (
<div data-tip="nameFr">
<Geography />
</div>
);
}
function App() {
return (
<>
<Geography data-tip="hello-world" /> // Your way, won't work
<ComponentWithTooltip /> // Work
<div data-tip="nameFr2"> // Work
<Geography />
</div>
// Works with div wrapper, without won't work.
{geographies.map((geofraphy, i) => (
<div key={i} data-tip={geofraphy.properties.nameFr}>
<Geography />
</div>
))}
<ReactTooltip />
</>
);
}
Check out the demo with all use cases:

How to change JSON data through textboxes and buttons in a ReactJS?

I just started learning react.
Please see code in codepen link below.
When you press the edit button, the field in the table is changed to a textbox.
And that's what I want.
I wanna give Click on the edit button again.
How to replace the value of the data in JSON data?
Thanks so much for the help.
let UsersData = [
{Name: 'AAA',Last:"1111"},
{Name: 'BBBB',Last:"222"},
]
constructor(props) {
super(props)
this.state={
Editing:false,
}
this.toggleEditing = this.toggleEditing.bind(this)}
toggleEditing() {
let Editing = !this.state.Editing
this.setState(
{Editing: Editing}
)}
FULL CODE IN CODEPEN
Codepen https://codepen.io/StCrownClown/pen/MEQPzP?editors=0010
To change your JSON data first you need to get the user input through your TextInput component, to do that you need to define a value and an onChange props to store the value of the input in your state. Given that your input is a custom component I'll pass those props as props.
Like this:
class TextInput extends React.Component {
render() {
const {value, onChange, name} = this.props
return (
<td>
<input type="text"
value={value} // to display the value
onChange={onChange} // to store the value on the state
name={name} // to use use the name as a property of the state
/>
</td>
)
}
}
Then in your TableRow component state, you need to:
Save those value and handle their changes:
this.state = {
Editing:false,
// from props to show their current value
name : this.props.data.Name
last: this.props.data.Last
}
// to handle changes
onChange(event){
this.setState({
[event.target.name] : event.target.value
})
}
and pass the above mentioned props to the TextInput:
<TextInput value={this.state.name} name="name" onChange={this.onChange}></TextInput>
<TextInput value={this.state.last} name="last" onChange={this.onChange} ></TextInput>
To show those values to the user when to Editing is false you need to:
Defined a state for your Table component so it re-renders with the changes and a function that changes that state when the user is done editing:
this.state = {
UsersData: UsersData
}
saveChanges({key, name, last}){
// key: unique identifier to change the correct value in the array
// name: new Name
// last: new Last
this.setState(prevState => ({
UsersData: prevState.UsersData.map(data => {
if(data.Name === key) return { Name: name, Last: last }
return data
})
}))
}
Finally, pass that function to the TableRow component:
const rows = []
// now the loop is from the UsersData in the component state to see the changes
this.state.UsersData.forEach((data) => {
rows.push (
<TableRow
key={data.Name}
saveChanges={this.saveChanges}
data={data}
/>
)
})
and call the saveChanges function in the TableRow component when the Done button is clicked:
saveChanges(){
const {name , last} = this.state
this.toggleEditing()
this.props.saveChanges({
key: this.props.data.Name,
name,
last
})
}
<button onClick={this.saveChanges} >Done</button>
You can check the full code here.

React-Native - Dynamic State from JSON for Switch

Hey there :) I got following issue by adding a filter Modal to my SearchView
I constructed a SearchPage where several events can be listed. This all workes pretty fine. Now i am trying to add filter to my SearchPage. If i set the filter manually it works pretty fine -> Now my issue:
If i try to change the switch value of the Switch, it set´s back to the root because the state for the value is not set
Steps i did explained:
I am trying to open a Modal View where all my filter are listed and where i can set true/false by using a Switch. My idea was to fetch all filter Settings by creating a JSON for it:
module.exports = {
"filter":
{
"track": [
{
"id": 1,
"description": "IoT & Living tomorrow"
},
{
"id": 2,
"description": "Smart & Digital Retail"
},
{
"id": 3,
"description": "Startups, Digital Culture & Collaboration"
}
]
}
}
The JSON above is just for expample - Normally its much larger and has more topics than just track
Now i import the JSON and save it at the var filter. I checked the data is in the right format here -> filter.track -> All my JSON Objects
Now i created a my class with the filter Modal
import React, {Component} from 'react';
import {
ListView,
Modal,
StatusBar,
StyleSheet,
Text,
TouchableOpacity,
View,
Switch
} from 'react-native';
var filter = require('../JSON/filter');
class PopoverFilter extends Component {
constructor(props) {
super();
// ds for the menu entries
var ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
this.state = {
eventTracks: ds.cloneWithRows(filter.filter.track)
}
this.show = this.show.bind(this);
}
render() {
return(
<Modal>
<ListView
style={styles.mainView}
renderRow={this.renderMenuEntries.bind(this)}
dataSource={this.state.eventTracks}/>
</Modal>
);
}
renderMenuEntries(entry) {
var switchState = entry.description;
return(
<View style={styles.switchView}>
<Text style={[styleHelper.fonts.titleSize, styles.text]}>{entry.description}</Text>
<Switch onValueChange={(value) => this.switchChanged(switchState, value)}
value={this.state.switchState}/>
</View>
);
}
switchChanged(field, value) {
var obj = {};
obj[field] = value;
this.setState(obj);
}
}
var styles = StyleSheet.create({
});
module.exports = PopoverFilter;
Please ignore the missing Style and also there are more Objects in the Modal but its not important for this case.
Most important is that i try to render the every Switch by the renderMenuEntries method and i give them all entries -> The works just the Switch is not set right. As far as i try to change the value of the switch it is instant go back to its root. And no state is set.
Maybe my solution is not possible and i have to make every state static - but this solution would be very good in case that i could set dynamic filter later without changing the whole code
The scenario you describe is possible. There were a number of issues I encountered with your code:
In renderMenuEntries the value you were assigning to the <Switch /> component was the description of the data item, instead of the expected boolean that the <Switch /> component value expects. Further, this value was also referencing a property of this.state that didn't exist.
The switchChanged function was also just updating the component state using the data item's description
Using your code sample provided I created a new class from scratch named PopoverFilter. Instead of requiring the filter data within this component, it expects the data to come in via a component prop named filterData. This will promote reusability of the component to accept different datasets.
The code is heavily commented to help explain the concepts demonstrated. Here's the PopoverFilter class:
import React from 'react';
import {
ListView,
Modal,
Switch,
Text,
TouchableOpacity,
View
} from 'react-native';
export default class PopoverFilter extends React.Component {
constructor (props) {
super(props);
// bind relevant handlers up front in the constructor
this.renderRow = this.renderRow.bind(this);
this.onPress = this.onPress.bind(this);
// process the incoming filter data to add a 'selected' property
// used to manage the selected state of its companion switch
this._filterData = this.processFilterData(this.props.filterData);
const ds = new ListView.DataSource({ rowHasChanged: (r1, r2) => r1 !== r2 });
this.state = {
filterDataSource: ds.cloneWithRows(this._filterData)
}
}
processFilterData (filterData) {
// don't mutate the filterData prop coming in
// use map to create a new array and use Object.assign to make
// new object instances with a new property named 'selected' initialized
// with a value of false
return filterData.map((item) => Object.assign({}, item, { selected: false }));
}
switchChanged (rowId, isSelected) {
const index = +rowId; // rowId comes in as a string so coerce to a number
const data = this._filterData;
// don't mutate this._filterData
// instead create a new array and new object instance
this._filterData = [
...data.slice(0, index), // take everything before the target index
Object.assign({}, data[index], { selected: isSelected }), // create a new object instance with updated selected property
...data.slice(index + 1) // take everything after the selected index
];
// update the listview datasource with the new data
this.setState({
filterDataSource: this.state.filterDataSource.cloneWithRows(this._filterData)
});
}
renderRow (item, sectionId, rowId) {
return(
<View>
<Text>{item.description}</Text>
<Switch
onValueChange={(value) => this.switchChanged(rowId, value)}
value={item.selected}
/>
</View>
);
}
// just a test function used to dump the current state of the _filterData
// to the console
onPress () {
console.log('data', this._filterData);
}
render () {
return (
<Modal>
<ListView
renderRow={this.renderRow}
dataSource={this.state.filterDataSource}
/>
<TouchableOpacity onPress={this.onPress}>
<Text>Get Filter Data</Text>
</TouchableOpacity>
</Modal>
);
}
}
Note this PopoverFilter class also renders a button that when pressed will dump out the current state of the data to the console so you can view it's current form.
Here's an example of how to use the component:
import React from 'react';
import {
AppRegistry,
View
} from 'react-native';
import filterData from './filter';
import PopoverFilter from './PopoverFilter';
class MyApp extends React.Component {
render () {
return (
<View>
<PopoverFilter filterData={filterData.filter.track} />
</View>
);
}
}
AppRegistry.registerComponent('MyApp', () => MyApp);