skip to Main Content

I want to return the following function if the user clicks a children of the anchor:

<a href="/product/product-id">
I am a product
  <div>
    Add to favorites
   </div>
</a>
const handleClick = (event) =>{
  console.log(event);
  
  // true -> if i click any of its children aka. the add to favorites
  if(true){
    event.preventDefault();
    return;
  }
  
  // Route is about to change
  NProgress.start();
}

document.addEventListener('click', handleClick);

How can i do such thing?

Edit 1:

This is my react.js/next13/next14 code:

'use client';

export default function NextNProgress() {
    useEffect(() => {
        NProgress.configure();

        function isAnchorOfCurrentUrl(currentUrl: string, newUrl: string) {
            const currentUrlObj = new URL(currentUrl);
            const newUrlObj = new URL(newUrl);
            // Compare hostname, pathname, and search parameters
            if (
                currentUrlObj.hostname === newUrlObj.hostname &&
                currentUrlObj.pathname === newUrlObj.pathname &&
                currentUrlObj.search === newUrlObj.search
            ) {
                // Check if the new URL is just an anchor of the current URL page
                const currentHash = currentUrlObj.hash;
                const newHash = newUrlObj.hash;
                return (
                    currentHash !== newHash &&
                    currentUrlObj.href.replace(currentHash, '') === newUrlObj.href.replace(newHash, '')
                );
            }
            return false;
        }

        const htmlElements = document.querySelectorAll('html');

        function findClosestAnchor(element: HTMLElement | null): HTMLAnchorElement | null {
            while (element && element.tagName.toLowerCase() !== 'a') {
                element = element.parentElement;
            }
            return element as HTMLAnchorElement;
        }

        function handleClick(event: MouseEvent) {
            try {
                const target = event.target as HTMLElement;
                const anchor = findClosestAnchor(target);
                const newUrl = anchor?.href;
                if (newUrl) {
                    const currentUrl = window.location.href;
                    // const newUrl = (anchor as HTMLAnchorElement).href;
                    const isExternalLink = (anchor as HTMLAnchorElement).target === '_blank';
                    const isBlob = newUrl.startsWith('blob:');
                    const isAnchor = isAnchorOfCurrentUrl(currentUrl, newUrl);
                    if (newUrl === currentUrl || isAnchor || isExternalLink || isBlob || event.ctrlKey) {
                        NProgress.start();
                        NProgress.done();
                        [].forEach.call(htmlElements, function (el: Element) {
                            el.classList.remove('nprogress-busy');
                        });
                    } else {
                        NProgress.start();
                        (function (history) {
                            const pushState = history.pushState;
                            history.pushState = function () {
                                NProgress.done();
                                [].forEach.call(htmlElements, function (el: Element) {
                                    el.classList.remove('nprogress-busy');
                                });
                             
                                return pushState.apply(history, arguments as any);
                            };
                        })(window.history);
                    }
                }
            } catch (err) {
                NProgress.start();
                NProgress.done();
            }
        }

        // Add the global click event listener
        document.addEventListener('click', handleClick);

        return () => {
            document.removeEventListener('click', handleClick);
        };
    }, []);

    return styles;
}

For those who were asking why i tagged this as react/next… this is the code i hacked to work with nprogress library… I think next will soon add router events back but for the mean time this is what i have done so far…

2

Answers


  1. The easiest way of achieving your objective would be to add an event listener directly to the div inside the first a element:

    document.querySelector("a>div").addEventListener("click",ev=>{
      ev.preventDefault();
      console.log('take action on "Add to favorites"');
    });
    <a href="/product/product-id">
    I am a product
      <div>
    Add to favorites
       </div>
    </a>

    As there was nothing React specific in the question I provided the above answer for a page with Vanilla JavaScript. This is probably not "the React way" of doing things.

    If you want to work with the "global event handler" you can try the following:

    const handleClick = ev =>{
      console.log(ev.type);
      
      // In case the clicked element is a direct child of an A element:
      if(ev.target.closest("div").parentNode.tagName=="A"){
        console.log("Cart action ...");
        ev.preventDefault();
        return;
      }
      
      // Route is about to change
      // NProgress.start();
    }
    
    document.addEventListener('click', handleClick);
    <a href="/product/product-id">
    I am a product
      <div>
    Add to<br><br><span><b>favorites</b><img src="https://picsum.photos/200/300"></span>
       </div>
    </a>
    Login or Signup to reply.
  2. You can try using event.stopPropagation in your <div> element.

    Something like this:

    HTML

    <a href="/product/product-id">
      I am a product
      <div id="1" class="favorite-button">Add to favorites</div>
    </a>
    

    JS

    <script>
      const likeButtons = document.querySelector(".favorite-button");
    
    
      likeButtons.forEach((likeButton) => likeButton.addEventListener('click', (event) => {
        event.stopPropagation();
        event.preventDefault();
    
        // your rules here
      } ))
    </script>
    

    I hope helped you

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search