I have a simple data structure that lists some information. The problem is when I click the icon it opens the both content. I didn't find a solution how to open the current div.
class HotSpots extends React.Component {
constructor(props, context) {
super(props, context);
this.handleClick = this.handleClick.bind(this);
this.state = {
isOpen: false,
icon: 'fa-plus'
}
}
handleClick(event) {
console.log(this.state.isOpen, 'clicked');
this.setState({
isOpen: !this.state.isOpen,
icon: this.state.icon === 'fa-plus' ? 'fa-remove' : 'fa-plus'
})
}
render() {
//console.log(DATA.module.hotSpots.popups);
let items = DATA.module
.hotSpots
.popups.map(n =>
<div data-open={n.openByDefault}
data-coordx={n.config.coords[0]}
data-coordy={n.config.coords[1]}
data-enable-mobile-chords={n.config.useMobileCoords>
<a style={{
marginLeft: n.config.coords[0],
marginRight: n.config.coords[1]
}}
onClick={this.handleClick}>
<i className={`fa ${this.state.icon}`}></i>
</a>
<section data-is-open={this.state.isOpen} className="hotspot-detail">
<h2>{n.headline}</h2>
<p>{n.bodyCopy}</p>
</section>
</div>
);
return (
<section className="hotspots">
{console.log('status' + this.state.isOpen)}
<div>{items}</div>
</section>
)
}
}
class App extends React.Component {
constructor(props) {
super(props)
}
render() {
return <div name={this.props.name}
data-src-phone-highres={this.props.srcPhoneHighRes}
data-src-desktop={this.props.srcDesktop}
data-src-tablet-highres={this.props.srcTabletHighres}
data-src-phone={this.props.phone}
data-src-tablet={this.props.srcTablet}
data-src-desktop-highres={this.props.srcDesktopHighres}>
<HotSpots />
</div>
}
}
React.render( <App name={DATA.moduleName}
srcPhoneHighRes={DATA.images.desktop.externalUrl}
/>, app);
http://codepen.io/agriboz/pen/MyGOMG?editors=0010
Thanks in advance
As suggested by #XtremeCoder. You're not using the unique key identifier to trace your event. So in your react component pass the key in the click handler as follow onClick={this.handleClick.bind(this, i, n) Then include a new state i which can capture the current element clicked.
this.state = {
i: 0,
isOpen: false,
}
}
handleClick(i,n) {
this.setState({
i: i,
isOpen: !this.state.isOpen,
})
Now you can check for boolean on state change to display the content and change the icon
//for icon
<i className={`fa ${(this.state.isOpen && this.state.i==i ? 'fa-close' : 'fa-plus')}` }></i>
//for content
<section data-is-open={this.state.isOpen && this.state.i==i} className="hotspot-detail">
Here is the fully functioning code
let DATA = {
"module": {
"name": "E-Hot-PDP-X9405C-X9305C-Series-en_US-2015-03-M24-fullflush",
"masterName": "E-Hot-PDP-X9405C-X9305C-Series-en_GL-2015-03-M24-fullflush",
"maintenanceStructure": "Electronics/05_Televisions_and_Home_Cinema/01_Televisions/X9405C-X9305C-Series",
"_id": "urn:sony:module:editorial_hotspots:590359239320250140028",
"isLocalized": "false",
"masterId": "urn:sony:module:editorial_hotspots:1991426988117153303078371",
"version": "20160122080005",
"readyForLive": "No",
"mode": "full",
"editorialEnabled": "yes",
"type": "urn:sony:module:editorial_hotspots",
"createdAt": 1430303942648,
"updatedAt": 1453816025859,
"dependents": [
"urn:sony:media:image_family:1995667013507913303041209"
],
"config": {
"style": "dark-text-trans-box",
"background": "true",
"grouping": "group-middle",
"type": "full",
"variation": {
"background": "white"
},
"layout": {
"name": "full",
"text": "full",
"alignment": "center",
"columns": [
"12",
"0"
]
}
},
"hotSpots": {
"popups": [
{
"headline": "Full flush surface",
"alwaysOpen": "no",
"openByDefault": "no",
"bodyCopy": "With thin styling and a full flush screen surface, you’ll enjoy an immersive viewing experience.",
"dropShadow": "no",
"bullets": [],
"links": [],
"config": {
"size": "large",
"useMobileCoords": "no",
"hotSpotsIcon": "yes",
"dropShadow": "yes",
"coords": [
"10%",
"31%"
]
}
},
{
"headline": "Wedge",
"alwaysOpen": "no",
"openByDefault": "no",
"bodyCopy": "The unique shape has been designed to increase speaker capacity for a rich, full sound.",
"dropShadow": "no",
"bullets": [],
"links": [],
"config": {
"size": "large",
"useMobileCoords": "no",
"hotSpotsIcon": "yes",
"dropShadow": "yes",
"coords": [
"78.5%",
"49%"
]
}
}
],
"image": {
"type": "urn:sony:media:image_container",
"imageFamily": {
"name": "ImgF-PDP-X9405C-X9305C-Series-2015-03-M24-fullflush",
"masterName": "ImgF-PDP-X9405C-X9305C-Series-2015-03-M24-fullflush",
"maintenanceStructure": "Electronics/05_Televisions_and_Home_Cinema/01_Televisions/X9405C-X9305C-Series",
"_id": "urn:sony:media:image_family:1995667013507913303041209",
"isLocalized": "false",
"masterId": "urn:sony:media:image_family:1995667013507913303041209",
"localizedImageFamily": {
"name": "Loc-ImgF-PDP-XBR-X9405C-X9305C-Series-2015-03-M24-fullflush-SOLA",
"masterName": "Loc-ImgF-PDP-XBR-X9405C-X9305C-Series-2015-03-M24-fullflush-SOLA",
"maintenanceStructure": "Electronics/05_Televisions_and_Home_Cinema/01_Televisions/X9405C-X9305C-Series",
"_id": "urn:sony:localized_image_family:4512059944822603303579063",
"isLocalized": "false",
"masterId": "urn:sony:localized_image_family:4512059944822603303579063",
"locale": "all",
"version": "20150327064448",
"readyForLive": "No",
"type": "urn:sony:localized_image_family",
"createdAt": 1428930904784,
"updatedAt": 1428930906576,
"localizedImageFamilies": [
{
"imageFamily": {
"_id": "urn:sony:media:image_family:4492784185533253304288460",
"isLocalized": "false",
"locale": "all",
"maintenanceStructure": "Electronics/05_Televisions_and_Home_Cinema/01_Televisions/X9405C-X9305C-Series",
"masterId": "urn:sony:media:image_family:4492784185533253304288460",
"masterName": "ImgF-PDP-XBR-X9405C-X9305C-Series-2015-03-M24-fullflush-SOLA",
"name": "ImgF-PDP-XBR-X9405C-X9305C-Series-2015-03-M24-fullflush-SOLA",
"readyForLive": "No",
"type": "urn:sony:media:image_family",
"version": "20150327061216",
"createdAt": 1428930904949,
"updatedAt": 1428930906679,
"dependents": [],
"images": {
"desktop": {
"internalUrl": "https://prod-imgws.sony.eu/cms/images/Electronics/05_Televisions_and_Home_Cinema/01_Televisions/X9405C-X9305C-Series/E-Hot-PDP-X94-X93-en_GL-2015-03-M24-fullflush_XBR-desktop.jpg",
"md5": "90e6df273a7fe6ba9ef6411a83a995e3",
"mimeType": "image/jpg",
"status": "published",
"uploadAttempts": 1,
"uploadLastAttemptAt": 1428412207508,
"assetHandle": [
"a|23360418"
]
}
}
},
"locales": [
"es_AR",
"es_BO",
"pt_BR",
"es_CL",
"es_CO",
"es_CR",
"es_DO",
"es_EC",
"es_SV",
"es_GT",
"es_HN",
"es_MX",
"es_PA",
"es_PY",
"es_PE",
"es_PR",
"es_VE",
"es_NI"
]
}
],
"dependents": [
"urn:sony:media:image_family:4492784185533253304288460"
]
},
"locale": "all",
"version": "20150327075311",
"readyForLive": "No",
"type": "urn:sony:media:image_family",
"createdAt": 1428930904791,
"updatedAt": 1453731785919,
"dependents": [
"urn:sony:localized_image_family:4512059944822603303579063"
],
"images": {
"desktop": {
"internalUrl": "https://prod-imgws.sony.eu/cms/images/Electronics/05_Televisions_and_Home_Cinema/01_Televisions/X9405C-X9305C-Series/E-Hot-PDP-X94-X93-en_GL-2015-03-M24-fullflush_desktop.jpg",
"mimeType": "image/jpg",
"uploadAttempts": 1,
"uploadLastAttemptAt": 1427203801114,
"status": "published",
"md5": "93a8c28123eede1d42d33871e6553daf",
"assetHandle": [
"a|23104311"
],
"externalUrl": "//sonyglobal.scene7.com/is/image/gwtprod/93a8c28123eede1d42d33871e6553daf?fmt=jpeg"
},
"phone": {
"internalUrl": "https://prod-imgws.sony.eu/cms/images/Electronics/05_Televisions_and_Home_Cinema/01_Televisions/X9405C-X9305C-Series/E-Hot-PDP-X94-X93-en_GL-2015-03-M24-fullflush_phone.jpg",
"mimeType": "image/jpg",
"uploadAttempts": 1,
"uploadLastAttemptAt": 1427203801114,
"status": "published",
"md5": "40df54c624e5cebfa27fdae4d3207f5d",
"assetHandle": [
"a|23104300"
],
"externalUrl": "//sonyglobal.scene7.com/is/image/gwtprod/40df54c624e5cebfa27fdae4d3207f5d?fmt=jpeg"
},
"tablet": {
"internalUrl": "https://prod-imgws.sony.eu/cms/images/Electronics/05_Televisions_and_Home_Cinema/01_Televisions/X9405C-X9305C-Series/E-Hot-PDP-X94-X93-en_GL-2015-03-M24-fullflush_tablet.jpg",
"mimeType": "image/jpg",
"uploadAttempts": 1,
"uploadLastAttemptAt": 1427203801115,
"status": "published",
"md5": "5e9ab8ac405f170a5b24f1ccf1f71c1f",
"assetHandle": [
"a|23104304"
],
"externalUrl": "//sonyglobal.scene7.com/is/image/gwtprod/5e9ab8ac405f170a5b24f1ccf1f71c1f?fmt=jpeg"
}
}
}
}
},
"locale": "en_US",
"contentLocale": "en_US"
},
"moduleId": "editorial_hotspots_590359239320250140028",
"moduleName": "editorial_hotspots"
};
class HotSpots extends React.Component {
constructor(props, context) {
super(props, context);
//this.handleClick = this.handleClick.bind(this);
this.state = {
i: 0,
isOpen: false,
}
}
handleClick(i,n) {
this.setState({
i: i,
isOpen: !this.state.isOpen,
})
}
render() {
//console.log(DATA.module.hotSpots.popups);
let items = DATA.module
.hotSpots
.popups.map((n, i) =>
<div key={i}
onClick={this.handleClick.bind(this, i, n)} data-open={n.openByDefault}
data-coordx={n.config.coords[0]}
data-coordy={n.config.coords[1]}
data-enable-mobile-chords={n.config.useMobileCoords}>
<a style={{
marginLeft: n.config.coords[0],
marginRight: n.config.coords[1]
}}
>
<i className={`fa ${(this.state.isOpen && this.state.i==i ? 'fa-close' : 'fa-plus')}` }></i>
</a>
<section data-is-open={this.state.isOpen && this.state.i==i} className="hotspot-detail">
<h2>{n.headline}</h2>
<p>{n.bodyCopy}</p>
</section>
</div>
);
return (
<section className="hotspots">
{console.log('status' + this.state.isOpen)}
<div>{items}</div>
</section>
)
}
}
class App extends React.Component {
constructor(props) {
super(props)
}
render() {
return <div className={`${DATA.module.config.variation.background} ${DATA.module.config.type}`}
name={this.props.name}
data-src-desktop={this.props.srcDesktop}
data-src-phone={this.props.phone}
data-src-tablet={this.props.srcTablet}>
<HotSpots />
</div>
}
}
React.render( <App name={DATA.moduleName}
srcDesktop={DATA.module.hotSpots.image.imageFamily.images.desktop.externalUrl}
srcPhone={DATA.module.hotSpots.image.imageFamily.images.phone.externalUrl}
srcTablet={DATA.module.hotSpots.image.imageFamily.images.tablet.externalUrl}
/>, app);
Codepen:
http://codepen.io/anon/pen/WwJPLe?editors=0010
Hope it helps!
This is because you are associating same state(isOpen) to all the contents.
To show this modified your pen to this:
handleClick(event) {
this.setState({
parentClass :event.currentTarget.className,
isOpen: !this.state.isOpen,
icon: this.state.icon === 'fa-plus' ? 'fa-remove' : 'fa-plus'
})
}
render() {
let items = DATA.module
.hotSpots
.popups.map((n,i) =>
<div data-open={n.openByDefault}
data-coordx={n.config.coords[0]}
data-coordy={n.config.coords[1]}
data-enable-mobile-chords={n.config.useMobileCoords}>
<a style={{
marginLeft: n.config.coords[0],
marginRight: n.config.coords[1]
}}
onClick={this.handleClick} className={'parent'+i}>
<i className={`fa ${this.state.icon}`}></i>
</a>
<section data-is-open={this.state.isOpen && (this.state.parentClass===("parent"+i)) } className="hotspot-detail">
<h2>{n.headline}</h2>
<p>{n.bodyCopy}</p>
</section>
</div>
);
return (
<section className="hotspots">
{console.log('status' + this.state.isOpen)}
<div>{items}</div>
</section>
)
}
}
http://codepen.io/Debabrata89/pen/bpMOOM?editors=0010
Hope this helps
Related
I'm using React Navigation to send the array additional in the DisplayItem screen, I use componentDidMount to set the state with the array and I use SectionList to display the array, the goal is to use the function pressOptional to update the value selected in the array, It works at the moment, but the problem is that it doesn't update the state in real-time, the changes in SectionList happen only when I re-render the screen.
Array: additional
Array [
Object {
"data": Array [
Object {
"id": 0,
"price": 1,
"selected": true,
"title": "Ranch",
"type": "Sides",
},
Object {
"id": 1,
"price": 1,
"selected": false,
"title": "Blue Cheese",
"type": "Sides",
},
],
"id": 0,
"required": false,
"title": "Sides",
},
Object {
"data": Array [
Object {
"id": 0,
"price": 0,
"selected": false,
"title": "Hot Sauce",
"type": "Sauces",
},
Object {
"id": 1,
"price": 0,
"selected": false,
"title": "Medium Sauce",
"type": "Sauces",
},
],
"id": 1,
"required": true,
"title": "Sauces",
},
]
Screen
class DisplayItem extends Component {
constructor(props) {
super(props);
this.state = {
additional: [],
}
}
componentDidMount() {
const { item } = this.props.route.params;
const additional = item.additional;
if (additional !== undefined) {
this.setState({additional:[...additional]})
}
}
pressOptional = (e) => {
const additional = this.state.additional;
additional.map((item) => {
if (item.title == e.type) {
item.data.map((item) => {
if (item.id == e.id) {
item.selected = !e.selected
}
})
}
})
}
render() {
const { additional } = this.state;
return (
<View>
<SectionList
sections={additional}
keyExtractor={(item, index) => item + index}
renderSectionHeader={({ section: { type, required } }) => (
<View>
<Text>{type}</Text>
</View>
)}
renderItem={({ item, section: { required } }) => {
return (
<TouchableOpacity key={item.id} onPress={() => this.pressOptional(item)}>
<Ionicons
name={item.selected == false ? 'square-outline' : 'square'}
/>
<Text>{item.title}</Text>
<Text>${item.price}</Text>
</TouchableOpacity>
)
}
}
/>
</View>
)
}};
export default DisplayItem;
Try to use useState instead State classes:
https://reactnative.dev/docs/state
I have a REST call which returns different sets of result. Each data set contains data for different parts of the page. It contains nested array of objects and I am not sure how do I easily display the name and value pairs from the rest call to my page depending on the certain section.
Here's what the REST call response looks like:
{
"dstrSpecificHelpRs": [
{
"row": [
{
"name": "HELP_TEXT_TITLE_NM",
"value": "TestAgain and again and again and again andagain50",
"link": {
"exists": false,
"linkType": null,
"linkId": null
}
},
{
"name": "HELP_TEXT_ID",
"value": "100114",
"link": {
"exists": false,
"linkType": null,
"linkId": null
}
},
{
"name": "Help",
"value": "Help",
"link": {
"exists": true,
"linkType": "url",
"linkId": "www.google.com"
}
}
]
},
{
"row": [
{
"name": "HELP_TEXT_TITLE_NM",
"value": "Testing Helpline Page and 2301 DisasterONLY",
"link": {
"exists": false,
"linkType": null,
"linkId": null
}
},
{
"name": "HELP_TEXT_ID",
"value": "100174",
"link": {
"exists": false,
"linkType": null,
"linkId": null
}
},
{
"name": "Help",
"value": "Help",
"link": {
"exists": true,
"linkType": "url",
"linkId": "www.google.com"
}
}
]
}
],
"rgstInfoRs": [
{
"row": [
{
"name": "PREFIX_NM",
"value": "MS",
"link": {
"exists": false,
"linkType": null,
"linkId": null
}
},
{
"name": "FST_NM",
"value": "MITZI",
"link": {
"exists": false,
"linkType": null,
"linkId": null
}
}
]
}
],
"insSettlementRs": [
{
"row": [
{
"name": "ON_FILE",
"value": "0",
"link": {
"exists": false,
"linkType": null,
"linkId": null
}
}
]
}
],
"dstrOptionRs": [
{
"row": [
{
"name": "DSTR_OPTION",
"value": "1",
"link": {
"exists": false,
"linkType": null,
"linkId": null
}
},
{
"name": "HELPLINE_AREA_CD",
"value": "818",
"link": {
"exists": false,
"linkType": null,
"linkId": null
}
},
{
"name": "HELPLINE_PHN_NR",
"value": "5055511",
"link": {
"exists": false,
"linkType": null,
"linkId": null
}
}
]
}
],
"correspondenceOutRs": [
{
"row": [
{
"name": "SUMMARY_CD_TX",
"value": "SUPER,SEAL,APPR_INTRO,APPROVAL,ECNA",
"link": {
"exists": false,
"linkType": null,
"linkId": null
}
}
]
},
{
"row": [
{
"name": "SUMMARY_CD_TX",
"value": "9069CL,SEAL",
"link": {
"exists": false,
"linkType": null,
"linkId": null
}
},
{
"name": "ASTN_PGM_CD",
"value": "MISC",
"link": {
"exists": false,
"linkType": null,
"linkId": null
}
},
{
"name": "GENERATED_DT",
"value": "2020-09-03 14:08:10.0",
"link": {
"exists": false,
"linkType": null,
"linkId": null
}
}
]
}
],
"statePhoneRs": [],
"insAssistanceRs": [
{
"row": [
{
"name": "DOC_ID",
"value": "",
"link": {
"exists": false,
"linkType": null,
"linkId": null
}
},
{
"name": "RGSN_ID",
"value": "370002900",
"link": {
"exists": false,
"linkType": null,
"linkId": null
}
}
]
}
]
}
and here's what I have working so far:
class App extends React.Component {
constructor(props) {
super(props);
this.setState = {
data: []
};
}
componentDidMount() {
fetch("https://demo3531217.mockable.io/getRegistrationData")
.then((res) => res.json())
.then((res) => {
const responseData = this.getPayloadObject(res);
this.setState({
data: responseData
});
})
.catch((error) => console.error(error));
}
getPayloadObject = (action) => {
console.log(action);
Object.keys(action).forEach((key) => {
if (typeof action[key] === "object") {
const payload = action[key];
let result = _.map(
payload,
(data, i) => {
const row = data["row"];
const rowData = _.map(row, (item) => {
return {
name: item.name,
value: item.value
};
});
console.log("rowData ", rowData);
},
[]
);
return result;
}
});
};
render() {
return (
<div>
<div>
<h1>Section 1</h1>
</div>
<div>
<h1>Section 2</h1>
</div>
</div>
);
}
}
if I wanted to display certain data for specific section how do I so in my page? Can someone please help?
link for sandbox can be found here: https://codesandbox.io/s/vibrant-sid-i140l?file=/src/App.js:75-1304
Let's try breaking the state into multiple sections. Something like this.
constructor(props) {
super(props);
this.state = {
dstrSpecificHelpRs: [],
rgstInfoRs: [],
insSettlementRs: [],
dstrOptionRs: [],
correspondenceOutRs: [],
statePhoneRs: [],
insAssistanceRs: []
};
}
Then, let's deconstruct the API response and set individual items in the state.
componentDidMount() {
fetch("https://demo3531217.mockable.io/getRegistrationData")
.then((res) => res.json())
.then((res) => {
// const responseData = this.getPayloadObject(res);
const {
dstrSpecificHelpRs,
rgstInfoRs,
insSettlementRs,
dstrOptionRs,
correspondenceOutRs,
statePhoneRs,
insAssistanceRs
} = res;
this.setState({
dstrSpecificHelpRs: dstrSpecificHelpRs,
rgstInfoRs: rgstInfoRs,
insSettlementRs: insSettlementRs,
dstrOptionRs: dstrOptionRs,
correspondenceOutRs: correspondenceOutRs,
statePhoneRs: statePhoneRs,
insAssistanceR: insAssistanceRs
});
})
.catch((error) => console.error(error));
}
Now all you have to do is find a way to loop through individual items in the state. Something like this
render() {
const dstrSpecificHelpRs = this.state.dstrSpecificHelpRs.map(row => row["row"]);
console.log("Sample = ", sample);
return (
<div>
<div>
<h1>Section 1</h1>
<div>
{dstrSpecificHelpRs.map(item => item.map(key => <p>{key.name}</p>))}
</div>
</div>
<div>
<h1>Section 2</h1>
</div>
</div>
);
}
This is by no means a perfect solution though. If you could change the response model, that would have been sweet!.
I receive JSON from my back end, I save it in my state and I want to use it in props in another react component, but it doesn't work.
I try to show need date like that in props of my component - {this.state.movies["0"]["title"]}, but it doesn't work.
constructor() {
super();
this.state = {
movies: []
}
}
componentDidMount() {
this.getAllMoviesForMainPage();
}
getAllMoviesForMainPage() {
axios.get("http://localhost:8080/showAll")
.then(response => {
this.setState({ movies: response.data })
})
}
render() {
return (
<div className="qwerty">
<MainPageComponent />
<div className='moviePreviewGrid'>
<Router>
<div className="moviePreviewGrid-row">
<div className="moviePreviewGrid-col">
<MoviePreview
Title={this.state.movies["2"]["title"]}
MoviePreviewAvatar={DrivePoster}
SeeMore="unrelated long string here"
/>
<NavLink to="/showByTitle/Драйв">
<button type="button" className="myBtn">See more</button>
</NavLink>
</div>
and structure of my JSON
[
{
"id": 1,
"title": "Джокер",
"releaseDate": "2019",
"genre": "Триллер, драма, криминал",
"duration": "122 минуты",
"rating": 8.7,
"criticReviews": [
{
"criticName": "Anton",
"review": "anton review"
},
{
"criticName": "OldCritic",
"review": "old review"
}
],
"userReviews": [
{
"nickName": "Igor",
"review": "igor review"
},
{
"nickName": "Nik",
"review": "nik review"
}
]
},
{
"id": 2,
"title": "Ирландец",
"releaseDate": "2019",
"genre": "Драма, триллер, криминал, биографический",
"duration": "209 минут",
"rating": 8.4,
"criticReviews": [
{
"criticName": "YoungCritic",
"review": "young review"
}
],
"userReviews": [
{
"nickName": "Gambit",
"review": "gambit review"
},
{
"nickName": "Andrew",
"review": "andrew review"
}
]
},
{
"id": 3,
"title": "Драйв",
"releaseDate": "2011",
"genre": "Боевик, драма",
"duration": "100 минут",
"rating": 7.8,
"criticReviews": [
{
"criticName": "Critic",
"review": "review"
}
],
"userReviews": [
{
"nickName": "Anton",
"review": "anton review"
}
]
},
{
"id": 4,
"title": "Последний человек на Земле",
"releaseDate": "2015",
"genre": "Комедия",
"duration": "22 минуты",
"rating": 7.3,
"criticReviews": [
{
"criticName": "NewCritic",
"review": "new review"
}
],
"userReviews": [
{
"nickName": "Atomf7",
"review": "atomf7 review"
}
]
},
{
"id": 5,
"title": "Интерстеллар",
"releaseDate": "2014",
"genre": "Фантастика, драма, приключения",
"duration": "169 минут",
"rating": 8.6,
"criticReviews": [
{
"criticName": "Nik",
"review": "nik review"
}
],
"userReviews": [
{
"nickName": "Alice",
"review": "alice review"
}
]
}
]
and i wont to have for example title of first movie
In the first init, the this.state.movies has a length of 0 so this.state.movies["2"]["title"] of course would have no value at all
because getAllMoviesForMainPage is async (axios call) and takes a little longer to complete, so first you must give it an initial value and only when the request completes you can give it the real value.
example:
<MoviePreview
Title={this.state.movies.length > 0 ? this.state.movies[2].title : ""}
MoviePreviewAvatar={DrivePoster}
/>
Usually a state, isLoading is used for this case. So you can know when you received your data.
In the first render movies are not already fetched from the api.
So you need to conditionally render it.
import React, { Component } from "react";
import axios from "axios";
export default class Test extends Component {
constructor() {
super();
this.state = {
movies: [],
loading: true
}
}
componentDidMount() {
this.getAllMoviesForMainPage();
}
getAllMoviesForMainPage() {
axios.get("http://localhost:8080/showAll")
.then(response => {
this.setState({ movies: response.data, loading: false })
})
}
render() {
const { loading, movies } = this.state;
if (loading) {
return <div>Loading...</div>;
} else {
return (
<div>
{movies.length > 0 ? (
<div>First movie title: {movies[0].title}</div>
) : (
<div>No movies</div>
)}
</div>
);
}
}
}
You can check this example using a fake api.
You are making a GET request in componentDidMount which is async so until the promise is resolve in .then(.. your state does not contain response.data in movies.
The important thing to remember is component gets re-render every time you do this.setState(.. , so before you do setState in your getAllMoviesForMainPage method, the initial render will happen and it will contain an empty array in this.state.movies that you have defined in constructor
Also since your response contains array of objects, you would be using movies['2'].title instead of movies['2']['title']
So your render method should contain something like this to show movie preview:
<div className="moviePreviewGrid-col">
{this.state.movies.length ? (
<MoviePreview
Title={this.state.movies['2'].title}
MoviePreviewAvatar={DrivePoster}
SeeMore="unrelated long string here"
/>
) : (
<PlaceHolderPreview />
)}
<NavLink to="/showByTitle/Драйв">
<button type="button" className="myBtn">
See more
</button>
</NavLink>
</div>
PlaceHolderPreview can be your another component that will show -- well a placeholder for preview.
Hope it all makes sense.
Does anyone know how to set a colour range for this map? The variations between the values aren't large enough to notice the change in colour. So most of the values on the map appear to be in the same colour. I would either like to set my own colours or change much these colours vary by.
I cant find the answer on how to do this in react anywhere
import React, { Component } from 'react';
import AmCharts from "#amcharts/amcharts3-react";
import { connect } from "react-redux"
import { lookup } from 'country-data';
import * as adapter from "../Adapter.js";
class App extends Component {
constructor(props) {
super(props)
this.state = {
allCountriesHouseholdSpending: null,
selectedCoutry: null,
countrySpending: [{
"id": "AU",
"value": 4447100
},
{
"id": "US",
"value": 658188
}]
}
}
componentDidMount() {
adapter.getAllCountriesrtyHouseholdSpending()
.then(spendingData => this.setState({ allCountriesHouseholdSpending: spendingData }))
}
selectedCountrySpending = (country) => {
let selectedCity = country.mapObject.enTitle
if (selectedCity !== "Russia" && selectedCity !== "Venezuela" && selectedCity !== "Bolivia" && selectedCity !== "Svalbard and Jan Mayen" && selectedCity !== "Syria" && selectedCity !== "Tanzania" && selectedCity !== "Democratic Republic of Congo") {
// console.log(lookup.countries({ name: selectedCity }));
console.log(lookup.countries({ name: selectedCity })[0].alpha3);
console.log('selected!', selectedCity)
return selectedCity
}
}
render() {
const config = {
"type": "map",
"theme": "light",
"colorSteps": 10,
"dataProvider": {
"map": "worldLow",
"getAreasFromMap": true,
"areas": [{
"id": "AU",
"value": 658188.6034,
"selected": true
},
{
"id": "AT",
"value": 217653.4063
},
{
"id": "BE",
"value": 255659.6354
},
{
"id": "CA",
"value": 896977.0966
},
],
valueLegend: {
divId: "legenddiv",
left: 10,
bottom: 0,
minValue: "little",
maxValue: "a lot!"
},
},
"areasSettings": {
"selectedColor": "#CC0000",
"selectable": true,
"balloonText": "National Spending in [[title]]: <b>[[value]]</b>"
},
"listeners": [{
"event": "clickMapObject",
"method": (e) => {
console.log(e.mapObject.enTitle)
this.selectedCountrySpending(e)
}
}]
}
return (
<AmCharts.React style={{ width: "100%", height: "600px" }} options={config} />
);
}
}
const mapStateToProps = (state) => ({
})
const mapDispatchToProps = (dispatch) => ({
})
export default connect(mapStateToProps, mapDispatchToProps)(App)
You can customize the start and end colors by setting color and colorSolid in your areasSettings. You can also specify your own color by setting the color directly in the area object, e.g.
{
"id": "AU",
"value": 88323532,
"color": "#00ff00"
},
// ...
Note that setting getAreasFromMap: true essentially enables all the other areas as if they were defined in the dataProvider, which may not be what you want.
Here's a demo of color and colorSolid:
var chart = AmCharts.makeChart("chartdiv", {
"type": "map",
"theme": "light",
"colorSteps": 10,
"dataProvider": {
"map": "worldLow",
//"getAreasFromMap": true,
"areas": [{
"id": "AU",
"value": 658188.6034,
"selected": true
},
{
"id": "AT",
// "color": "#0000ff", //if you want to specify a color directly on an area
"value": 217653.4063
},
{
"id": "BE",
"value": 255659.6354
},
{
"id": "CA",
"value": 896977.0966
},
],
valueLegend: {
divId: "legenddiv",
left: 10,
bottom: 0,
minValue: "little",
maxValue: "a lot!"
},
},
"areasSettings": {
"color": "#880000",
"colorSolid": "#008888",
"selectedColor": "#CC0000",
"selectable": true,
"balloonText": "National Spending in [[title]]: <b>[[value]]</b>"
},
"listeners": [{
"event": "clickMapObject",
"method": (e) => {
}
}]});
html, body {
width: 100%;
height: 100%;
margin: 0px;
}
#chartdiv {
width: 100%;
height: 100%;
}
<script src="//www.amcharts.com/lib/3/ammap.js"></script>
<script src="//www.amcharts.com/lib/3/maps/js/worldLow.js"></script>
<script src="//www.amcharts.com/lib/3/themes/light.js"></script>
<div id="chartdiv"></div>
I have two ReactJS components, the first one will display a grid. When a row is clicked, it will populate the 2 component with Name.
But when I try to edit the input box, it cannot be changed. What are the proper way in ReactJS to handle this.
class NameForm extends React.Component {
constructor(props) {
super(props);
this.state = { formName : ''}
this.handleFormName = this.handleFormName.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleFormName(e) {
console.log(e.target.value);
this.setState({ formName: e.target.value });
}
handleSubmit(event) {
console.log(this.state.formName);
axios.post(this.props.UrlPost, { FirstName: this.state.formName })
.then(function (response) {
});
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Name:
<input type="text" value={this.props.Name} onChange={this.handleFormName} />
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
class ComponentWithGriddle extends React.Component {
constructor(props) {
super(props);
this.state = {
selectedRowId: 0,
};
}
onRowClick(row) {
console.log(row.props.data.name);
this.setState({ selectedRowId: row.props.data.id });
this.props.handleNameChange(row.props.data.name);
}
render() {
var rowMetadata = {bodyCssClassName: rowData => (rowData.id === this.state.selectedRowId ? "selected" : '')};
//console.log(rowMetadata);
return (
<Griddle results={fakeData} onRowClick={this.onRowClick.bind(this)} columnMetadata={columnMeta} useFixedHeader={true} rowMetadata={rowMetadata} useGriddleStyles={true} />
);
}
}
class RootFrame extends React.Component {
constructor(props) {
super(props);
this.handleNameChange = this.handleNameChange.bind(this);
this.state = { Name: '' };
}
handleNameChange(name)
{
this.setState({ Name: name });
}
render() {
return (
<div>
<ComponentWithGriddle Name={this.state.Name} handleNameChange={this.handleNameChange} />
<NameForm UrlPost={this.props.UrlPost} Name={this.state.Name}/>
</div>
);
};
}
var emptyData = [];
var columnMeta = [
{
"columnName": "id",
"order": 1,
"locked": false,
"visible": true,
"displayName": "ID"
},
{
"columnName": "name",
"order": 2,
"locked": false,
"visible": true,
"displayName": "Name"
},
{
"columnName": "city",
"order": 3,
"locked": false,
"visible": true
},
{
"columnName": "state",
"order": 4,
"locked": false,
"visible": true
},
{
"columnName": "country",
"order": 5,
"locked": false,
"visible": true
},
{
"columnName": "company",
"order": 6,
"locked": false,
"visible": true
},
{
"columnName": "favoriteNumber",
"order": 7,
"locked": false,
"visible": true,
"displayName": "Favorite Number"
}
];
var rowMeta =
{
"key": "id"
};
var propertyGridMeta = [
{
"columnName": "property",
"order": 1,
"locked": false,
"visible": true,
"cssClassName": "properties-name",
"displayName": "Property"
},
{
"columnName": "description",
"order": 2,
"locked": false,
"visible": true,
"cssClassName": "properties-description",
"displayName": "Description"
},
{
"columnName": "type",
"order": 3,
"locked": false,
"visible": true,
"cssClassName": "properties-type",
"displayName": "Type"
},
{
"columnName": "default",
"order": 4,
"locked": false,
"visible": true,
"cssClassName": "properties-default",
"displayName": "Default"
}
]
var fakeData = [
{
"id": 0,
"name": "Mayer Leonard",
"city": "Kapowsin",
"state": "Hawaii",
"country": "United Kingdom",
"company": "Ovolo",
"favoriteNumber": 7
},
{
"id": 1,
"name": "Koch Becker",
"city": "Johnsonburg",
"state": "New Jersey",
"country": "Madagascar",
"company": "Eventage",
"favoriteNumber": 2
},
{
"id": 2,
"name": "Lowery Hopkins",
"city": "Blanco",
"state": "Arizona",
"country": "Ukraine",
"company": "Comtext",
"favoriteNumber": 3
},
];
ReactDOM.render(<RootFrame UrlPost={'Home/SaveData'}/>,
document.getElementById("demoForm"));
Essentially, I am trying to select a row, at the same time be able to change the name and click submit.
Selected row from grid
From the "Name" field, user can change the name.
Your input doesnt work because you are setting a static value this.props.Name for the input. In order to edit your input and still set the initial value with this.props.Name you should make use of state
class NameForm extends React.Component {
constructor(props) {
super(props);
this.state = { formName : '', inputName: ''}
this.handleFormName = this.handleFormName.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
componentDidMount() {
this.setState({inputName: this.props.Name});
}
handleFormName(e) {
console.log(e.target.value);
this.setState({ formName: e.target.value });
}
handleSubmit(event) {
console.log(this.state.formName);
this.setState({inputName: event.target.value});
axios.post(this.props.UrlPost, { FirstName: this.state.formName })
.then(function (response) {
});
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Name:
<input type="text" value={this.state.inputName} onChange={this.handleFormName.bind(this)} />
</label>
<input type="submit" value="Submit" />
</form>
);
}
}