agriboz agriboz - 7 months ago 10
Javascript Question

React iteration current this

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

Answer

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!