Separate navbar Ctrl for one-page application - javascript

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.

Related

Mixing Static and Dynamic Elements in Header

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>

Onsen UI combined navigation (sliding-menu with tabbar and navigator)

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.

AngularJS routing load script on template load

In my single page application inside one of route templates I have script which loads (in place where it is placed) some content, like inputs and some forms.
simple example hot it looks:
<div class="col-xs-12">
<div class="col-md-12 centered-col-div" style="height:300px">
<script type='text/javascript' src='https://www.getContent.com' ></script>
</div>
</div>
When I put this code in main page, it works perfectly, but inside route template it is not executing. maybe someone can help me and say how to execute this code when route template is visible.

AngularJS + SPA - change layout

I build a SPA using AngularJS. I want to have two diffrent layouts for page and for admin dashboard.
My current index.html looks like this
<!DOCTYPE html>
<html data-ng-app="AngularApp">
<head>
....
</head>
<body>
<div>
//some code for navbar and others stuff that doesn't change
</div>
<div data-ng-view="">
//here are loaded all the content
</div>
I want to do a diffrent page with diffrent content and navbar for admin.
How can I switch to a completely different layout with different css, js etc.
Basically a second index-admin.html that will load angular, bootstrap, js, css and everything from the top
any ideas?
setting routing like this
.when("/admin", {
controller: "adminController",
templateUrl: "/app/admin/views/index.html"
});
will load content into
<div data-ng-view=""></div>
which I do not want
Take a look at https://github.com/angular-ui/ui-router
There is support for nested views that will allow you to have a base view for the admin user that has a different layout

AngularJS: Tab panes vary in HTML markup, I want them to be created dynamically and filled with data provided by factory service

I'm building a tabbed interface for displaying posts from various social networks (timelines) but not all tabs will have the same HTML markup. My factory service is returning JSON response so that part is fine.
Also, a sidebar contains tabs onto which I put ng-click for opening appropriate panes.
Now, I'm wondering if I should proceed with creating a custom directive to reside inside my tab-pane wrapper:
<div class="tab-pane">
<div timeline=""></div>
or
<timeline></timeline>
</div>
If so, I'm unsure whether $compile is the right approach? I've read that it is rarely used but it seems to me that it would allow me to dynamically decide which custom directive template to use, based on the clicked tab.
If there is a better approach to the solution, let me know. I'm really new to AngularJS but I'm eager to learn it, and learn it properly, applying best practices whenever possible.
The easy way might be:
<div class="tab-pane" ng-repeat="tab in tabs" ng-switch="tab.network">
<div ng-switch-when="Network_A">
/* Template for Network A here... */
</div>
<div ng-switch-when="Network_B">
/* Template for Network B here... */
</div>
<div ng-switch-when="Network_C">
/* Template for Network C here... */
</div>
</div>
So, you will need to add a network attribute to the tab objects, which tells what is the type of the social network.
Using directives might be a more efficient solution, but also more complicated.

Categories