Click on Tab return to tab page

Hi there!

I have the Tab Template with 4 tabs, they are each loaded into the view with js exactly like in the Tab Template. On the second tab I have a list. A click on a item navigates to the item page while tabs are still visible. Now I want to click on the tab icon and return to the first tab page, but I can only do so by clicking the back link in the left corner. How can I do that?

Question: Why are all 4 Tabs active (.tab-active)?

Thank you in advance!

This shouldn’t happen, there is some issue in your code i guess.

You need to do it manually by adding custom click handler to these tab links, and calling router.back('/path-to-tabs-home-page/', { force: true }) on appropriate View

@nolimits4web

Thank you for the answer! This is the remaining problem:
When I click the tab-link, it should only navigate to the first tab page if this tab was active before the click. This should prevent when being on another tab and going back to this tab, you should have to do an extra click to go to the first tab page. How can I do that?

I tried with an onclick on the tab link and then checking if “.tab-active” class is available at this tab, but the onclick is too slow, the tab-active class is always available.

Then before calling back() on that router you need to check it is history length view.router.history.length. If it is 1 then it is on root page

@nolimits4web

Thanks for your answer! I need to detect the following difference in the 4 Tab App:

  1. I’m on View2 and clicking the tab-icon of View2 (the view doesn’t change, because it is already active)
    VS
  2. I’m on View4 and clicking the tab-icon of View2 (and there for changing the view to View2)

I can’t detect the difference by the onclick handler of the View2-tab-icon because the Class “page-current” is there so fast when changing views

Hi @tobi! I did like to achieve the same result as you describe: when app-tab is clicked twice, return to tab homepage. (Like for example in Facebook app) I wrote the event handler below to accomplish this, because indeed you can’t determine if the clicked tab already was the current active one because the Framework7 handler is run earlier.

@nolimits4web Maybe a feature suggestion for an extra tab event that could be triggered in such case: tab:alreadyactive / tabAlreadyActive Although I’m sure it should be a little smarter.

Remember to adjust below code: modify ‘#app’ to your app root element, and modify ‘f7app’ to your app instance.

// Save first tab as currently active on initialization
window.current_tab = $('#app > .views > .toolbar .tab-link:first').attr('href');

$(document).on('click', '#app > .views > .toolbar .tab-link', function() {

  var tab = $(this).attr('href');

  if (window.current_tab === tab) {

      var view = f7app.views.get( $(this).attr('href') );

      if (view.history.length > 1) {

          var route = view.history[0];
          view.router.back(route, {
            force: true
          });

      }

  }

  window.current_tab = tab;

});

PS. I know putting a global window var is not best practise, but couldn’t come up with something better atm :slight_smile:

Thank you @Tim!
Yes I agree there should be an extra event! Would appreciate is very much @nolimits4web!

It can be done a bit easier:

$('#app > .views > .view.tab').on('tab:show', function (e) {
  var tabEl = this;
  var router = app.views.get(tabEl).router;
  if (router.history.length > 1) {
    router.back(router.history[0], { force: true })
  }
});

@nolimits4web This doesn’t work the way we mean I think. The event tab:show only fires once when a tab is made visible, and is not fired again when the tab link is clicked repeatedly with the tab already visible. (And that’s OK) But that’s why I had wired up the event handler on the tab link.

I’ve got another strange problem with router.back using force:true. If there are only two pages in history, like this:

And then calling view.router.back(’/’, { force: true}), the back animation is OK, but the ‘page-previous’ stays in history and is never removed from DOM. If there are three or more pages in history and ‘stacked’ class comes in, then router.back works as expected and removes both ‘page-previous’ from DOM.

Is this expected behavior and should I work around or can be considered a bug?

Right, then your code is correct, and can be modified a bit to not use global var like:

$(document).on('click', '#app > .views > .toolbar .tab-link', function() {
  var $viewEl = $($(this).attr('href'));
  if ($viewEl.hasClass('tab-active')) {
      var view = f7app.views.get( $viewEl );
      if (view.history.length > 1) {
        view.router.back(view.history[0], {
          force: true
        });
      }
  }
});

I see you use stacked pages, in this case you should go back to root like:

router.back({pageName: 'panels.events'}, { force: true })

Hi all, I am trying to achieve the same thing and have tried the code above by @nolimits4web however, It immediately returns to the root page on the very first click. My idea is to allow the user to return to the tab wherever they may have left it as per the usual implementation of the tabbed view but to have the ability to return to the root page only if the tab is already in view and the user clicks on the tab again.

I understand this is what the tab-active check is looking for but that class is being added straight away as I click on the tab.

I have put this code into app.js

$$(document).on(‘click’, ‘#app > .views > .toolbar .tab-link’, function() {
var $viewEl = $$($$(this).attr(‘href’));

if ($viewEl.hasClass(‘tab-active’)) {
var view = app.views.get( $viewEl );
console.log($viewEl);
if (view.history.length > 1) {
view.router.back(view.history[0], {
force: true
});
}
}
});

Are there any updates in regards to this, I am experiencing the same issue as @Haidar

I almost found a solution (I use it in my app.vue, in mounted() event)

  // Clicking again a tab already selected move it back to first page
  const $ = this.$$;
  const app = this.$f7;
  let lastTab = $('#framework7-root > .views > .toolbar .tab-link.tab-link-active').attr('data-tab');
  $(document).on('click', '#framework7-root > .views > .toolbar .tab-link.tab-link-active', function () {
    const currentTab = $(this).attr('data-tab');
    if (currentTab === lastTab) {
      const $viewEl = $(currentTab);
      const view = app.views.get($viewEl);
      if (view.history.length > 1) {
        view.router.back(view.history[0], {
          force: true,
        });
      }
    }
    lastTab = currentTab;
  });

It works well, except for a tab with a list-index.
If I go to this tab, then select a page in the list, then go back to the list by clicking again the already selected tab, then move to another tab, then move back to this tab, I have an error in the console and the index list does not scroll auto scroll when using the index (index labels still appear correctly though):

list-index-class.js:351 Uncaught TypeError: Cannot read property 'offsetHeight' of undefined
    at ListIndex.calcSize (list-index-class.js:351)
    at HTMLDivElement.handleResize (list-index-class.js:133)
    at HTMLDivElement.handleEvent (dom7.module.js:407)
    at Dom7.trigger (dom7.module.js:569)
    at Framework7.show (tabs.js:145)
    at Framework7.tabLinkClick (tabs.js:264)
    at eval (clicks.js:42)
    at Array.forEach (<anonymous>)
    at eval (clicks.js:38)
    at Array.forEach (<anonymous>)

EDIT : I partially reproduced my issue!
https://jsfiddle.net/s69kmjwr/1/

  1. Go to tab B
  2. Navigate as deep as you want with the links
  3. Click tab B again: you move back to page B in tab B
  4. Go to tab A
  5. Go back to tab B

Look into the console: the error shared below appears.

Note that on my real app, in addition to the error appearing in the console, the “auto scroll” when swiping over the index stops working. But I tested to replace my dynamic datas by static datas, and I then observe the same result than the jsfiddle: everything seems to work, except for the error in the console.


EDIT : I found a solution ; it’s auto init that was failing.
https://jsfiddle.net/f1c4kq7L/

Strange enough, I discovered that the bug was not affecting iOS… so it’s perhaps something specific to Chrome, but I do not know exactly what. Anyway, now, it works. There is perhaps something that should be corrected inside Framework7, so I will open a bug ticket, just in case.