Define page events in multiple files

Hi to all
i’m trying to define some page events like “onPageInit”.

I can’t bind events directly on router because doing so means to define all events in a single place (the router file)
I can’t use a global “pageInit” for the same reason: means to define all events in a single function like the following:

app.on('pageInit', function(page) {
    if ( page.name == '' )              onHomeInit(page);
    if ( page.name == 'order' )         onOrderInit(page);
});

What I would like to do is something like the following (assured that I’m using a different JS file for each page):

app.on('pageInit', 'pageName', function(page) {
   my callback
});

with this syntax, I’ll be able to put the same code in every JS file, because only events related to a single page a set.

Any help ?

With F7 v1 there was a similiar way:

App.onPageInit('index', function (page) {
    // your code
})

or something similar. It doesn’t work anymore in v2

You could do this:

File A

window.onHomeInit = function (page) { //code }

File B

app.on('pageInit', function(page) {
    if ( page.name == '' )              onHomeInit(page);
});

Just be sure to include File A before file B.

I’m not using just 2 files but about 18.
Doing in this way, the last call to

app.on('pageInit', function(page) {

will overwrite all previous one.

Currently, as workaround, i’m doing this:

$$(document).on('page:init', pageSelector, function (e) {
}

but with this I don’t have access to the page variable like using app.on('pageInit', function(page) { });

It doesn’t matter if you are using 2 oder 1.000 files - you can include as many as you want.

You can go the F7 way as well and append one route in each file:

app.routes.push({
    path: '/blog/',
    url: './pages/blog.html',
    on: {
        pageInit : function(page) { //do something }
    }
});

Great.
This should be added to official docs.

Any idea on how to trigger pageInit on the index page, without having to create a custom method ?

app.routes[0].emit('pageInit');

No, it won’t override, it is an event listener, you will just assign new one handler.

You have access to same page data:

$$(document).on('page:init', pageSelector, function (e) {
  var page = e.detail
}

app.routes[0].emit(‘pageInit’);

I wasn’t aware of this. Thanks.

So, using something of this

app.on(‘pageInit’, function(page) {
   if ( page.name == 'page1' ) { doCode1(); }
});

app.on(‘pageInit’, function(page) {
   if ( page.name == 'page2' ) { doCode2(); }
});

would call both pageInit every time, but , thanks to the “IF”, only one would be executed, based on page name, right ?

Let me try to explain what I’m trying to do, maybe you have some best-practise suggestions.

I’m building an app with multiple page. One page has it’s own JS code, in a dedicated file, in example:
/js/pages/page1.js
/js/pages/page2.js

Inside each page’s js I have a Closure used as “namespace”

(function () {
	app.routes.push({
	    path: '/page1/',
	    url: './pages/page1.html',
	    on: {
		pageInit : function(page) {
		   console.log('Page1 pageInit');
	 	}
	    }
	});

        othercode.......
})();

Now I have some Cordova plugins to use, all cordova plugins must be called after “deviceready”.
Calling them directly inside the closure would execute them immediatly.
Using $$(document).on('deviceready') would execute the code twice, one after device ready (regardless F7 initialization) and one after pageInit

So I was thinking about putting the whole closure inside a deviceready event, so that all F7 event binding would be set after Cordova device ready.

AFAIK, the whole F7 init() should be already in a Cordova deviceready, but doesn’t seem to work properly because plugin will break without using the proper deviceready event listener

No advice about this?

deviceready fires forEach time you call it (when/if the device is “ready”)
no matter where or when, forEach time.
even if you call it after a week, it will fire (after a week).
NOT only when the device is ready

not really sure what are you trying to do
assuming your plugin is “camera”

#1 scenario
Dom7(document).on('deviceready',function(e){
  console.log(navigator.camera);//=> return obj
});
var app=new Framework7({
  initOnDeviceReady:true, //true by default
  on:{
    init:function(){
      console.log(navigator.camera);//=> return obj
    }
  }
});
app.routes.push({
  path:'/page1/',
  url:'./pages/page1.html',
  on:{
    pageInit:function(page) {
      console.log(navigator.camera);//=> return obj
    }
  }
});
console.log(navigator.camera);//=> may return undefined
#2 scenario
Dom7(document).on('deviceready',function(e){
  console.log(navigator.camera);//=> return obj
});
var app=new Framework7({
  initOnDeviceReady:false,
  on:{
    init:function(){
      console.log(navigator.camera);//=> may return undefined
    }
  }
});
app.routes.push({
  path:'/page1/',
  url:'./pages/page1.html',
  on:{
    pageInit:function(page) {
      console.log(navigator.camera);//=> may return undefined
                                    //   probably not (too late)
                                    //   unless this is an initial-page-route
                                    //   or if you navigate immediately
                                    //   it may return undefined
    }
  }
});
console.log(navigator.camera);//=> may return undefined
1 Like

app.routes[0].emit(‘pageInit’);

This doesn’t work.

Uncaught TypeError: app.routes[0].emit is not a function
    at index.js:72

This is what I have now:

app.js:

// Framework7 App main instance
var app  = new Framework7({
  root: '#app', // App root element
  id: 'x', // App bundle ID
  name: 'y', // App name
  theme: 'auto', // Automatic theme detection,
  initOnDeviceReady: true,
  on: {
    init: function() {
      console.log('F7 init');
    }
  }
});

var mainView = app.views.create('.view-main');




index.js

(function() {
    console.log('Page index.js');
    var pageSelector = '.page[data-name="index"]';

    app.routes.push({
        path: '/',
        url: './index.html'
    });

    var pageInit = function() {
        console.log(navigator.camera);
        
        console.log('index pageInit method');
    }

    $$(document).on('page:init', pageSelector, function (e) {
        console.log('Triggering page:init on index');
        pageInit();
    });
});

it doesn’t work properly. There is a sort of “race condition” between cordova’s deviceready and F7 init.
This is what I can see in console:

Page index.js
device ready
F7 init
Triggering page:init on index
undefined
index pageInit method

undefined is coming from console.log(navigator.camera);. Cordova seems to be not ready yet when F7 is initialized

1 Like
$$(document).on('page:init', '.page[data-name="about"]', function (e) {
  // Do something here when page with data-name="about" attribute loaded and initialized
})

Is that something you are looking for?

I’m already using that, ad wrote in my sample code above

Then you can set init: false and init it when you need it:


var app = new Framework7({
  init: false;
});

$(document).on('deviceready', function (){
  // push routes and assign handlers
  
  // init app
  app.init()
});

As far as i know, f7 should init itself automatically in deviceready, right?

Yes and this is what you see in console

So, why Camera doesn’t work properly? It’s undefined, like when calling before deviceready