2

I have previously created a web app, and now I would like to integrate it with OnsenUI to enable my app to be used on all mobile devices as well as the web.

I am using a splitter in a toolbar which will be the header of all pages, and it will redirect the user to other pages when they click an item in it. Clicking the home item successfully redirects to the home page (index, which is already loaded correctly). However, clicking any of the other items in the splitter redirects me to the requested page, but shows the content of the file in text format instead of actually rendering the page. It looks like the following, except it's all jumbled together with no spaces:

searchForTrainer.jade:

//-ons-template(id='searchForTrainer.jade')
ons-page(ng-controller='SearchController' ng-init='showme = false; getAllTrainers();')

ons-toolbar
  .left
    ons-toolbar-button(ng-click='mySplitter.left.open()')
      ons-icon(icon='md-menu')
  .center
    | Search Trainer

   // ***** I cut off the rest of the file for simplicity 
   // ***** I should still be able to see the toolbar if the page loads correctly

Here is the content of index.jade:

doctype html
html
  head
    link(rel='stylesheet' href='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css')
    link(rel='stylesheet', href='/stylesheets/style.css')
    link(rel='stylesheet' type='text/css' href='/stylesheets/jquery.datetimepicker.css')
    link(rel='stylesheet' type='text/css' href='/stylesheets/ratings.css')
    link(rel='stylesheet' type='text/css' href='/stylesheets/searchTrainerTab.css')
    link(rel='stylesheet' type='text/css' href='/onsenui/css/onsenui.css')
    link(rel='stylesheet' type='text/css' href='/onsenui/css/onsen-css-components.css')


    block loadfirst
    script(src='https://ajax.googleapis.com/ajax/libs/angularjs/1.5.7/angular.min.js')
    script(src="https://code.jquery.com/jquery-1.12.3.min.js"
        integrity="sha256-aaODHAgvwQW1bFOGXMeX+pC4PZIPsvn2h1sArYOhgXQ=" crossorigin="anonymous")

    script(src='/onsenui/js/onsenui.js')
    script(src='/onsenui/js/angular-onsenui.js')
    script(src='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js')
    script(src='/angular/fitnessapp.js')

    script(data-require='angular-credit-cards@*', data-semver='3.0.1', src='https://rawgit.com/bendrucker/angular-credit-cards/v3.0.1/release/angular-credit-cards.js')

    script(async='', defer='', src='https://maps.googleapis.com/maps/api/js?key=AIzaSyDcVf7YAPNwa8gUsMCOZNQZA31s5Ojf2n8&libraries=places')



      body
        ons-splitter(var='mySplitter', ng-controller='RootController as splitter')
          ons-splitter-side(side='left', width='220px', collapse='', swipeable='')
            ons-page
              ons-list
                ons-list-item(ng-click="splitter.load('index.jade')", tappable='')
                  | Home
                ons-list-item(ng-click="splitter.load('searchForTrainer.jade')", tappable='')
                  | Search Trainer
                ons-list-item(ng-click="splitter.load('searchForEvent.jade')", tappable='')
                  | Search Event
                ons-list-item(ng-click="splitter.load('trainerAddEvent.jade')", tappable='')
                  | Create Event
                ons-list-item(ng-click="splitter.load('userProfile.jade')", tappable='')
                  | Profile
                ons-list-item(ng-click="splitter.load('addPayment.jade')", tappable='')
                  | Payment
                ons-list-item(ng-click="splitter.load('userSettings.jade')", tappable='')
                  | Settings
                ons-list-item(ng-click="splitter.load('trainerSignup.jade')", tappable='')
                  | Trainer Application
                ons-list-item(ng-click="href='/logout'", tappable='')
                  | Logout
          ons-splitter-content(page='index.jade')

        ons-template(id='index.jade')
          ons-page(ng-controller='MapController' ng-init='getEvents()')

            ons-toolbar
              .left
                ons-toolbar-button(ng-click='mySplitter.left.open()')
                  ons-icon(icon='md-menu')
              .center
                | Fitness App
              //-.right
                a(href='https://www.paypal.com/webapps/mpp/paypal-popup', title='How PayPal Works', onclick="javascript:window.open('https://www.paypal.com/webapps/mpp/paypal-popup','WIPaypal','toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=yes, resizable=yes, width=1060, height=700'); return false;")
                  img(src='https://www.paypalobjects.com/webstatic/mktg/logo/bdg_now_accepting_pp_2line_w.png', border='0', alt='Now Accepting PayPal')

            //- google maps stuff
            ons-input#pac-input.controls(type='text', placeholder='Search Box')
            div#map.col-md-12

            ons-bottom-toolbar
              .center
                | Fitness App

      block scripts
        script.
          // ***** I cut out javascript related to Google Maps for simplicity

here is the splitter load page function I am using in my angular file:

this.load = function(page) { console.log("The page is: " + page);
    mySplitter.content.load(page)
      .then(function() {
        mySplitter.left.close();
      });
  };

Has anyone successfully built an Onsen app using Jade?

UPDATE When I leave the code in html instead of jade, everything works correctly. When I convert it back to jade it shows up as text again.

UPDATE 2 Using Solution 1 from the selected answer, I realized and solved my problem with the guidance from the selected answer on my other post: Answer

Community
  • 1
  • 1
rgins16
  • 349
  • 1
  • 3
  • 11

1 Answers1

2

By the looks of it you seem to be using Jade on the server side.

To solve the problem I see a couple possible solutions.

Solution 1:

Make sure that whatever Onsen UI is receiving is pure HTML. You're free to use Jade, but as it stands Onsen does not have Jade bundled inside, so there is no way for it to support it out of the box. However as long as Onsen sees only html it should be fine.

The reason why the ons-template(id='index.jade') works initially is actually because when you serve the page you are actually serving actual html, so when onsen starts the contents of that template are actually pure html.

In searchForTrainer.jade it seems that you are giving it raw jade, which it does not know how to handle. You can handle this on the server side, making sure that the request for the searchForTrainer returns html. Returning jade.renderFile('searchForTrainer.jade') from the server instead of the jade file itself should solve the issue.

Solution 2:

As you noticed as long the contents are inside the initial page everything will be fine. So you could just put all your ons-templates inside the initial page.

If you want to retain your current file structure you can just do

include searchForTrainer.jade

while having an ons-template tag in the file itself. That way in the end the result will be a page with the template already converted into html.

Solution 3:

The final option is to give the raw jade files, but help Onsen understand Jade, so that it can use them properly. To do that you need to include jade.js and modify Onsen UI so that it uses it.

However since Onsen does not currently provide an official API for switching template engines whatever hack we use now might break in the future. It's possible that in the near future a feature like that may be implemented, but in order to do it now we need to wrap some of onsen's internal functions.

Here's a simple example to do it.

module.run(function($onsen) {
  var old = $onsen.normalizePageHTML;
  ons._internal.normalizePageHTML = $onsen.normalizePageHTML = function(html) {
    return old(jade.render(html, {}));
  };
});

And here's also a working Demo showing this solution in action.

Note: that demo actually checks for a comment // jade at the beginning just to be safe.

Which solution to choose?

Solution 1 - I think this makes most sense as it retains a clear separation of concerns. If you want to change the templating engine it should be handled only in one place. Onsen does not need to know what you're using on the server as long as it gets what it wants.

Solution 2 - Not the best way to solve the problem, but it may be the easiest to use if you just want things to work. One minus is that with it you would load all the templates at the beginning, which may not be very good.

Solution 3 - While this solution can work I would suggest avoiding it as handling jade on the frontend would result in poor performance. It's could be an option if you actually decide not to rely on the server.

Ilia Yatchev
  • 1,254
  • 7
  • 9
  • Thank you for your very detailed answer. However when I try to implement solution #2, no matter where in index I put 'include searchForTrainer.jade', the page loads as a white screen. The searchForTrainer file starts as: ons-template \n ons-page \n etc... – rgins16 Jul 08 '16 at 14:27
  • Did you receive some kind of error - either from the server or client side? – Ilia Yatchev Jul 08 '16 at 14:49
  • I received a 500 (Internal Server Error) which I was only able to see if I clicked 'preserve' in the browser console. – rgins16 Jul 08 '16 at 14:53
  • hmm... I guess it sounds like a server issue in that case. Maybe there is some additional requirement like needing to write a `./` at the beginning like `include ./searchForTrainer.jade` or indentation issue. Just to be safe you can try to remove any "strange" markup like scripts etc. Maybe you can try to include something extremely simple like the example [here](http://jade-lang.com/reference/includes/) and see if that works properly – Ilia Yatchev Jul 08 '16 at 14:59
  • Wow. I fixed the problem. I'm wondering if you can explain this to me: In searchForTrainer.jade, I had an giant block of code commented out. The way I commented out was by putting '//-' to the left of the top div for the block of code. This commented out the whole chunk of code. When I deleted the commented code, my page rendered in jade correctly. Additionally, when I did 'Ctrl-A', 'Ctrl-/' every line became commented out with '//-' instead of just the top div. This also led the page to be rendered correctly. Any idea about what the issue was? – rgins16 Jul 08 '16 at 15:29
  • Well basically usually it's better to have a `//-` in front of every line. Having it only at the top div might actually still leave the contents, but without the parent that would screw up the indentation. Another option would be if you had an empty line somewhere and had a setting "trim_trailing_on_save" or something similar which would remove trailing spaces and again causing improper structure. Anyway using `Ctrl + /` to comment out all selected lines is always best. I would suggest doing that in the future. Well I'm glad the problem was solved. Good luck with your project. :) – Ilia Yatchev Jul 08 '16 at 16:16
  • I was thinking how I would go about solution 1 while still using the splitter. Instead of the mySplitter.content.load(page), would I need to make a nodeJS route to perform 'jade.renderFile('searchForTrainer.jade')'? Because I believe that can not be done in Angular. – rgins16 Jul 08 '16 at 17:05
  • You are correct. node.js is the server - where solution 1 resides. Angular is the client (where you can do solution 3). Anyway since what you're asking in the last message is purely a server issue I think making a separate question (in which you can provide the server code) would be for the best. If you still want to keep the connection between the two questions you can comment on them each referencing the other one. – Ilia Yatchev Jul 08 '16 at 19:14
  • Perfect. Thank you for all your help :) – rgins16 Jul 08 '16 at 22:13
  • Hi @ilia, I'm revisiting this. I have been using solution 1 since last July. My application seems to lag because of what I assume to be: every time I use a navigator to load a page, my browser has to communicate to the server to convert the raw jade. Would it be faster to just convert all my jade to html? Would that eliminate the need to communicate with the server on page loading? – rgins16 Apr 13 '17 at 14:13