Cannot read property '#<Object>' of undefined , after retriving onClick Custom React - javascript

I'm building a leaflet map that dipslay markers. These markers have additional data on them besides lat and long, (keys in this case)
I'm using a custom react component from the react-leaflet repo. I can get multiple markers location, but when I try to retrieve the marker I clicked on and pass it to a child component I get
Cannot read property '# < Object > ' of undefined
I can pass ALL the data , without a problem though.
I get this error when I try to pass the "clicked" marker to the Card and Cartitle components.
What I've tried so far:
Inside the handleToggle function I did:
index = this.props.places[index]
but that is when I get the error above. What am I doing wrong?
P.D. Also, Im able to display ALL the data to the children components
import ...
const markers = [
{
key: 'P12345678',
position: [37.786464, -122.411047],
children: 'My first popup'
},
{
key: 'M12345678',
position: [40.689192, -74.044563],
children: 'My second popup'
},
];
class Mapper extends Component {
constructor(props) {
super(props);
this.handleToggle = this.handleToggle.bind(this);
this.handleClose = this.handleClose.bind(this);
this.state = {
lat: 29.761993,
lng: -95.366302,
zoom: 4,
open: false,
places: []
}
}
handleToggle(index) {
const self = this;
self.setState({
open: !this.state.open,
places: markers
});
// index = this.props.places[index]
console.log(this.state.places)
}
handleClose() {
this.setState({
open: false
});
}
render() {
const center = [this.state.lat, this.state.lng];
//Custom Marker Component
const MyPopupMarker = ({ children, position }) => (
<Marker
onClick={this.handleToggle}
position={position}
places={this.state.places}
>
<Popup>
<span>{children}</span>
</Popup>
</Marker>
)
MyPopupMarker.propTypes = {
// children: MapPropTypes.func,
// position: MapPropTypes.latlng,
}
//Custom Marker List Component
const MarkerList = ({ markers }) => {
const items = markers.map(({ key, ...props }) => (
<MyPopupMarker key={key} {...props} />
))
return <div style={{display: 'none'}}>{items}</div>
}
MarkerList.propTypes = {
markers: MapPropTypes.array.isRequired,
}
// console.log('markers', markers)
return (
<div>
<Map
center={center}
zoom={this.state.zoom}
style={styles.map}>
<TileLayer
url='https://cartodb-basemaps-{s}.global.ssl.fastly.net/light_all/{z}/{x}/{y}.png'
attribution='© OpenStreetMap contributors'
/>
<MarkerList markers={markers} />
</Map>
<Drawer
width={500}
openSecondary={true}
docked={false}
open={this.state.open}
onRequestChange={(open) => this.setState({open})}
containerStyle={styles.whitebox}
>
{
markers.map((cf, k) => (
<Card
style={styles.appMedia}
key={k}
>
<CardTitle
titleStyle={styles.drawTitle}
subtitleStyle={styles.drawTitle}
title={cf.key}
subtitle="Common Field Equipment"/>
</Card>
))
}
</Drawer>
</div>
);
}
}
export default Mapper;

Your handleToggle method is the onClick handler for the Marker component. The onClick handlers in React pass a synthetic event object by default (More info on this here).
So the index passed into the handleToggle method will be that synthetic event object, which would not help you get the index of the marker from your places array. You would have to pass the index explicitly into your handleToggle method. To do this you would need to make the following changes:
1> Change the binding of the function in the constructor to:
this.handleToggle = this.handleToggle.bind(this,index);
2> Pass the index explicitly in the MyPopupMarker component:
const MyPopupMarker = ({ children, position,index }) => (
<Marker
onClick={()=>this.handleToggle(index)}
....
)
3> Pass the index to the MyPopupMarker component in the MarkerList component
const items = markers.map(({ key, ...props },i) => (
<MyPopupMarker key={key} index={i} {...props}/>
))
4> Access the index from the places array in the state object and not the props object.
handleToggle(index) {
const self = this;
self.setState({
open: !this.state.open,
places: markers
});
var selectedMarker = this.state.places[index];
console.log(this.state.places)
}
The reason for the error message Cannot read property '# < Object > ' of undefined was that you were trying to access the places array in the props object where it was undefined.
As an aside, I would like to point out that creating components inside the render method (the components MyPopupMarker and MarkerList) is not a good practice as these components would be created on every render which would be wasteful. It would be much more efficient if you declare them outside your Mapper component.
Edit:
To move the components out of render you need to pass the handleToggle function in as props. I have changed your code as follows:
The MyPopupMarker component: This component gets the index and the handleToggle function as props.
const MyPopupMarker = ({ children, position, index, handleToggle }) => (
<Marker onClick={() => handleToggle(index)} position={position}>
<Popup>
<span>{children}</span>
</Popup>
</Marker>
);
The MarkerList component: This component gets the handleToggle function as props and passes it on to the MyPopupMarker component along with the index
const MarkerList = ({ markers, handleToggle }) => {
const items = markers.map(({ key, ...props }, i) => (
<MyPopupMarker key={key} {...props} index={i} handleToggle={handleToggle} />
));
return <div >{items}</div>;
};
The Mapper component: This component passes the handleToggle function to the MarkerList component along with the markers
class Mapper extends Component {
constructor(props) {
super(props);
this.handleToggle = this.handleToggle.bind(this);
this.handleClose = this.handleClose.bind(this);
this.state = {
lat: 29.761993,
lng: -95.366302,
zoom: 4,
open: false,
places: []
};
}
handleToggle(index) {
const self = this;
self.setState({
open: !this.state.open,
places: markers
});
// index = this.props.places[index]
let selectedMarker = this.state.places[index];
console.log(selectedMarker);
}
handleClose() {
this.setState({
open: false
});
}
render() {
const center = [this.state.lat, this.state.lng];
let selectedMarker = this.state.places;
return (
<div>
<Map center={center} zoom={this.state.zoom} style={styles.map}>
<TileLayer
url="https://cartodb-basemaps-{s}.global.ssl.fastly.net/light_all/{z}/{x}/{y}.png"
attribution="© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors"
/>
<MarkerList markers={markers} handleToggle={this.handleToggle} />
</Map>
<Drawer
width={500}
openSecondary={true}
docked={false}
open={this.state.open}
onRequestChange={open => this.setState({ open })}
containerStyle={styles.whitebox}
>
{selectedMarker.map((value, index) => (
<Card style={styles.appMedia} key={index}>
<CardTitle
titleStyle={styles.drawTitle}
subtitleStyle={styles.drawTitle}
title={value.key}
subtitle="Common Field Equipment"
/>
</Card>
))}
</Drawer>
</div>
);
}
}
export default Mapper;
The full working example can be found at https://codesandbox.io/s/4r1yo07kw9

Related

Trying to update props in state with method in class component

I'm trying to render a closable tab bar using some Material UI components, and I'm having trouble implementing the onDelete method for when the user wants to close a tab. I'm passing the data set, an array of objects, as a prop called dataSet. I want to update it whenever the user closes a tab but it doesn't re-render; all tabs still appear. When I console.log this.state.dataSet on each click however, I see that the tabs are getting deleted. What am I doing wrong?
class ClosableTabs extends Component {
state = {
tabIndex: 0,
dataSet: this.props.dataSet,
};
onDelete = id => {
this.setState(prevState => {
const updatedDataSet = prevState.dataSet.filter(tab => tab.id !== id);
return {
dataSet: updatedDataSet,
};
}, console.log(this.state.dataSet);
};
renderTabs = dataSet => {
return dataSet.map(data => {
return (
<Tab
key={data.id}
label={
<span>
{data.title}
</span>
<Button
icon="close"
onClick={() => this.onDelete(data.id)}
/>
}
/>
);
});
};
render() {
const { value, dataSet, ...rest } = this.props;
return (
<TabBar value={this.state.tabIndex} onChange={this.onChange} {...rest}>
{this.renderTabs(dataSet)}
</TabBar>
);
}
}
export default Tabs;
and here is my data set that I pass as props when I use <ClosableTabs />
const dataSet = [
{
id: 1,
title: 'title 1',
},
{
id: 2,
title: 'title 2',
},
{
id: 3,
title: 'title 3',
},
];
When you render dataSet, you use the array you get from props (which never changes):
render() {
const { value, dataSet, ...rest } = this.props; // dataSet comes from props
return (
<TabBar value={this.state.tabIndex} onChange={this.onChange} {...rest}>
{this.renderTabs(dataSet)} // renderTabs renders this.props.dataSet
</TabBar>
);
}
}
instead, render dataSet which comes from your state (you should use different naming for this.props.dataSet and this.state.dataSet to avoid this kind of mistakes):
render() {
const { value, ...rest } = this.props;
const { dataSet } = this.state; // dataSet now comes from state
return (
<TabBar value={this.state.tabIndex} onChange={this.onChange} {...rest}>
{this.renderTabs(dataSet)} // renderTabs renders this.state.dataSet
</TabBar>
);
}
}
The problem is you are rendering the component with props instead of state.
Your render function should look likes this:
render() {
const { value, dataSet, ...rest } = this.props;
return (
<TabBar value={this.state.tabIndex} onChange={this.onChange} {...rest}>
{this.renderTabs(this.state.dataSet)}
</TabBar>
);
}
}

How fetch data by api and render child component with it - react google maps

I have to files: eventsMapPage.js (main) and Maps.js(child).
getEvents = async () => {
const requestResponse = await request(BASE_API_URL + "/api/events", { method: "GET", headers: {}, body: {} });
this.state.eventList = requestResponse.data;
console.log('getEvents');
console.log(this.state.eventList);
}
//fetching data from api in parent
```getEvents = async () => {
const requestResponse =
await request(BASE_API_URL + "/api/events", {method:"GET", headers: {}, body: {} });
this.state.eventList = requestResponse.data;
}
```
//Sent state with fetched data
```
<GoogleApiWrapper eventList={this.state.eventList} ></GoogleApiWrapper>
```
//Send data
```
let markerList = []
export class MapContainer extends Component {
constructor(props) {
super(props);
this.state = {};
markerList = props.eventList;
```
//I want to put this fetched data to Markers
```
return (
<Map google={google} zoom={14} onClick={this.onMapClick} style={mapStyles} initialCenter={initialCenter}>
{
markerList.map(marker => {
return (
<Marker
key={marker.id}
onClick={this.onMarkerClick}
title={marker.title}
name={marker.name}
position={{
lat: marker.lat,
lng: marker.lng
}}
/>
...
```
Actually, I want only to have Markers from web api in my google maps. When I send hard-coded arrar{} with data it works but when I send with this api. First renders child, then takes from api. So I don't have any Markers on my map.
I read about:
a)componentWillMount
b)event on google maps like onChange or onBoundsChanged but I have no idea how to use it in my project.
Normally in WPF I had binding, here google maps works strange. JS should refresh automaticly when data comes. How to have Markers from api?
You are directly mutating the state like,
this.state.eventList = requestResponse.data; //direct mutation
You never mutate state like this, because it is not the right way to change state and it will not re-render your component.
You must use setState to change your state, which will cause a re-render and your component will get data.
this.setState({eventList : requestResponse.data})
Also make sure you are adding your child component when your data is ready,
{this.state.eventList.length > 0 && <GoogleApiWrapper eventList={this.state.eventList} ></GoogleApiWrapper>}
main.js
import React from 'react';
import GoogleMapsWrapper from './GoogleMapsWrapper.js';
import { Marker } from 'react-google-maps';
import MarkerClusterer from "react-google-/lib/components/addons/MarkerClusterer";
class DemoApp extends React.Component {
componentWillMount() {
this.setState({ markers: [] })
}
componentDidMount() {
const url = [
// Length issue
`https://gist.githubusercontent.com`,
`/farrrr/dfda7dd7fccfec5474d3`,
`/raw/758852bbc1979f6c4522ab4e92d1c92cba8fb0dc/data.json`
].join("")
fetch(url)
.then(res => res.json())
.then(data => {
this.setState({ markers: data.photos });
});
}
render () {
return (
<GoogleMapsWrapper
googleMapURL="https://maps.googleapis.com/maps/api/js?v=3.exp&libraries=geometry,drawing,places"
loadingElement={<div style={{ height: `100%` }} />}
containerElement={<div style={{ height: `400px` }} />}
mapElement={<div style={{ height: `100%` }}
defaultZoom={3}
defaultCenter={{ lat: 25.0391667, lng: 121.525 }}>
<MarkerClusterer
averageCenter
enableRetinaIcons
gridSize={60}>
{this.state.markers.map(marker => (
<Marker
key={marker.photo_id}
position={{ lat: marker.latitude, lng: marker.longitude }}
/>
))}
</MarkerClusterer>
</GoogleMapsWrapper>
);
}
}
GoogleMapsWrapper.js
import React from 'react';
import { GoogleMap,withGoogleMap,withScriptjs } from 'react-google-maps';
export default const GoogleMapsWrapper = withScriptjs(withGoogleMap(props => {
return <GoogleMap {...props} ref={props.onMapMounted}>{props.children}</GoogleMap>
}));
Follow https://github.com/tomchentw/react-google-maps/issues/636

How to implement geolocation in a react app with Google Maps JS API instead of hard-coded location?

I have a React app which uses Google Maps API. I am using Foursquare API also, to fetch data about venues. Currently i am fetching about venues near Nashville, TN, keywords "yoga" and "coffee". I want to use the user's current location, and Nashville as a fallback in case they do not allow.
i've got this from MDN:
var options = {
enableHighAccuracy: true,
timeout: 5000,
maximumAge: 0
};
function success(pos) {
var crd = pos.coords;
console.log('Your current position is:');
console.log(`Latitude : ${crd.latitude}`);
console.log(`Longitude: ${crd.longitude}`);
console.log(`More or less ${crd.accuracy} meters.`);
}
function error(err) {
console.warn(`ERROR(${err.code}): ${err.message}`);
}
navigator.geolocation.getCurrentPosition(success, error, options);
and am looking for help implementing this in my code. How do i start with replacing the near: "Nashville, TN", below with the geolocation code? This is my app.js:
import React, { Component } from 'react';
import './App.css';
import SquareAPI from './API/';
import Map from './component/Map';
import SideBar from './component/Sidebar';
class App extends Component {
constructor(){
super();
this.state = {
venues: [],
markers: [],
center: [],
zoom: 14,
updateSuperState: obj => {
this.setState(obj);
}
};
}
closeAllMarkers = () => {
const markers = this.state.markers.map(marker => {
marker.isOpen = false;
return marker;
});
this.setState({ markers: Object.assign(this.state.markers, markers) });
};
handleMarkerClick = marker => {
this.closeAllMarkers();
marker.isOpen = true;
this.setState({ markers: Object.assign(this.state.markers, marker) });
const venue =this.state.venues.find(venue => venue.id === marker.id);
SquareAPI.getVenueDetails(marker.id).then(res => {
const newVenue = Object.assign(venue, res.response.venue);
this.setState({ venues: Object.assign(this.state.venues, newVenue) })
console.log(newVenue);
});
};
handleListItemClick = venue =>{
const marker = this.state.markers.find(marker => marker.id === venue.id)
this.handleMarkerClick(marker)
}
componentDidMount(){
SquareAPI.search({
near:"Nashville, TN",
query: "yoga",
limit: 10
}).then(results => {
const { venues } = results.response;
const { center } = results.response.geocode.feature.geometry;
const markers = venues.map(venue => {
return {
lat: venue.location.lat,
lng: venue.location.lng,
isOpen: false,
isVisible: true,
id: venue.id
};
})
this.setState({ venues, center, markers });
}).catch(error =>{
console.log("Error: " + error)
})
}
render() {
return (
<div className="App">
<SideBar {...this.state} handleListItemClick={this.handleListItemClick}/>
<Map {...this.state}
handleMarkerClick={this.handleMarkerClick}/>
</div>
);
}
}
export default App;
and my Map.js - i may also need to do it at line 10, defaultCenter=...
/* global google */
import React, { Component } from 'react';
import { withScriptjs, withGoogleMap, GoogleMap, Marker, InfoWindow } from 'react-google-maps';
const MyMapComponent = withScriptjs(
withGoogleMap(props => (
<GoogleMap
defaultZoom={8}
zoom={props.zoom}
defaultCenter={{ lat: -36.186, lng: -87.066 }}
// defaultCenter={
// }
center={{
lat: parseFloat(props.center.lat),
lng: parseFloat(props.center.lng)
}}
>
{props.markers &&
props.markers.filter(marker => marker.isVisible).map((marker, idx, arr) => {
const venueInfo = props.venues.find(venue => venue.id === marker.id);
return (
<Marker
key={idx}
position={{ lat: marker.lat, lng: marker.lng }}
onClick={() => props.handleMarkerClick(marker)}
animation={arr.length === 1
? google.maps.Animation.BOUNCE
: google.maps.Animation.DROP}
>
{marker.isOpen &&
venueInfo.bestPhoto && (
<InfoWindow>
<React.Fragment>
<img src={`${venueInfo.bestPhoto.prefix}300x300${venueInfo.bestPhoto.suffix}`} alt={venueInfo.name} />
<p>{venueInfo.name}</p>
</React.Fragment>
</InfoWindow>
)}
</Marker>
);
})}
</GoogleMap>
))
);
export default class Map extends Component {
render() {
return (
<MyMapComponent
{...this.props}
isMarkerShown
googleMapURL="https://maps.googleapis.com/maps/api/js?key=API_REMOVED"
loadingElement={<div style={{ height: `100%` }} />}
containerElement={<div style={{ height: `100%`, width: `65%` }} />}
mapElement={<div style={{ height: `100%`}} />}
/>
);
}
}
thanks!
Use the browsers geolocation.
There is an example in the docs.
In terms of React, you would set locations to state, (add a field), pass them to the Map component via prop.
Something like this
class Anything extends Component{
state = {
location : ''
} //no need for constructor no more, these are called class fields.
getPosition= ()=> {
console.log(navigator.gelocation)
//look at example in the docs and then
this.setState(response from navigator)
}
render(){
return (
<Map {...this.state}> // as you are spreading you are good here, access to
// geolocation via this.props.location in map
// component
)
}
}
https://developers.google.com/maps/documentation/javascript/geolocation

Updating Parent State Dynamically

I am trying to update my parent compenent's state according to child's component input value and render components again.
I have App, Map and ListPlaces components.
Map component shows the map and markers and takes markers from App component as a prop.
ListPlaces component has own state(searchQuery) and a method(updateQuery). Basically it uses regexp and filter the results according to the input and show filtered values in the list element. It's fine, however, I need much more than this. What I want to do here? According to input value changes, I want to update my markers (state in App component) and re-render my map component again to show only related markers on the map. Idea is basic, but I couldn't implement it.
When I try to change my markers which is actually array, it would be 0. I will share my all code but I need to say that I think the problem probably is about onChange method in the input element (ListPlaces)
App.js
class App extends Component {
constructor(props) {
super(props);
this.state = {
places: [],
markers: [],
markerID: -1,
newmarkers: []
};
this.changeMarkers = this.changeMarkers.bind(this);
}
componentDidMount() {
fetch(
"api_url"
)
.then(response => response.json())
.then(data => {
this.setState({
places: data.response.venues,
markers: data.response.venues
});
})
.catch(error => {
console.log("Someting went wrong ", error);
});
}
openInfo = (e, id) => {
this.setState({
markerID: id
});
};
closeInfo = () => {
this.setState({
markerID: -1
});
};
changeMarkers = newValue => {
const newmarkers = this.state.places.filter(
place => place.name === newValue
);
this.setState({
markers: newmarkers
});
};
toggleListPlaces = () => {
const nav = document.getElementById("nav-toggle");
const body = document.getElementsByTagName("body")[0];
nav.classList.toggle("active");
if (body.classList.contains("show-nav")) {
body.classList.remove("show-nav");
} else {
// If sidebar is hidden:
body.classList.add("show-nav");
}
};
render() {
return (
<div className="App">
<Map
role="application"
places={this.state.places}
markers={this.state.markers}
openInfoHandler={this.openInfo}
closeInfoHandler={this.closeInfo}
markerID={this.state.markerID}
googleMapURL="map_url"
loadingElement={<div style={{ height: "100%" }} />}
containerElement={<div style={{ height: "100%" }} />}
mapElement={<div style={{ height: "100%" }} />}
/>
<ListPlaces
toggleListHandler={this.toggleListPlaces}
locations={this.state.places}
openInfoHandler={this.openInfo}
changeMarkersHandler={this.changeMarkers}
/>
</div>
);
}
}
export default App;
ListPlaces
class ListPlaces extends Component {
state = {
searchQuery: ""
};
updateQuery = query => {
this.setState({ searchQuery: query});
};
render() {
const { toggleListHandler, locations, openInfoHandler, changeMarkersHandler} = this.props;
let showLocations;
if (this.state.searchQuery) {
const match = new RegExp(escapeRegExp(this.state.searchQuery), "i");
showLocations = locations.filter(location =>match.test(location.name));
} else {
showLocations = locations;
}
return (
<div>
<aside>
<h2>Restaurants</h2>
<nav>
<div className="search-area">
<input
className="search-input"
type="text"
placeholder="Search Restaurant"
value={this.state.searchQuery}
onChange={e => {this.updateQuery(e.target.value); changeMarkersHandler(e.target.value)}}
/>
</div>
<ul>
{showLocations.map(location => {
return (
<li
key={location.id}
onClick={e =>
openInfoHandler(e, location.id)
}
>
{location.name}
</li>
);
})}
</ul>
</nav>
<p>Information provided by Foursquare</p>
</aside>
<a
onClick={toggleListHandler}
id="nav-toggle"
className="position"
>
<span />
</a>
</div>
);
}
}
export default ListPlaces;
Map
const Map = withScriptjs(withGoogleMap((props) =>
<GoogleMap
defaultZoom={14}
defaultCenter={{ lat: 48.2854790, lng: -143.1407394 }}
>
{props.markers.map(restaurant => {
let marker = (
<Marker
id={restaurant.id}
key={restaurant.id}
name={restaurant.name}
position={{lat: restaurant.location.lat, lng: restaurant.location.lng}}
address={restaurant.location.address}
defaultAnimation={window.google.maps.Animation.DROP} // Should be 1 or 2 according to Stackoverflow
onClick={e => {props.openInfoHandler(e, restaurant.id)}}
animation = {props.markerID === restaurant.id && window.google.maps.Animation.BOUNCE}
>
{props.markerID === restaurant.id && (
<InfoWindow onCloseClick={e => {props.closeInfoHandler()}}>
<div className="info-window">
<p className="restaurant-name">{restaurant.name}</p>
<p className="restaurant-address">{restaurant.location.address}</p>
</div>
</InfoWindow>
)}
</Marker>
);
return marker;
})}
</GoogleMap>
))
export default Map;
you're on the right track - you need to lift up the filter value/filter operation into the common parent
App.js
class App extends React.Component {
onChangeFilter = (newFilter) => {
this.setState({ filter: newFilter })
}
render () {
const { filter, places } = this.state
const mPlaces = places.filter(/* filter places here */)
return (
<div className="App">
<ListPlaces
places={ mPlaces }
onChangeFilter={ this.onChangeFilter }
...
/>
<Map
locations={ mPlaces }
...
/>
</div>
)
}
}
ListPlaces.js
class ListPlaces extends React.Component {
updateQuery = (query) => {
this.props.onChangeFilter(query)
}
...
}
this is a common pattern in React - so common it has its own page in the React docs.

Retrieve row value selected in a Table as an array and send the results to another function on React

How can I console log selected values displayed on a Table component, then store my selection and pass it to a second function?
I have a table showing up data from my API, the table has checkboxes on each one of its rows. I'm using the < Table /> Material UI component for React.
According to documentation the the onRowSelection (similar to onClick) prop should give me an array of the selected rows (only the indices), for example If I select the first row the console will print [0] and if I selected the first and the fifth , the console will print [0,4]
Now, the data that is feeding the table is coming from my state which is data coming from my API pretty much this.state.dataTable = response.data (see code at the end)
so it looks like it's looping thru this.state.dataTable and is not considering the event being fired. what am I doing wrong?
on my function that goes inside onRowSelection I did:
handleRowSelection (i) {
for (let x = 0, len = i.length; x < len; x++) {
i = this.state.dataTable[x];
console.log(i);
}
}
Which I first thought it was giving the right value. when I click the first checkbox (row) it gave the value of the first row element, but when I clicked the 6th checkbox it's giving the value of the second row element, 7th checkbox = third element and so on.
I've also tried this
handleRowSelection (row) {
const selectedRows = []
this.state.dataTable.forEach((row, i) => {
row = row.indexOf(i) > -1
selectedRows.push(row)
}
console.log(selectedRows)
Which gives me an interesting value such as: [false, false, false, true, false, false, true]
Needless to say, the true values represent the checkboxes I've selected
CODE (skip til the begining of the Class)
import ...
import {Table, TableBody, TableHeader, TableHeaderColumn, TableRow,
TableRowColumn} from "material-ui/Table";
const REAL_URL = `//xx.xx.xx.xx/getData/`;
const markers = [
{
key: "Q123456789",
position: [37.786464, -122.411047],
children: "My first popup"
},
{
key: "P234567890",
position: [40.689192, -74.044563],
children: "My second popup"
}
];
const MyPopupMarker = ({ children, position, index, handleToggle }) => (
<Marker onClick={() => handleToggle(index)} position={position}>
<Popup>
<span>{children}</span>
</Popup>
</Marker>
);
const MarkerList = ({ markers, handleToggle }) => {
const items = markers.map(({ key, ...props }, i) => (
<MyPopupMarker key={key} {...props} index={i} handleToggle={handleToggle} />
));
return <div>{items}</div>;
};
// var holdArray = []
class Mapper extends Component {
constructor(props) {
super(props);
this.handleToggle = this.handleToggle.bind(this);
this.handleRowSelection = this.handleRowSelection.bind(this);
this.handleClose = this.handleClose.bind(this);
this.handleDeploy = this.handleDeploy.bind(this);
this.state = {
lat: 29.761993,
lng: -95.366302,
zoom: 4,
open: false,
places: [],
selectedMarker: null,
selectable: true,
multiSelectable: true,
enableSelectAll: true,
dataTable: [],
selectedRows: []
};
}
componentDidMount() {
this.setState({
places: markers
});
}
handleToggle(index) {
const self = this;
const selectedMarker = this.state.places[index];
this.setState({
open: !this.state.open,
selectedMarker: selectedMarker
});
const LAST_URL = REAL_URL + this.state.selectedMarker.key;
axios
.get(LAST_URL)
.then(response => {
self.setState({
dataTable: response.data
});
console.log(response.data);
})
.catch(function(error) {
console.log(error);
});
}
handleRowSelection (i) {
for (let x = 0, len = i.length; x < len; x++) {
i = this.state.dataTable[x];
console.log(i);
}
}
handleDeploy () {
let resultObject = {
"devices": this.state.selectedMarker.key,
// "app": this.handleRowSelection()
}
// console.log(resultObject)
}
render() {
const center = [this.state.lat, this.state.lng];
const selectedMarker = this.state.selectedMarker;
let availableRows = this.state.dataTable.map((row, k)=>{
return (
<TableRow key={k} selected={row.selected}>
<TableRowColumn>{row}</TableRowColumn>
<TableRowColumn>Unknown</TableRowColumn>
</TableRow>
)
});
return (
<div>
<Map center={center}
zoom={this.state.zoom}
minZoom={3}
style={styles.map}>
<TileLayer
url="https://cartodb-basemaps-{s}.global.ssl.fastly.net/light_all/{z}/{x}/{y}.png"
attribution="© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors"
/>
<MarkerList markers={markers} handleToggle={this.handleToggle} />
</Map>
<Drawer
width={500}
openSecondary={true}
docked={false}
open={this.state.open}
onRequestChange={open => this.setState({ open })}
containerStyle={styles.whitebox}
>
{
selectedMarker ? (
<div>
<Card style={styles.appMedia}>
<CardTitle
titleStyle={styles.drawTitle}
subtitleStyle={styles.drawTitle}
title={selectedMarker.key}
subtitle="Common Field Equipment"
/>
</Card>
<Table
selectable={this.state.selectable}
multiSelectable={this.state.enableSelectAll}
onRowSelection={(selectedApps) => this.handleRowSelection(selectedApps, this.props)}
>
<TableHeader
enableSelectAll={this.state.enableSelectAll}
displaySelectAll={false}
>
<TableRow>
<TableHeaderColumn>Applications</TableHeaderColumn>
<TableHeaderColumn>Status</TableHeaderColumn>
</TableRow>
</TableHeader>
<TableBody
deselectOnClickaway={this.state.clickAway}
showRowHover={true}
>
{availableRows}
</TableBody>
</Table>
<RaisedButton
label="START SELECTED"
onClick={this.handleDeploy}
style={styles.buttonStl}
labelPosition="before"
backgroundColor="#363636"
labelStyle={styles.labelStl}
icon={<BeenHere />}
/>
<RaisedButton
label="STOP SELECTED"
style={styles.buttonStl}
labelPosition="before"
backgroundColor="#FF0000"
labelStyle={styles.labelStl}
icon={<Cancel />}
/>
</div>
) : null
}
</Drawer>
</div>
);
}
}
export default Mapper;
link to component http://www.material-ui.com/#/components/table
In your 2 handleRowSelection examples, you are either redefining a variable or not using the passed in variable. This should work:
handleRowSelection (indexes) {
const selectedRows = indexes.map(x => this.state.dataTable[x]);
}
Edit: Looks like if all rows are selected, then onRowSelection will return the string "all" so that will need to be handled:
handleRowSelection (indexes) {
const {dataTable} = this.state;
const selectedRows = (indexes === 'all')
? [...dataTable] // copy of the dataTable
: indexes.map(x => dataTable[x]);
}
Edit
Showing the relevant code for checking the checkboxes:
constructor(props) {
// ...
this.state = {
// ...
dataTable: [],
selectedIndexes: []
}
}
handleRowSelection (indexes) {
this.setState({selectedIndexes: indexes});
}
render() {
//...
let availableRows = this.state.dataTable.map((row, k) => {
return (
<TableRow key={k} selected={this.state.selectedIndexes.indexOf(k) !== -1}>
<TableRowColumn>{row}</TableRowColumn>
<TableRowColumn>Unknown</TableRowColumn>
</TableRow>
)
});
//...
}

Categories

Resources