How to properly include JS files per page


#1

Hi, I am experiencing a problem while using the router’s .back() function. When I call back it properly returns to the previous page in the history but it then runs all of the JS on that page more than once. Let’s say I am on page 1, navigate forwards to page 2, and the forwards to page 3. From page 3 I go back to page 2. The JS on page 2 runs twice. If I go back to page 1 the JS runs 3 times. By “runs” I mean things like: handlers get attached multiple times, when handler code is executed it runs mulitple times, etc.

I have one index.js file which contains some common code and sets things like the Framework7 material (router and initializes app, etc.) and then a JS page with code specifically for each other page of my application. SO, my JS directory looks like this:

index.js
page1.js
page2.js

If I am on page 2, I only want the “common” JS and the page specific JS to execute. So, for page 2 that would be index.js and page2.js. I don’t want to worry about code for page 1 or page N running when I am not on those pages. I could put all the JS in one file but that would be too messy and doesn’t solve what I believe the problem actually is.

I have not built single page applications before, so this is a little new to me. I am not really certain on what the standard is when it comes to how you load JS and CSS files for each page in a SPA. I have tried the following to no avail:

I put the CSS and JS files in the page element:

index.html:

<body>
<div ip="appMain">
    <div class="view view-main">
    </div>
</div>
...End HTML

Other scripts like the framework7.min.js, etc.
<script src="js/index.js"></script>
</body>

page1.html:

<div class="page" data-name="login">
    ...HTML
    <script src="js/page1.js"></script>
</div>

This doesn’t work as none of the code is executed in page1.js.

I have ended up having to do this:

index.html:

<body>
<div id="appMain">
    <div class="view view-main">
    </div>
</div>
...End HTML

All script files are listed here
<script src="js/index.js"></script>
<script src="js/page1.js"></script>
</body>

page1.js:

fw7.on("pageBeforeIn", function() {
    if(mainView.router.currentRoute.name === "login") {
        //All of the code for page1 goes here
    }
});

This works but I have a very strong feeling the error I am experiencing is due to the “pageBeforeIn” being triggered after/during the back navigations because the page is in the history. Thinking this I tried:

index.html:

<body>
<div ip="appMain">
    <div class="view view-main">
    </div>
</div>
...End HTML

Other scripts like the framework7.min.js, etc.
<script src="js/index.js"></script>
</body>

page1.html:

<div class="page" data-name="login">
    ...HTML
    <script src="js/page1.js"></script>
</div>

page1.js:

if(mainView.router.currentRoute.name === "login") {
    //All of the code for page1 goes here
}

However, this doesn’t work either.

I have tried using other page events but they don’t work every time you end up on the page and I don’t really think it is correct to check for a whole bunch of different page events to determine when to trigger the page code. It seems that the .back() issues are due to how I am including and executing the JS files. What is the proper way for me to do this?

Sorry this is a long post, but I would prefer to be more detailed up-front.

Thanks!


#2

[pageBeforeIn,pageAfterIn]
run on every route (forward or back) to a page

use [pageInit] instead

the diff in ms (on my machine) is 0.010ms
nothing to worry about


#3

@plpl thanks for replying!

Unfortunately this hasn’t resolved the issue. I have also tried the page:mounted event and that doesn’t fix the issue either. A common symptom of this bug is dialogs. I have a dialog set to display when the user clicks a button:

$$("#cancelOrder").click(() => {
    const $$cancelOrderDialog = fw7.dialog.create({
        //set up the text, title, and buttons here
        buttons: [
            {text: "yes", close: true, //click handler},
            {text: "no", close: true}
        ]
    });

    $$cancelOrderDialog.open();
})

Let’s call this page 1. If I go to page 2 and then use .back() to return to page 1 and then click on the cancel order button, the dialog appears once, and once I click on either button it displays again. Do I need to un-register all of the handlers when the page is transitioning out, or can I do something with the router itself such as remove caching or something?


#4

if the dialog appears twice :
you definitely register it twice

post your real code

yes:
that is because the core allow only one dialog at a time
as soon as you close the first one, the second dialog pops up


#5
fw7.on("pageMounted", function() {
    if (mainView.router.currentRoute.name === "drawOrder") {


        $$("#cancelOrder").click(() => {
            const $$cancelOrderDialog = fw7.dialog.create({
                title: "Cancel Order?",
                text: "The patient/order will remain on the work list but any changes you've made will not be saved.",
                buttons: [
                    {
                        text: "Yes",
                        close: true,
                        onClick: function(dialog, e) {
                            const canceledOrder = deleteOrderFromCache(orderObj.order.reqNumber);
                            canceledOrder.then(() => {
                                mainView.router.back();
                                fw7.toast.create({
                                    text: "Order has been reset."
                                });
                            }).catch((error) => {
                                console.log(error);
                            });
                        }
                    },
                    {
                        text: "No",
                        close: true
                    }
                ]
            });

            $$cancelOrderDialog.open();
        });
    }
});

This is the actual code of the dialog. I have tried with other page events but they all have the same issue.


#6

look like your stackPages is : false
make it “true”, otherwise the pageMounted event
will get fire (again,like first-time) when you click back on the 3th page

if you want to keep stackPages -> false :
make it like this:

fw7.on('pageMounted',function(p){
  p.$el.find('.my-class').click(() => {
    console.log('click')
  });
});

and you engine will GC the prev element
otherwise the prev element (+ attached events) still exist in memory
and will get fire again and agian

also:
try to avoid id’s as much is possible


#7

also from 3.6.0
you have “keepAlive : true”
this make the mounted “lc” to run only once

did not test it yet
but it should work only for compoPage


#8

Yes, thank you very much! Using the reference to the page with page event parameter has resolved the problem.