INFOSYS
INFOSYS

Reputation: 1585

How to add a dynamic Element to particular Html Node which is extracted from React ref?

I am using React to get hold of a element using ref callback when rendered on the browser and then transform this in case the child exceeds the parent, the content is not parsed by React but comes a API call so the parsing has to be manually.

Note - currently i am getting element this via react ref callback and trying to modifying via plain Js will it effect in case re rendering happens to the react component (if yes how can we do it in React) or if we modify DOM using plain JS is it fine ?

(function (e) {
            // how to add icon at the end of the image if the size of the image is greater then container            
         }})(window,document)
         
    const parent = element.getBoundingClientRect();
    const imgTags = element.querySelectorAll("img");
    imgTags.forEach(imgTag => {
      const imgBoundingRect = imgTag.getBoundingClientRect();
      if (imgBoundingRect.width > parent.width) {
        const parent = imgTag.parentNode;
        const wrapper = document.createElement('div');
        wrapper.classList.add(styles.horizontalScroll);
        parent.replaceChild(wrapper, imgTag);
        wrapper.appendChild(imgTag);
      }
    });
.horizontalScroll {
  overflow-x: auto;
}

    But i am not sure how to add icon instead of scroll bar 
    to the node and then clicking on the icon moves it instead of scroll
<html>
   <body>
      <script>      
      </script>

      <div style="width: 10px;border: 1px solid red" >
            <p>Mine MIne;GGGG;8 If <img height="84px" src="https://encrypted-tbn0.gstatic.com/images?q=tbn%3AANd9GcQGnVCSgGcosHQqtLDK2s8ZdOaZxNcntg8vk2kHgygqP--Rbtdd&usqp=CAU" style="vertical-align:middle" width="510px"> then the value of </p>
         </div
   </body>
</html>

Looking for output like this enter image description here using just Plain JS when image is loaded i am not able to create Nodes on the Fly for images > parent width . I have been able to capture width and add overflow but how to add button to a node with styling.

Update : React code for getting the Ref

  <div dangerouslySetInnerHTML={createMarkup(myContent)} // this is a set of <p> tags which may or may not contain images inside which comes in via server. those images can sometime move out of view . due to no style prop attached
       className={classNames(styles.data, externalStyle)}
       ref={(input) => {
         if (input) {
           myJSFunction(input); // this is the Input
         }
       }}/> 

Upvotes: 3

Views: 504

Answers (1)

Rahul Singh
Rahul Singh

Reputation: 19640

We can try something like this add dynamic element in React context ..

export const overFlowIcon = (element) => {
  const oldId = element.querySelectorAll(‘#myID’); // add someId inside to icon and check may Be in case content re renders in React 
    setTimeout(() => {
      const pDiv = element.getBoundingClientRect();
      const imgTags = element.querySelectorAll("img");
      imgTags.forEach(imgTag => {
        const imdDiv = imgTag.getBoundingClientRect();
        if (imdDiv.width > pDiv.width) {
          const parent = imgTag.parentNode;
          parent.style.width = '100%';
          const cont = document.createElement('div');
          const wrap = document.createElement('div'); 
          cont.classList.add(‘stickycontainer');
          wrap.classList.add(‘horizontalScroll');
          container.appendChild(wrap);
          parent.replaceChild(container, imgTag); 
          wrap.appendChild(imgTag);
          const newE = document.createElement('span'); // creating icon
          newE.onclick = (event) => (element.scrollBy(100, 0); event.stopPropagation();)
          newE.classList.add(‘arrow'); // styling a problem can fix
          wrap.appendChild(newE);
        }
      });
    }, 0);
};
.stickycontainer
  position: relative;
}

.horizontalScroll {
  overflow-x: auto;
  display: flex;
}
.arrow {
  position: absolute;
  left: 80%;
  top: 50%;
  border: solid #000;
  border-width: 0 3px 3px 0;
  display: inline-block;
  padding: 3px;
  cursor: pointer;
  transform: rotate(-45deg);
  -webkit-transform: rotate(-45deg);
}

In this case we are making sure the element is in view and then do the transformation using JS, also to prevent the effect of Re render we can add id to any element and then if React Rerenders we can check the id if exists we prevent the whole method run altogether there by preventing the effect of re render / or can add a additional arg to the method.

Update Post adding of the React Ref, as the content comes in form of string you can may be use DOM parser to convert it to your format and back to string and then have the logic in React Context itself some thing like

export const horizontalOverflow = (content) => {
  const parser = new DOMParser();
  const doc = parser.parseFromString(content, 'text/html');
  const element=  doc.body;
  if (element) {
    const imgTags = element.querySelectorAll("img");
    imgTags.forEach(imgTag => {
      const parent = imgTag.parentNode;
      const wrapper = document.createElement('span');
      wrapper.classList.add(horizontalscrolling);

      parent.replaceChild(wrapper, imgTag);
      wrapper.appendChild(imgTag);
    });
  }
  return element.outerHTML;
};

Now you can use it to create Markup.

Upvotes: 2

Related Questions