Monaca Onsen UI Discord Chat Github Repo

Vue.JS + Vanilla = opinions?

  • I’ve found the solution at last. I was just about to rip my hair out when it occurred to me what the solution could be:

    1. Attach (a.k.a. mount) Riot/Vue/whatever component to the incoming page during the ‘init’ event (it’s prudent to keep track in an array of what tags are mounted so you don’t double-mount them in the case of multiple init fires for the same page, which can occur in some circumstances)

    2. Instead of navigator.pushPage, use:

    navigator.insertPage(0, 'page.html');

    …to sort of fake double buffering. I’ve got no more animation issues on iOS as of now, and hopefully it’ll stay that way.

    Edit: the ‘init’ event fires too many times already when using nested tabviews, and with the above change, it fires even more frequently, making it hard to attach the components. Should be fixable though.

  • @theprotocol Awesome! I agree on the init firing way too many times. That was the reason I went to the show event. I would assume init would only fire once but it seems to always be firing for some reason.

  • Onsen UI

    @munsterlander @theprotocol init event should fire only once per page. Otherwise it’s a bug :sweat_smile:
    Any short way to reproduce that behavior?

  • @Fran-Diox I will try to come up with a test. It just seemed like with the tabbar it would fire all the inits at once for all the tabs on startup and then all of them again when you would switch tabs. It may have been a coding issue on my side though.

    I will need to get more specific and see what I can come up with.

  • Onsen UI

    @munsterlander Oh! Well, now all the tabs are persistent so it’s normal that they throw init events at the beginning, but they should not throw them again after initialization.

  • Sorry for the delay in responding, I got swamped with some work. :sweat:

    In my case, the init event was firing many times because I’m using navigator.insertPage and navigator.bringPageTop to simulate double-buffering. I tried chaining them like insertPage(...).then(function(){bringPageTop()}) to avoid concurrent inits but it didn’t work and the same pages would init multiple times.

    I agree with @munsterlander though that sometimes init would fire multiple times even when using the regular pushPage too, but I can’t quite determine what circumstances cause that and can’t re-produce it. There’s definitely something related to <ons-template> containing a <ons-tabbar>, and/or nested tabbars and navigators.

    In the specific case of DOM injection on init, the source seems to be a mix of <ons-template> + <ons-tabbar> inside riot.js components. The <ons-template> seems to prevent the tabbar pages from being initialized on desktop (chrome + ripple emulator), but on mobile they did initialize (although I don’t know how to recreate this)! It’s extremely hard to diagnose because the above are inside riot.js tags, which are basically components that include html+javascript which I’m injecting into the DOM at runtime. So what happens when you inject a component with <ons-template> containing <ons-tabbar> where 1 of the tab pages also contains an <ons-tabbar> at runtime, and then load this <ons-template> from a navigator or tabbar? A huge mess. :)

    Switching back to navigator.pushPage seems to resolve the issue somewhat (with some fiddling, I managed to get init to only be called once per page now) but I’m back to the animation problems (iOS only, haven’t tested Android).

    The exact nature of the animation problems is twofold:

    1. If I inject a riot.js component into the incoming page DOM on page init, the animation shows the last frame for a split second (flicker) before occurring normally.

    2. Doing the same with an <ons-toolbar> inside the component that we inject to DOM on init completely cancels the animation (resulting in a heavy flicker and instantly going to the last frame).

    In summary, pretty much any DOM manipulation of the incoming page in page init ruins animations severely on mobile.

    I tried a gazillion workarounds, e.g. setting the page visibility to hidden for 20ms in the init event to prevent the last-frame appearing at animation start -> entire animation canceled with a flicker like in point #2 above.

    When I get some time I might try creating a plunkr which shows the animation issues, assuming I can recreate them.

  • Here is a plunkr which shows the worst case scenario of the animation problem (#2 in my last post - the transition animation is canceled when injecting an ons-toolbar with ons-back-button into the incoming page), which occurs on iOS Mobile Safari but not on desktop Chrome. In my Cordova app, it’s even worse than in this example (heavier flickering when the animation fails to occur), possibly because I have more elements on the pages.

    I couldn’t recreate animation problem #1 (last animation frame shows for a split-second upon animation start) on mobile Safari; it might only happen in Cordova, or I might be missing something about what’s causing it.

    I wonder if a different navigation approach is needed than loading a ons-template and doing DOM injection into it on ‘init’ or ‘show’. I feel like this should also be an issue with the React version of Onsen-UI… Or is the DOM injection into the ons-template done differently there? One thing is certain: DOM injection is how every framework is doing things nowadays.

    Ideally, I’d love for navigator.pushPage to expose some kind of ‘page setup’ function, specifically for injecting into the DOM of the incoming page, rather than doing everything in ‘init’, something like navigator.pushPage(page, options, callback, pageSetup).

  • I agree with @theprotocol. It definitely involved ons-template and ons-tabbar. Quick question though and maybe an observation, when you have a multi-tab tabbar, are all the tab inits supposed to fire on the first initial page load? If that is the expected behavior then ok, but it seems odd to do it when the items haven’t been attached to the DOM (or maybe they are supposed to be and there is a different issue at hand.)

    This is why I went to show. In that event, I would create additional event listeners for data binding. I would consistently get null pointer errors because the item was not attached to the DOM; however, the init event had fired. I in turn went to the show event which resolved my issue. I have yet to test everything with the new implementation of show, but I doubt it will affect my code much.

  • @munsterlander I believe ons-tabbar is persistent by default in 2.0, so all of the ons-tab do get initialized before they’re shown.

  • Onsen UI

    @theprotocol said:

    Ideally, I’d love for navigator.pushPage to expose some kind of ‘page setup’ function, specifically for injecting into the DOM of the incoming page, rather than doing everything in ‘init’, something like navigator.pushPage(page, options, callback, pageSetup).

    Yes, I actually wanted to mention it. We already planned to add some love around ons-template so we will probably implement something like that. This way you can inject custom behavior and also modify the template itself for the new page before it’s actually created. It would allow to write real templates (using handlebars or anything) in ons-template. In my mind it was something like this:

    myNavigator.pushPage('page.html', {
      templating: function(name, template) {
        return template.replace('{{placeholder}}', 'content');

    However, this may not be included in RC yet since we are focusing in bug fixes rather than new features, so probably after the release.
    Do you have any suggestions about it?

    Apart from that, we also have a rewritables object in every navigation component to inject some functionality before showing the page. This is used internally for, for example, creating page’s $scope in Angular 1 bindings. I made an example to integrate Knockout.js with beta.5 using this, so it may be helpful:

    @munsterlander In v2 the tabbar attaches all the pages at the beginning so it’s normal to see 3 or 4 init events at the same time (1 per page). It could be possible that, even though the page is attached to the DOM, its inner components are not. If you find this kind of issue, please report it and we’ll check it. It’s a bit hard to control all of this because everything is asynchronous.

  • @Fran-Diox I like the proposal for templating with options but agree that it may not be a priority for everyone. With v2 going persistent - which I had implemented awhile ago based on another one of our many conversations - it definitely solved some of my issues. The problem I had with the internal components not being attached was the inability to do data binding on controls that were not visible yet. Again, show resolved that, so I don’t think it is that big of an issue. I think its more of the fact that I need to wrap my head around init better.

    Overall, I have no issues with the current RC and it is more of changing my hacking code to proper code now.

  • @Fran-Diox I understand that it’s not going to happen right away, but I’m glad to hear your plans for improved templating. This is really critical these days since most frameworks are going with the component approach, which sadly isn’t compatible with the typical innerHTML loading mechanisms of navigators and such.

    That rewritables code looks very promising. I’ll give it a shot soon, thanks! :thumbsup:

  • @Fran-Diox FYI I’m still experiencing the same animation issue whether using rewritables or init to do the DOM attachment. You can see the bug in action if you access this on iOS, where you’ll see that the animation is completely broken because the element being attached (page-2-component.html) contains an ons-toolbar.

    I understand it might not be considered urgent, although it does seem like a bug, since I can also reproduce the animation issue by doing other kinds of processing upon page init, not necessarily just injecting a riot tag into DOM.

    edit: Tested on Android and there was no animation bug, so it’s only on iOS.