1

actually i am trying to create a popup which allow user to see expanded view inside the popup when user click on expand view for the particular element there are series of more then one element

Requirment:-the issue is that there are multiple elements, and whenever you click on the element, it should open inside the popup. u can think of it like there is a grid of contacts whenever u click on any of the contact it should be viewed in a popup

my current Approch :-

when user click on the element, i am saving the element refrence to the variable and trying to pass the refrence as children props

but getting error

suggestion for diffrent approch are welcomed.

thanks in advance

import React from "react";

const Summary = () => {

  const [expand, SetExpand] = useState<boolean>(false);
  const expendRef = useRef<HTMLDivElement>(null);

  return <div >
    {expand && <><span>hello</span> {
    }<Popup show={expand}>
      {expendRef.current?.parentNode }
    </Popup></>}
     <div ref={expendRef} className='summary-table col-md-6' onClick={()=>SetExpand(!expand)>
             Reference element
     </div>
   </div>
        
}


const Popup=(props)=>{
render(<>
<h1>Popup Element</h1>
<div>{props.children}</props>
<>)

}

export default Summary
  • assigning a [ref](https://reactjs.org/docs/refs-and-the-dom.html#accessing-refs) in this way returns the underlying HTML element and not jsx so you can't pass it directly as a child – pilchard Nov 30 '22 at 13:28
  • 1
    you could just pass the actual element as a child instead of passing the ref to the element ` {YOUR_ELEMENT} ` – Xiduzo Nov 30 '22 at 13:29
  • hi @Xiduzo , the issue is that there are multiple elements, and whenever you click on the element, it should open inside the popup. u can think of it like there is a grid of contacts whenever u click on any of the contact it should be viewed in a popup – Anurag Sharma Nov 30 '22 at 13:36
  • please update your question accordingly so we can understand the question better and try and help better – Xiduzo Nov 30 '22 at 16:45

3 Answers3

1

Your idea was really creative and interesting, to put the div inside the popup. I think i did the way you want, but it's a little hacky, i had to create a DOMElement with an append child, weird solution... it would be something like this:

import React, { useEffect, useRef, useState } from "react";

const Summary = () => {
  const [popupVisible, setPopupVisible] = useState<boolean>(false);
  const [element, setElement] = useState() as any;

  const showElementOnPopUp = (e: any) => {
    if (!popupVisible) setPopupVisible(true);
    const elementClone = e.currentTarget.cloneNode(true);
    elementClone.querySelector("div").style.display = "block";
    setElement(elementClone);
  };

  return (
    <div>
      <div className="summary-table col-md-6" onClick={showElementOnPopUp}>
        Contact 1
        <div style={{ display: "none" }}>
          <p>Number: 111111</p>
          <p>Address: House 1</p>
        </div>
      </div>

      <div className="summary-table col-md-6" onClick={showElementOnPopUp}>
        Contact 2
        <div style={{ display: "none" }}>
          <p>Number: 222222</p>
          <p>Address: House 2</p>
        </div>
      </div>

      <div className="summary-table col-md-6" onClick={showElementOnPopUp}>
        Contact 3
        <div style={{ display: "none" }}>
          <p>Number: 333333</p>
          <p>Address: House 3</p>
        </div>
      </div>

      {popupVisible && (
        <Popup element={element} setPopupVisible={setPopupVisible}></Popup>
      )}
    </div>
  );
};

const Popup = (props: any) => {
  const { element, setPopupVisible } = props;

  return (
    <>
      <h1>Popup Element</h1>
      <div>
        <DOMElementContainer element={element} />
      </div>
      <button
        onClick={() => {
          setPopupVisible(false);
        }}
      >
        Close Popup
      </button>
    </>
  );
};

const DOMElementContainer = ({ element }: any) => {
  const ref = useRef() as any;

  useEffect(() => {
    if (!element) return;
    ref.current.innerHTML = "";
    ref.current.appendChild(element);
  }, [element]);

  return <div ref={ref}></div>;
};

export default Summary;

But i think a better approach would be this one, that better uses react state, and is more real, where you would get the list of contacts from some api:

import React, { useEffect, useRef, useState } from "react";

const Summary = () => {
  const [popupVisible, setPopupVisible] = useState<boolean>(false);
  const [contactList, setContactList] = useState() as any;
  const [contactInfo, setContactInfo] = useState() as any;

  const someApiCall = () => {
    return Promise.resolve([
      { name: "Contact 1", number: "11111", address: "House 1" },
      { name: "Contact 2", number: "222222", address: "House 2" },
      { name: "Contact 3", number: "333333", address: "House 3" },
    ]);
  };

  useEffect(() => {
    someApiCall().then((data) => {
      console.log(data);

      setContactList(data);
    });
  }, []);

  return (
    <div>
      {contactList?.map((contact: any) => {
        return (
          <div
            onClick={() => {
              setContactInfo(contact);
              setPopupVisible(true);
            }}
          >
            {contact.name}
          </div>
        );
      })}

      {popupVisible && (
        <Popup
          contactInfo={contactInfo}
          setPopupVisible={setPopupVisible}
        ></Popup>
      )}
    </div>
  );
};

const Popup = (props: any) => {
  const { contactInfo, setPopupVisible } = props;

  return (
    <>
      <h1>Popup Element</h1>
      <div>
        <p>Name: {contactInfo.name}</p>
        <p>Number: {contactInfo.number}</p>
        <p>Address: {contactInfo.address}</p>
      </div>
      <button
        onClick={() => {
          setPopupVisible(false);
        }}
      >
        Close Popup
      </button>
    </>
  );
};

export default Summary;
Paulo Fernando
  • 3,148
  • 3
  • 5
  • 21
1

What you want to do is an interesting feature, but I'm sure that you can do it following the React patterns and re-using Components. With that said I will try to answer your question in a simple way.

The answer to your question:

const Summary = () => {
  const [expand, setExpand] = useState(false)
  const expendRef = useRef(null)

  return (
    <div>
      {expand && (
        <>
          <span>hello</span>
          <Popup show={expand} element={expendRef} />
        </>
      )}
      <div 
         ref={expendRef} 
         className="summary-table col-md-6" 
         onClick={() => setExpand(!expand)}
      >
        {'Reference element'}
      </div>
    </div>
  )
}

const Popup = (props) => {
  return (
    <>
      <h1>Popup Element</h1>
      <div dangerouslySetInnerHTML={{ __html: props.element.current.outerHTML }} style={{ background: 'red' }} />
     {/* Background red is just to do it obvious, when its render */}
    </>
  )
}

How it works?

By default, React escapes the HTML to cross-site scripting, BUT if you really want to render some HTML, you can use the dangerouslySetInnerHTML property. Then you can take the HTML of your reference, doing .current.outerHTML

Code Example

https://codepen.io/FMadoery/pen/VwdGqwM

0

You can't do this with ref !

You can do it like as :

import React from "react";

const Summary = () => {

   const [expand, SetExpand] = useState<boolean>(false);

   const renderContent = () => (
      <div ref={expendRef} className='summary-table col-md-6' onClick={()=>SetExpand(!expand)>
         Reference element
      </div>
   )

   return (
      <div >
         {expand && <><span>hello</span>
         <Popup show={expand}>
            {renderContent()}
         </Popup></>}
         {renderContent()}
      </div>       
}

export default Summary;
Amr Eraky
  • 1,423
  • 7
  • 13
  • hi @Amr Eraky , the issue is that there are multiple elements, and whenever you click on the element, it should open inside the popup. u can think of it like there is a grid of contacts whenever u click on any of the contact it should be viewed in a popup – Anurag Sharma Nov 30 '22 at 13:42