0

I have a well-known problem of the iPhone users with my current website. I have two tabs allowing my users to switch between two weeks:

<ul class="nav nav-tabs justify-content-center" id="myTab" role="tablist">
  <li class="nav-item">
    <a class="nav-link active" id="home-tab" data-toggle="tab" href="#currentWeekTab" role="tab" aria-controls="home" aria-selected="true" >
      {{{weekInterval 1}}}
    </a>
  </li>
  <li class="nav-item">
    <a class="nav-link" id="profile-tab" data-toggle="tab" href="#nextWeekTab" role="tab" aria-controls="profile" aria-selected="false" >
      {{{weekInterval 0}}}
    </a>
  </li>
</ul>

My problem is that my iPhone users need to click twice to actually change the tab. I read that the problem was coming from the hover but no answer fixed my problem.

How can I allow my customers using iPhone to change tab with just one click? Thanks in advance.

Virthuss
  • 3,142
  • 1
  • 21
  • 39

1 Answers1

1

You can let Blaze solve your problem by listening to the "click, touchstart" (=tap) event (I am not sure if cordova automatically converts click to tap but I think you will get the point) and force a redraw based on a reactive variable:

First rewrite your ul to not use any bootstrap based events but Blaze helpers:

<ul class="nav nav-tabs justify-content-center" id="myTab">
    <li class="nav-item">
        <a class="nav-link week-tab-link {{#if active 'currentWeek'}}active{{/if}}"
           id="home-tab"
           data-state="currentWeek"
           href="#currentWeekTab"
           aria-controls="home" aria-selected="{{active 'currentWeek'}}">
            1
        </a>
    </li>
    <li class="nav-item">
        <a class="nav-link week-tab-link {{#if active 'nextWeek'}}active{{/if}}"
           id="profile-tab"
           data-state="nextWeek"
           href="#nextWeekTab"
           aria-controls="profile" aria-selected="{{active 'nextWeek'}}">
            2
        </a>
    </li>
</ul>

{{#if active 'currentWeek'}}
    <p>render current week</p>
{{/if}}

{{#if active 'nextWeek'}}
    <p>render next week</p>
{{/if}}

As you can see the template relies on some state to determine a) which tab is active and b) which content to render.

To resolve this active state a helper is required:

Template.myTemplate.helpers({
  active (tabName) {
    return Template.instance().state.get('active') === tabName
  }
})

There also needs to be a default state to be set in order to determine what to render when the page is loaded:

Template.myTemplate.onCreated(function helloOnCreated () {
  const instance = this
  instance.state = new ReactiveDict(0)
  instance.state.set('active', 'currentWeek')
})

In order to save lines of code (=less possible errors) you can create an event map for a common class selector .week-tab-link which triggers an event callback if any of the tab is clicked. In this callback you can "read" the data-state attribute from the tab in order to set the active state:

Template.myTemplate.events({
  'click, touchstart .week-tab-link' (event, templateInstance) {
    // event.preventDefault() // uncomment this to prevent href update
    const $target = templateInstance.$(event.currentTarget)
    const activeState = $target.data('state')
    templateInstance.state.set('active', activeState)
  }
})

Note, that this uses ReactiveDict but you can also implement this using ReactiveVar.

Related:

Touch events in Meteor

Jankapunkt
  • 8,128
  • 4
  • 30
  • 59
  • This is sadly not working, the href is not taken into account anymore and changing the tab doesn't change the content... – Virthuss Dec 11 '18 at 08:06
  • 1
    You did not mention that you are rendering depending on the route. I will update accordingly – Jankapunkt Dec 11 '18 at 08:08
  • Worked perfectly! Had to remove some lines of code linked to bootstrap, but the idea you provided was the good one. Thanks. – Virthuss Dec 12 '18 at 09:29
  • Just one last thing: The click on the tab now put the scrolling back on the top of the screen. Is there a way to keep the scrolling level at the current one after a click? – Virthuss Dec 12 '18 at 09:35
  • Yes but I am not sure if this cause glitches. However you can check out [scrollIntoView (JS)](https://developer.mozilla.org/de/docs/Web/API/Element/scrollIntoView) or [scroll-behavior (css)](https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-behavior) in combination with Template`s `onRendered` where you can also run a `autorun` and check inside, whether the `active` state has changed and if so run one of the above methods. – Jankapunkt Dec 12 '18 at 09:41