I am upgrading my first PhoneGap application with a couple new functions that require to have separate pages.
I started implementing a sliding-menu, but I quickly bumped into problems.
The initial application had an ons-navigator that took care of all the navigation through the app.
I have 2 controllers: a LoginController and an AppController.
The structure of my index.html file looks like this:
<ons-sliding-menu main-page="navigator.html" menu-page="menu.html" side="left" max-slide-distance="250px" var="menu">
</ons-sliding-menu>
<ons-template id="menu.html">
<ons-list>
<ons-list-item modifier="tappable" onclick="menu.setMainPage('navigator.html', {closeMenu: true})">
Home
</ons-list-item>
<ons-list-item modifier="tappable" onclick="menu.setMainPage('Page1.html', {closeMenu: true})">
Page1
</ons-list-item>
<ons-list-item modifier="tappable" onclick="menu.setMainPage('Page2.html', {closeMenu: true})">
Page2
</ons-list-item>
</ons-list>
</ons-template>
<ons-template id="navigator.html">
<ons-navigator title="Navigator" var="myNavigator" page="main.html">
</ons-navigator>
</ons-template>
This is the navigation part of the page.
Then I have the pages like this:
<ons-template id="login.html">
<ons-page ng-controller="LoginController" id="login">
<ons-toolbar>
<div class="center">Log In</div>
</ons-toolbar>
<div class="login-form">
<input type="text" class="text-input--underbar" placeholder="Username" ng-model="email">
<input type="password" class="text-input--underbar" placeholder="Password" ng-model="password">
<br><br>
<ons-button modifier="large" class="login-button" ng-click="checkLogin(email,password)" > Log In</ons-button>
Don't have an account? Register now!
</div>
</ons-page>
</ons-template>
<ons-template id="main.html">
<ons-page id="main" >
<ons-tabbar>
<ons-tab active="true" page="SP1.html">
<div class="tab">
<ons-icon icon="ion-calendar" class="tab-icon"></ons-icon>
<div class="tab-label">SP1</div>
</div>
</ons-tab>
<ons-tab page="SP2.html">
<div class="tab">
<ons-icon icon="ion-checkmark" class="tab-icon"></ons-icon>
<div class="tab-label">SP2</div>
</div>
</ons-tab>
<ons-tab page="settings.html">
<div class="tab">
<ons-icon icon="ion-gear-a" class="tab-icon"></ons-icon>
<div class="tab-label">Settings</div>
</div>
</ons-tab>
</ons-tabbar>
</ons-page>
</ons-template>
In the pages mentioned in the main.html tabbar, I use the AppController, and in the login.html I use the LoginController.
When the application loads I have the following ons.ready function:
ons.ready(function() {
var storage = window.localStorage;
if(storage.getItem("username")!=null) {
if(storage.getItem("password")!=null) {
myNavigator.resetToPage('main.html');
}
}
else
{
myNavigator.resetToPage('login.html');
}
});
My first problem is, that the application initiates the AppController in the beginning, even though it shouldn't, so if there are no saved credentials in the cache, it still shows the main.html page for a second and then goes to the login.html. It does an unnecesary cycle and it's probably because of the navigation. I haven't found out why, i'm a little lost because of the 2 navigation systems.
The second problem is, that I cannot include ons-back buttons on the pages the sliding-menu has, because they appear for a second, and then they get overlapped by the header.
Any way, to clean up the navigational system, so the ons-sliding-menu and the ons-navigation work with eachother?
Also: Am I supposed to include an [ons-navigator var="myNavigator"] in all the pages that I tend to use the myNavigator.resetToPage('page.html') function on?
This is how Page1.html works (that is in the sliding-menu)
<ons-template id="Page1.html">
<ons-navigator title="Navigator" var="myNavigator">
<ons-page ng-controller="AppController" ng-init="ListLoad()" id="page1">
Page1.html has a list of items, that each are clickable and brings up a Details.html page.
The onclick event of the item (which has a simple myNavigator.resetToPage('details.html') function) didn't work until I added the to the page, but it seems to me that it's not right.
Any ways of clarifying the whole navigation in the onsen UI?
ALSO: Is there a way, to have the bottom tabbar visible on all the pages? So you could go to SP1.html or Settings.html from ANY page in the app?
Props for trying to use all navigation components in one app. Even though you may not be doing it the right way, but I guess that is why you asked this question.
first problem is, that the application initiates the AppController
It's doing that because you have set it to load main.html initially.
<ons-template id="navigator.html">
<ons-navigator title="Navigator" var="myNavigator" page="main.html"></ons-navigator>
</ons-template>
If you just remove the page attribute everything will be fine.
The second problem is, that I cannot include ons-back buttons on the pages the sliding-menu has, because they appear for a second, and then they get overlapped by the header.
TBH I'm not sure that I can grasp the situation very well. I am guessing that by header you mean an ons-toolbar element. If they are overlapping - why not just put them inside the ons-toolbar? Secondly this seems to be some sort of css issue, and for it you haven't provided neither the html nor css in order to reproduce, so it's hard to really help you with this amount of information.
So the only thing I can suggest is doing right click → inspect element and check what the situation is. You haven't mentioned which version of Onsen UI you are using, but I guess there is a chance that the ons-backbuttons are hiding themselves because of some Onsen logic which tries to see if there is a previous page to go back to.
Any way, to clean up the navigational system, so the ons-sliding-menu and the ons-navigation work with eachother?
Well since you can see that managing the navigation using multiple components is hard, what I would suggest is try to limit yourself to use less components for the actual navigation (preferably one).
The way which I see things you seem to be doing menu.setMainPage, so that means that when you do that you will lose all of the pages inside the navigator of your current page. However it seems that as a result of that you are trying to later put navigators in the other pages too.
A much simpler solution for this case would be - let the main page of the sliding menu be only one page with a navigator. Afterwards instead of calling menu.setMainPage you can just call myNavigator.resetToPage and achieve the same result. Basically you use sliding menu only to get access to the sliding menu and then you use the navigator for all navigation purposes.
Also: Am I supposed to include an [ons-navigator var="myNavigator"] in all the pages that I tend to use the myNavigator.resetToPage('page.html') function on?
If you want to use myNavigator you should always have a navigator to access. That's why in my suggestion is to have it outside of the pages Page1, Page2 etc and then just them inside the navigator. (You always have navigator.html in the sliding-menu, but only change the the contents of the navigator to Page1, Page2 etc.)
Any ways of clarifying the whole navigation in the onsen UI?
Basically we have several navigation components. Each of them is rather simple providing one or two methods to load a page somewhere inside of it. The only exception is ons-navigator. So what is generally recommended is to use the navigator as the main component for navigation and have others like sliding-menu and tabbar only for the additional bonuses which they bring (the sliding side and the tabbar buttons).
If you want to have many levels of navigation then that's up to you - as long as the navigation is structured as a tree and not a web (or spaghetti) it should still be fine. Usually a sheet and a pen are your best friends for deciding such navigations before the implementation.
ALSO: Is there a way, to have the bottom tabbar visible on all the pages? So you could go to SP1.html or Settings.html from ANY page in the app?
And just as things were becoming simpler we're adding one more complexity element to the table.
Since you want to have the tabbar on ANY page of the app that means that EVERY page in the app should be inside the tabbar. I am guessing that you still want your sliding-menu, so I guess you should have something like ons-sliding-menu > ons-tabbar.
In that case the solutions which come to my mind are:
Since in the code which you have showed you are using only myNavigator.resetToPage and never pushPage then maybe you can just remove the navigator in general. So maybe you can have only ons-sliding-menu > ons-tabbar as your logic and then do all navigation through the tabbar. So this means using something like myTabbar.loadPage in all places where you want to load a page.
If you want you could have a tree type navigation where you do something like the previous, but with the difference being that the pages which you want to use something like pushPage you have a navigator. So you will be choosing between setting the page of the tabbar and doing something with the navigator. In this solution though whenever you do an action with the tabbar you will lose the navigation stack.
Again just don't use the tabbar for the navigation, but rather use the navigator instead. The way to do that is:
Have ons-sliding-menu > ons-tabbar as your main html structure
Initially load navigator.html inside the tabbar the same way which you're doing now with the sliding-menu.
Don't provide active and page attributes to the tabs, but instead have something like ng-click="myNavigator.resetToPage('SP1.html')". I guess you can also modify some classes if you want them look activated.
That's pretty much all I've got as suggestions.
As conclusion I would advise you to try to follow the KISS principle.
Related
I am developing an application using Angular 1.X.
There is a component that is used across three pages.
I have several nested components into a main component. However there are two components that will only show on one page. I am currently ng-if(ing them) and was wondering if this is a bad option.
<!-- Component 1 -->
<div class="wrapper">
<div ng-if="showChildren">
<component2> </component2>
</div>
<!-- more code goes here -->
<div ng-if="showChildren">
<component3> </component3>
</div>
</div>
On the required page I would add in the controller
<component1 showChildren="true"></component1>
The code works, it gives no errors on page or in console.
Even though there might be other solutions for this, is there anything about this that is actually bad design/implementation?
This is mostly a matter of preference, as there's nothing inherently wrong with your solution.
Just a couple suggestions though:
If you are hiding all the children of the div.wrapper, why not apply the ng-show to the wrapper itself?
Since it seems that the value of showChildren won't change, why not use ng-if instead, and simplify the DOM? ng-show still generates the hidden DOM elements and uses styling to hide them, while ng-if will simply not generate them.
I am relatively new to angulerjs but using routes, services, controllers etc, I can develop a standard web application with a navbar header with pages appearing in an ng-view below it, i.e.
<body>
<header>
navbar goes here
</header>
<div class="content-wrapper" ng-controller="MainController">
<div ng-view></div>
</div>
</body>
At the moment, everything that appears between the <header> tags is completely static and doesn't change regardless of what page is loaded within the ng-view.
I now need to add a number of items to the header which is contextual based on what page is in ng-view.
So, I'll have a single bar across the top of the site (like stackoverflow). It will contain two sub elements - one will be floated to the left and will be static, the other will be floated to the right and it's contents will be dynamic.
I'm unsure how to accomplish this in angularjs because I believe a page can only contain one ng-view
Any advice would be appreciated
EDIT: Adding following explanation:
To give a little more context, one of the DIVs in the header will contain contextual buttons. E.g. if the site is displaying a product item, the buttons in the header will be 'Edit', 'Delete'. If the site is displaying an invoice, the buttons in the header will be 'Add Product', 'Send Invoice'. My header is basically like Youtube's, if the buttons on the right changed based on the type of page being displayed
I'm not entirely sure of exactly what you're trying to set in the header based on ng-view, and you may want to rethink some of the structure here if you're just starting out. In general, though, you can nest things a little differently to give you access to objects within MainController's $scope:
<body>
<div ng-controller="MainController">
<header>
{{customHeader}}
</header>
<div class="content-wrapper">
<div ng-view onload={{customHeader = 'something new'}}></div>
</div>
</div>
</body>
I am building a one page application with AngularJS. Right now I am using just one controller which is one very long file (of course there are several factories but nevertheless the Ctrl is still full). So as I could divide my page into navbar and the body, i thought of having a separate Ctrl for the navbar. (the thing is here, the navbar includes a big options dropdown and some other stuff, so not just Title and Links) However I do not really how to do that. Right now my main.html file looks like the following:
<div ng-include="'views/templates/navbar.html'" id="navbarContainer"></div>
<div id="map-container" class="container-fluid">
<leaflet id="map" lf-center="hamburg" markers-nested="true" layers="layers" defaults="defaults" markers="markers" class="map"></leaflet>
</div>
So as you can see, my navbar is a template in the main html file. Additionally the navbar and the main html should have the same route. So now, I definitely do not know how to use a second Ctrl. Do I not use the ng-template or can I just give the ng-template a separate Ctrl than the part below?
The navbar.html file can include its own controller.
Navbar.html
<div ng-controller="NavbarCtrl">
<!-- your code -->
</div>
See the Controller: Scope Inheritance Example in the AngularJS Docs for more info.
i am developing an app with cordova + Onsen UI.
I would like to know how can I use the .popPage() method to a navigator content.
Is it possible? I read and read and read but did not understood exactly the mean for a navigator.
I tried to get all this content off from navigator and put into a new page, then I defined the main page to this new I've created. But had no success too.
Look the code:
<ons-template id="home.html" style="background:#fff;">
<ons-navigator var="myNavigator" title="Navigator">
<ons-page id="content-home" class="fill">
<div class="gradient">
So how can I use push or replace function for a page inside the navigator?
Thank you.
There are many ways to manage the navigation, I'll show you an example with an ons-button element which, when triggered, pushes a new page into the navigator:
<ons-button modifier="light" ng-click="myNavigator.pushPage('page1.html', { animation : 'slide' } )">
Push Page
</ons-button>
You can find a full list of ons-navigator methods in the official documentation.
You also need to distinguish 3 concepts:
Push page: adds a new page into the stack.
Pop page: returns to the previous page on the stack, cannot be triggered if a push page action has not occurred yet.
Replace page: replace the current page with the specified one.
You can see a full example of navigation by taking a look at this CodePen example
EDIT (answers the opener's below comment)
I suggest you to don't put a page inside the navigator element but, instead, use the page attribute, which specifies the mail loaded page. Doing this, you can push the same page as many times as you wish.
Here is a very simple example, with its code:
<ons-navigator var="myNavigator" page="page1.html"></ons-navigator>
<ons-template id="page1.html">
<ons-page>
<ons-button ng-click="myNavigator.pushPage('page1.html');">Push</ons-button>
</ons-page>
</ons-template>
I´m starting to develop a Chrome App just to test it.
It seems that this kind of applications (desktop app at the end) must be developped with the single-page concept in mind.
But my application consists of three pages or "sections": One to control a web-cam, another to watch a streaming and the last to control a videoconference.
I´ve been reading and coding a bit within the Chrome Platform developing center, and just could find basic tutorials with one .html page.
So, my question is: What is the best way to load different .html pages (because i need to show different UI sections) in a Chrome App? I´ve seen that Google uses AngularJS to implement an MVC pattern, but i don´t know how to change from one view to another (thinking of views as .html pages) in that scenario (because i´ve never used AngularJS).
Thanks!
Is there a specific reason you need multiple HTML pages? It's pretty straightforward to do something like this:
<html>
<body>
<div id="tab_1">Section One</div>
<div id="tab_2">Section Two</div>
<div id="tab_3">Section Three</div>
</body>
</html>
and then show/hide each div according to which part of your app you want to show. CSS frameworks like Bootstrap are designed to work well this this kind of approach, turning the set of divs into a pane with a left nav, or a content area with a tab strip, all of which match the needs of a typical app UI.