I am fetching questions using an API and displaying question with dynamic radio options like this
[
{
"id": "question01",
"question": "Which of the following profiles you belongs",
"multiple": false,
"options": [
{
"id": "option01",
"title": "Buyer"
},
{
"id": "option02",
"title": "Planner"
},
{
"id": "option03",
"title": "Merchandiser"
},
{
"id": "option04",
"title": "Designer"
},
{
"id": "option05",
"title": "Analyst"
}
]
},
{
"id": "question02",
"question": "Which of the following is your responsibility?",
"multiple": true,
"options": [
{
"id": "option02_1",
"title": "Planning"
},
{
"id": "option02_2",
"title": "Design"
},
{
"id": "option02_3",
"title": "Development"
},
{
"id": "option02_4",
"title": "Testing"
}
]
},
{
"id": "question03",
"question": "What’s your level of seniority in the organization?",
"multiple": false,
"options": [
{
"id": "option03_1",
"title": "Entry Level"
},
{
"id": "option03_2",
"title": "Mid Level"
},
{
"id": "option03_3",
"title": "Senior Level"
}
]
},
{
"id": "question04",
"question": "Do you work with charts and dashboards to make data-backed decisions? ",
"multiple": false,
"options": [
{
"id": "option04_1",
"title": "Yes"
},
{
"id": "option04_2",
"title": "No"
},
{
"id": "option04_3",
"title": "Others"
}
]
}
]
I am rendering questions with options like this
<div>
{
questions && questions.length > 0 &&
questions.map((question, index) => {
return (
<div key={question.id}>
<div className='row'>
<div className='col-1'>
<h2 className='questionTitle'>Q{index + 1}.</h2>
</div>
<div className='col-11 questionContainer'>
<h2 className='questionTitle'>{question.question}</h2>
</div>
</div>
</div>
<div className='optionsList'>
{
question.options && question.options.map((option, index) => {
return (
<div key={option.id} className="mb-3">
<div className='d-flex align-items-center'>
{
question.multiple ?
<div className="form-check">
<input className="form-check-input form-checkbox" type="checkbox" value={option.title} onChange={() => handleAnswerSelection(option, question.id, true)} id={option.id} />
<label className="form-check-label" htmlFor={option.id}>
{option.title}
</label>
</div>
:
<div className="form-check">
<input className="form-check-input"
type="radio"
name={question.id}
value={option.title}
onChange={() => handleAnswerSelection(option,question.id, false)}
id={option.id}
checked={answersList.length && answersList.filter(ans => ans.id === question.id) && answersList.filter(ans => ans.id === question.id)[0].values[0].title === option.title }
/>
<label className="form-check-label" htmlFor={option.id}>
{option.title}
</label>
</div>
}
</div>
</div>
)
})
}
</div>
and onChange i am handling selection like this
const handleAnswerSelection = (selectedOption, ques, hasMany) => {
if (hasMany) {
//
}
else {
const answer = {
"id": ques,
"values": [selectedOption]
}
if (answersList.length > 0 && answersList.find(ans => ans.id === ques)) {
const index = answersList.findIndex(answer => answer.id === ques);
if (index > -1) {
answersList[index].values = [selectedOption];
}
}
else {
setAnswersList([...answersList, answer]);
}
}
console.log(answersList);
}
but the problem is on changing option is not reflecting at the same time also radio button is not changing.
state variables are
const [answersList, setAnswersList] = useState([]);
please help what i am doing wrong what is the solution for this ? Thanks in advance
const handleAnswerSelection = (selectedOption, ques, hasMany) => {
if (hasMany) {
//
}
else {
const answer = {
"id": ques,
"values": [selectedOption]
}
if (answersList.length > 0 && answersList.find(ans => ans.id === ques)) {
const index = answersList.findIndex(answer => answer.id === ques);
if (index > -1) {
let newAnswersList = [...answersList];
newAnswersList[index].values = [selectedOption];
setAnswersList(newAnswersList);
}
}
else {
setAnswersList([...answersList, answer]);
}
}
console.log(answersList);
}
It will be worked.
You should update answersList value using setAnswersList function.
On the following statement, the answersList value is not changed.
answersList[index].values = [selectedOption];
Related
I'm developing an application in React.JS
I have the array:
array =
[
{
"id": 1,
"user": {
"id": 1,
"name": "user-1"
},
"date": "2021-01-10",
"hour": {
"id": 1,
"time": "09:30:00.000"
},
"duration": {
"id": 1,
"time": 30
},
"type": {
"id": 1,
"name": "type-1"
},
"prof": {
"id": 1,
"name": "prof-1"
},
},
{
"id": 2,
"user": {
"id": 2,
"name": "user-2"
},
"date": "2021-01-14",
"hour": {
"id": 2,
"time": "10:00:00.000"
},
"duration": {
"id": 1,
"time": 45
},
"type": {
"id": 1,
"name": "type-1"
},
"prof": {
"id": 1,
"name": "prof-1"
},
}
]
and:
hour =
[
{
"id": 1,
"time": "09:30:00.000"
},
{
"id": 2,
"time": "10:00:00.000"
},
{
"id": 3,
"time": "10:30:00.000"
}
]
I need to show in a select only the hours that are not available given the equality condition in prof and day.
To try to do this I tried with
{
array.map(item => {
if (item.prof.id === "1" && item.date === "2021-01-14"){
return (
hour.map(elem => {
if (elem.id != item.hour.id){
return <option value={elem.time.id}>{elem.hour.time}</option>
}
})
);
}
})
}
In short I need to show the available hours.
For the example case, it should only show as an option: 09:30:00.000 and 10:30:00.000, as available hours.
How can I do it, suggestions?
your code works perfectly with some little changes:
1. === Operation checks type and value, in this case, prof.id has number type and not equal to string 1.
2. value and text of the options component should be elem.id and elem.time.
const OptionCreator = () => {
const profBusyHours = array
.filter((item) => item.prof.id === 1 && item.date === "2021-01-14")
.map((item) => item.hour.id);
return hour
.filter((elem) => profBusyHours.includes(elem.id) === false)
.map((elem) => (
<option key={elem.id} value={elem.id}>
{elem.time}
</option>
));
};
I have an array. The elements in the array represent the menu elements. I want to create "breadcrumb" according to the menu item I selected. However, it provides errors dynamically after 3 depth while working.
// My Array
const menuArray = [{
"label": "Dashboard"
},
{
"label": "Products",
"items": [{
"label": "All Products"
},
{
"label": "New Product"
},
{
"label": "Product Categories"
}
]
},
{
"label": "Posts",
"items": [{
"label": "All Posts"
},
{
"label": "New Post"
},
{
"label": "Post Categories"
}
]
},
{
"label": "Sliders"
},
{
"label": "Settings",
"items": [{
"label": "General Settings"
},
{
"label": "User",
"items": [{
"label": "Your Profile"
},
{
"label": "Edit Profile"
}
]
},
{
"label": "Social Settings"
},
{
"label": "Link Settings"
}
]
}
];
// The function I experiment with
writeParent(event, arr) {
let ct = 0;
let found = false;
let parentsLine = [];
arr.some((e) => {
parentsLine = [];
let curr = e;
for (curr; curr.items != null; curr = curr.items[0]) {
if (event.label == curr.label) {
found = true;
return true;
}
parentsLine.push(curr.label);
}
if (event.label == curr.label) {
found = true;
return true;
}
});
if (found) {
return parentsLine;
} else {
return 'ERR: elm not found';
}
}
console.log(writeParent({
"label": "Edit Profile"
}, menuArray));
For example, if the element I selected is;
{
"label": "New Post"
}
I want to get;
[
{
"label": "Posts"
},
{
"label": "New Post"
}
]
or
if the element I selected is;
{
"label": "Edit Profile"
}
I want to get;
[
{
"label": "Settings"
},
{
"label": "User"
},
{
"label": "Edit Profile"
}
]
I didn't know how to find the parent of the selected element. How can I do that?
I've solved the problem.
menuArray = [{
"label": "Dashboard"
},
{
"label": "Products",
"items": [{
"label": "All Products"
},
{
"label": "New Product"
},
{
"label": "Product Categories"
}
]
},
{
"label": "Posts",
"items": [{
"label": "All Posts"
},
{
"label": "New Post"
},
{
"label": "Post Categories"
}
]
},
{
"label": "Sliders"
},
{
"label": "Settings",
"items": [{
"label": "General Settings"
},
{
"label": "User",
"items": [{
"label": "Your Profile"
},
{
"label": "Edit Profile"
}
]
},
{
"label": "Social Settings"
},
{
"label": "Link Settings"
}
]
}
];
function find(array, event) {
if (typeof array != 'undefined') {
for (let i = 0; i < array.length; i++) {
if (array[i].label == event.label) return [event.label];
let a = this.find(array[i].items, event);
if (a != null) {
a.unshift(array[i].label);
return a;
}
}
}
return null;
}
console.log(find(menuArray, { "label": "Edit Profile" }));
sorry but I dont understand well refs. I've been reading react doc but I dont know how create an array of refs and access a node when check item.
My idea is ref all Tree Nodes and when call onCheck access to current ref and change property checked to a different status to current item, his parent items and his child items using javascript using childNodes, parentNode, nextSibling and previousSibling.
onCheck = (checkedKeys, event) => {
how can get node checked??? it always returns last node
const node = this.myRef.current;
console.log(node)
}
componentDidMount() {
// I have to do something here???
}
render() {
const loop = (data) => {
return data.map((item) => {
if (item.children && item.children.length) {
return <TreeNode ref={this.myRef} title={item.name} key={item.key} checked={item.checked} >{loop(item.children)}</TreeNode>;
}
return (
<TreeNode ref={this.myRef} title={item.name} key={item.key} isLeaf={item.isLeaf} checked={item.checked} />
);
});
};
return (
<div className="draggable-container">
<Tree
// Expand
expandedKeys={this.state.expandedKeys}
onExpand={this.onExpand} autoExpandParent={this.state.autoExpandParent}
// Draggable
draggable
onDragStart={this.onDragStart}
onDragEnter={this.onDragEnter}
onDrop={this.onDrop}
// Select && Check
onSelect={this.onSelect}
checkable onCheck={this.onCheck} checkedKeys={this.state.checkedKeys} >
{ loop(this.state.treeData) }
</Tree>
</div>
);
}
Instead of using React.createRef, you can make use of ref callback like
constructor(props) {
super(props);
this.myRef = {};
}
onCheck = (checkedKeys, event) => {
how can get node checked??? it always returns last node
const checkedKey = // get the checkedKey here, if its a array, loop and use
const node = this.myRef[checkedKey];
console.log(node)
}
render() {
const loop = (data) => {
return data.map((item, index) => {
if (item.children && item.children.length) {
return <TreeNode ref={(ref) => this.myRef[key] = ref} title={item.name} key={item.key} checked={item.checked} >{loop(item.children)}</TreeNode>;
}
return (
<TreeNode ref={(ref) => this.myRef[key] = ref} title={item.name} key={item.key} isLeaf={item.isLeaf} checked={item.checked} />
);
});
};
return (
<div className="draggable-container">
<Tree
// Expand
expandedKeys={this.state.expandedKeys}
onExpand={this.onExpand} autoExpandParent={this.state.autoExpandParent}
// Draggable
draggable
onDragStart={this.onDragStart}
onDragEnter={this.onDragEnter}
onDrop={this.onDrop}
// Select && Check
onSelect={this.onSelect}
checkable onCheck={this.onCheck} checkedKeys={this.state.checkedKeys} >
{ loop(this.state.treeData) }
</Tree>
</div>
);
}
This is my solution, because I had to modify treeData:
onCheck = (checkedKeys, event) => {
// console.log(this.treeData);
const checkedKey = event.node.props.eventKey;
this.updateItemChecked(checkedKey);
this.setState({ checkedKeys: checkedKeys }, () => {
this.props.parentTree(this.treeData);
});
}
updateItemChecked = (key) => {
var result = getNodeByKey(key, this.treeData);
if (result.type.localeCompare('folder') !== 0) {
if (result.checked === true ) {
result.checked = false;
} else {
result.checked = true;
}
} else {
this.checkIfFolderHasItem(result);
}
}
checkIfFolderHasItem = (result) => {
if ( result.children && result.children.length > 0) {
result.children.forEach( (item) => {
if (item.type.localeCompare('folder') !== 0) {
this.updateItemChecked(item.key);
} else {
this.checkIfFolderHasItem(item);
}
});
}
}
// Expand
onExpand = (expandedKeys, event) => {
// console.log('onExpand', expandedKeys);
const checkedKey = event.node.props.eventKey;
this.updateFolderExpanded(checkedKey);
this.setState({ expandedKeys, autoExpandParent: false }, ()=> {
this.props.parentTree(this.treeData);
});
}
updateFolderExpanded = (key) => {
var result = getNodeByKey(key, this.treeData);
if (result.type.localeCompare('folder') === 0) {
if (result.expanded === true ) {
result.expanded = false;
} else {
result.expanded = true;
}
}
}
render() {
const loop = (data) => {
return data.map((item) => {
if (item.children && item.children.length) {
return <TreeNode title={item.name} key={item.key} checked={item.checked} >{loop(item.children)}</TreeNode>;
}
return (
<TreeNode title={item.name} key={item.key} isLeaf={item.isLeaf} checked={item.checked} />
);
});
};
return (
<div className="draggable-container">
{
// (this.state.showModal) ? <TreeModal show={this.state.showModal} info={this.state.selected} treeData={this.state.treeData} parentTreeModal={this.doParentTreeModal} /> : null
}
<Tree
// Expand
expandedKeys={this.state.expandedKeys}
onExpand={this.onExpand} autoExpandParent={this.state.autoExpandParent}
// Draggable
draggable
onDragStart={this.onDragStart}
onDragEnter={this.onDragEnter}
onDrop={this.onDrop}
// Select && Check
onSelect={this.onSelect}
checkable onCheck={this.onCheck} checkedKeys={this.state.checkedKeys} >
{ loop(this.state.treeData) }
</Tree>
</div>
);
}
JSON Example:
[
{
"name": "Capas1",
"key": "0-23",
"isLeaf": false,
"type": "folder",
"expanded": true,
"children": [{
"name": "sectores",
"key": "0-20",
"isLeaf": true,
"type": "layer",
"checked": true
},
{
"name": "distribucion",
"key": "0-22",
"isLeaf": true,
"type": "layer",
"checked": false
}]
},
{
"name": "Nueva Carpeta0",
"key": "0-624",
"isLeaf": false,
"type": "folder",
"expanded": false,
"checked": false
},
{
"name": "Nueva Carpeta1",
"key": "0-625",
"isLeaf": false,
"type": "folder",
"expanded": true,
"children": [{
"name": "Nueva Carpeta2",
"key": "0-629",
"isLeaf": false,
"type": "folder",
"expanded": true,
"children": [{
"name": "Nueva Carpeta3",
"key": "0-623",
"isLeaf": false,
"type": "folder",
"expanded": true,
"children": [{
"name": "distribucion33",
"key": "0-99",
"isLeaf": true,
"type": "layer",
"checked": true
}]
}]
}]
},
{
"name": "sectores1",
"key": "0-27",
"isLeaf": true,
"type": "layer",
"checked": true
},
{
"name": "sectores12",
"key": "0-89",
"isLeaf": true,
"type": "layer",
"checked": false
},
{
"name": "Capas 2",
"key": "0-588",
"isLeaf": false,
"type": "folder",
"expanded": false,
"children": [{
"name": "Capas 3",
"key": "0-589",
"isLeaf": false,
"type": "folder",
"expanded": false,
"children": [{
"name": "Prueba",
"key": "0-36",
"isLeaf": true,
"type": "layer",
"checked": false
}]
}]
}
]
The JSON backend guys provide me its multiple parent child so I have to put the dynamic loop to show parent child.
JSON
"data": [
{
"id": 25,
"slug": "mobiles",
"parent_id": null,
"name": "Mobiles"
},
{
"id": 26,
"slug": "mobile-phones-accessories",
"parent_id": 25,
"name": "Mobile Phones accessories"
},
{
"id": 27,
"slug": "computer-laptop",
"parent_id": null,
"name": "Computer & Laptop"
},
{
"id": 28,
"slug": "laptops",
"parent_id": 27,
"name": "Laptops"
},
{
"id": 29,
"slug": "mobile-phones",
"parent_id": 26,
"name": "Mobiles Phone"
}
]
My Function (Kindly ignore this. It's just a try but I have got 1 child parent)
renderCategoriesHtml() {
const { categories } = this.props;
if (!categories) return false;
const nullCat = [];
categories.map((obj) => {
if (obj.parent_id == null) {
nullCat.push(obj);
}
});
return nullCat.map(
(parentCat, i) => (
<div className="form-group" key={i}>
<div className="checkbox" key={i}>
<label>
<Field
name={`categories.${parentCat.id}`}
component="input"
type="checkbox"
/>
{parentCat.slug}
</label>
</div>
{
categories.map(
(childCat, j) => (
parentCat.id == childCat.parent_id ?
<div className="checkbox ml-20" key={j}>
<label>
<Field
name={`categories.${childCat.id}`}
component="input"
type="checkbox"
/>
{childCat.slug}
</label>
</div>
: ''
)
)
}
</div>
)
);
}
I want this (That dynamic html i want)
<ul>
<li>mobiles</li>
<ul>
<li>mobile-phones-accessories</li>
<ul>
<li>mobile-phones</li>
</ul>
</ul>
<li>computer-laptop</li>
<ul>
<li>laptops</li>
</ul>
</ul>
Try this:
class TreeRender extends React.Component {
state = {
data: JSON.parse('[{"id": 25,"slug": "mobiles","parent_id": null,"name": "Mobiles"},{"id": 26,"slug": "mobile-phones-accessories","parent_id": 25,"name": "Mobile Phones accessories"},{"id": 27,"slug": "computer-laptop","parent_id": null,"name": "Computer & Laptop"},{"id": 28,"slug": "laptops","parent_id": 27,"name": "Laptops"},{"id": 29,"slug": "mobile-phones","parent_id": 26,"name": "Mobiles Phone"}]')
}
getCurrent = (node) => this.state.data.filter(cNode => cNode.parent_id == node).map(cNode => (
<ul key={`node_${cNode.id}`}>
<li>{cNode.name}</li>
{this.getCurrent(cNode.id)}
</ul>
))
render() {
return (
<div>
{this.getCurrent(null)}
</div>
);
}
}
FIDDLE
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