0

I have a web project with a menu item that needs to call a page, cusomers.php and a javascript function associated with the menu selection. I have chosen to use pure javascript as opposed to jquery. The menu piece is located in include/adminheader.php and looks like this:

               <li><a href="#">View</a>
                    <ul>
                       <li><a id="allCustomers" value="all" href="customers.php" >
                            All Customers</a></li>
                       <li><a href="customers.php" id="singleCustomer" value="single" >
                            Single Customer</a></li>
               </li>

When the event listener is setup in the external file with ‘onload’:

window.onload = function() {
    document.getElementById("allCustomers").addEventListener("click", getCustomers);
    document.getElementById("singleCustomer").addEventListener("click", viewCustomer);
}

The event listener is registered and the js function fires with one click, but the page link isn’t followed (i.e. if I’m in the index page when I click menu link to ‘All Customers’ I’m still on index.php after the menu click).

When I setup the same code at the bottom of customers.php the menu link takes me to customers.php but I have to click the link twice the first time, once thereafter to call the js function.

I have also tried adding the listener to the surrounding <li> tag to call the js function and had to click twice the first time for it to fire.

I have read the MDN reference here: https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener, and the information https://www.w3.org/TR/DOM-Level-3-Events/#event-flow, and of course many stack overflow entries to try to understand how to fix this but am still lost.

I have seen similar questions regarding a js function having to be clicked twice the first time and this was fixed with the onload, but never in conjunction with a link to another page (instead of a href="#"). I’m wondering if this might have something to do with capture but couldn’t figure that out. I realize that I probably should have been able to recognize that another question addresses my problem but if I saw it I did not recognize how to apply to my situration. Please help.

EDIT - js code added need to navigate to page prior to function call

function getCustomers() {
    event.preventDefault();
    grid.innerHTML = "";
    outputTable.innerHTML = "";
    
    grid.className = "grid_4cols";
    var ajax = new XMLHttpRequest();
    ajax.open("GET", "../controller/admincontroller.php?getCustomers=all", true);
    ajax.send();    
    ajax.onreadystatechange = function() {
        if (ajax.readyState == 4 && ajax.status == 200) {           
            var arr = JSON.parse(ajax.responseText);
            var result = "";
            for (var i = 0; i < arr.length; i++) {  
                result += "<form action='../controller/admincontroller.php' method='POST' >";
                result += "<input type='hidden' id='id' name='id' value ='" + arr[i]['ID'] + "'>" ;
                result += "<input type='text' name='fname' value='" + arr[i]['fname'] + "'>" ;
                result += "<input type='text' name='lname' value='" + arr[i]['lname'] + "'>";
                result += "<input type='text' name='email' value='" + arr[i]['email'] + "'>";
                result += "<input type='submit' name='selectCustomer' value='Select' ></form>";
            }
            
            grid.innerHTML = result;

        }
    };
        
}

//not implemented. Not sure how to setup so destination DOM is 
//loaded before function call to getCustomers() or viewCustomer()
function goToCustomers() {

    location.assign("customers.php"); //used location.replace for first edit
    
}
bethm
  • 1
  • 10
  • If you navigate to a new page, you're current page will no longer be in memory and therefore you can't call functions on it. You can call a function first and then (within that function) cause navigation to happen after). – Scott Marcus Jul 01 '20 at 17:48
  • Ok thanks. I considered that but it seemed 'hacky', but that's probably my inexperience. When I tried it just now I put my ```function goToCustomers()``` at the end of the other function. The output flashes and goes away even with ```event.preventDefault()```. Any suggestions? – bethm Jul 01 '20 at 18:09
  • You'd have to show that code so we can see exactly what you are doing and when. – Scott Marcus Jul 01 '20 at 18:11
  • Alright- I've edited that question. I **really** appreciate the guidance. BTW I tried putting the page function call at the top as well with the same results- function flash-then-goes away. – bethm Jul 01 '20 at 18:22
  • The `event.preventDefault()` in your `goToCustomers()` page is not going to do anything because that function is not an event handler, so there's no event to prevent the default action of. But I think you might still be missing the point. There's no reason to update the current page if all you are going to do is navigate away from it. Also, your `goToCustomers()` function is getting called as soon as your `getCustomers()` function is invoked and before your AJAX call returns because you have that statement outside of the `readystatechange` callback. – Scott Marcus Jul 01 '20 at 18:25
  • @ScotMarcus "There's no reason to update the current page if all you are going to do is navigate away from it." not sure what this means. Also, my goToCustomers() is right before the getCustomers() closing ```}```. and it makes sense that I dont' need the preventDefault() inside the page call funciton. – bethm Jul 01 '20 at 18:41
  • In your `goToCustomers()` function, you set up, configure and make an AJAX call (by the way the `readystatechange` handler should be set up prior to the `send` call). But AJAX is asynchronous, so while that goes off an happens, the main thread continues to run the `goToCustomer()` function where it finds your call to `getCustomers()`, so that is executed BEFORE the results of your AJAX call can be handled. Therefore, you navigate away from your page before the `readystatechange` handler runs. This is the source of your problem. I don't think you understand the nature of AJAX processing. – Scott Marcus Jul 01 '20 at 18:46
  • So, you need to decide between staying on the page and receiving the results of the AJAX call and update the page with that or navigate away and don't bother updating the page. But doing both makes no sense. – Scott Marcus Jul 01 '20 at 18:48
  • It shouldn't go anywhere. Read my prior comment. If you are updating the current page, why navigate away from it? You are trying to do two diametrically opposed things. It's like you are going to a restaurant, sitting down and ordering, and then getting up and leaving before the food comes. – Scott Marcus Jul 01 '20 at 18:50
  • Nope, when I am on index.php and click on the menu link to customers (and a call to getCustomers() 'on' the customers.php page) I need to go to customers.php. Does that make sense? – bethm Jul 01 '20 at 18:56
  • Then move your AJAX call to the second page. Doing both on the same page makes no sense. – Scott Marcus Jul 01 '20 at 18:58
  • Please look at my html code- two different ajax calls depending on which link is pressed. I'm sorry for being so dense. should you move us to 'chat'? I don't have a rating to do that. – bethm Jul 01 '20 at 19:00
  • All I need to see is in `getCustomers()`. That function does two things 1) makes an ajax call and updates the current page grid with the results of that call and 2) navigates away from the current page. And, #2 actually happens first. If you navigate away from the page, why bother making an AJAX call to update it? – Scott Marcus Jul 01 '20 at 19:02
  • OK but I need to get to the page and depending on the id of the tag call viewCustomer() or getCustomers(). I tried putting the event listener for the menu click at the bottom of customers.php (with the customers.php link in the menu), and understandably had to click the link twice the first time to get the function to fire. – bethm Jul 01 '20 at 19:13
  • Navigation is fine. Updating the current page is fine. But both together is not. Decide which you need and remove the other. – Scott Marcus Jul 01 '20 at 19:21

1 Answers1

0
  1. add a query string to the href that represents the function that you want to invoke
<li><a href="#">View</a>
  <ul>
     <li><a id="allCustomers" value="all" href="customers.php?getCustomers" >All Customers</a></li>
     <li><a href="customers.php?viewCustomer" id="singleCustomer" value="single" >Single Customer</a></li>
  </ul>
</li>
  1. on window load, check to see if the window.location.href has a specific string
  2. invoke the desired function
    window.onload = function() {
      if(window.location.href.includes('?getCustomers') {
        getCustomers();
      }else if(window.location.href.includes('?viewCustomer') {
        viewCustomer();
      }
    }
kenput3r
  • 229
  • 2
  • 9
  • Cool. Page navigation successful, but the function is still flashing on the page and disappearing. This is with the preventDefault() still inside the js function (in my quesion). – bethm Jul 01 '20 at 18:32
  • Your ajax function is asynchronous, meaning it gets invoked and doesn't finish before the page reloads. Unfortunately I didn't have any insight to that when originally posting the answer. Are you sure that you are supposed to navigate away from the current page after invoking ```getCustomers``` and ```viewCustomer```? – kenput3r Jul 01 '20 at 22:34
  • No, and I feel like an idiot for not seeing that the page was called after the function run in your example. I need to 1) navigate to the page and 2) call one of two functions depending on the menu link clicked. I was thinking if there was some way to micro-delay the function call until the customers page loaded I could avoid the 2-click issue. Maybe there is no way to do what I want… and should consider another design logic. – bethm Jul 02 '20 at 15:31
  • I found something here https://stackoverflow.com/questions/21518381/proper-way-to-wait-for-one-function-to-finish-before-continuing (scroll down), but at the moment can't envision how I could implement it. – bethm Jul 02 '20 at 15:43
  • Don'f feel like an idiot for asking questions on here. It takes putting yourself out there to get a help, and a lot of people are too afraid of being criticized to do it. Updated my answer to what I think it is that you are trying to do. – kenput3r Jul 03 '20 at 15:22
  • OK tried that but ran into the same problem with the DOM not loading before the function call. I'm still working on an answer. I might just use php w/out JS – bethm Jul 04 '20 at 17:58
  • Yes the DOM will load before the function call because it is in a window.load function. Typically you want the DOM to load before you start interacting with it. – kenput3r Jul 04 '20 at 18:20