How to properly include JS files per page

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!

1 Like

[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

@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?

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

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.

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

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

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

Hi @adestefano

Would you please guide me, how to fix this problem, as I am experiencing the same problem.

You can do one of two things:

  1. I always start my pages with a fw7 pagemounted event listener. In the callback function to these types of events I name a page parameter. When I try to reference any element on the page, instead of looking directly for the element with a standard selector, I do the page parameter.the actual page element.find("…") to find the element.

fw7.on(“pageMounted”, function(page) {

page.$el.find(“some element by id, name, etc.”)

})

  1. As @plpl also suggested, you can adjust the application settings to not keep previous pages in memory, as this is what causes the problem. He suggested the stackPages and keepAlive attributes. I had not tried these so I don’t know how they will work.

I have some problem as you, I wanna use specifics file js in every page on my app cause every single page difference need, like compass.js, quiz.js
but, I don’t use fw7. before, I wanna ask the questions.
Is need import library or npm install to use fw7, coz I wanna use it too?

Thanks