I have an app that has a navbar on everypage, so I factored it out into index.jade that inherits from my layout.jade file. This is fine for 99% of my app.
The only place it runs into issues is on the login screen as it just feels weird to have a navbar at the login screen, so I used angular to check a boolean against a $rootScope variable and hide the navbar if you are on the homepage.
This is okay but the navbar still loads for a split second, then it disappears. I know I could correct this by not factoring it out into a single file and just cramming it into every single jade file besides the login page, but this would be a maintenance nightmare.
Is there a way that I can keep my navbar factored out, hide it on the login screen using ng-hide, and not load at all until I login.
This is my code to give you an idea of what I did.
The controller that checks to see if you are at the root of the app ('/')
angular.module('app').controller('LoginCtrl', function($scope, $http, mvIdentity, mvNotifier, mvAuth, $location, $rootScope) {
$rootScope.currentPath = $location.path();
....
....
The jade file that shows how this variable is being used to hide the navbar
block main-content
section.content
nav.navbar.navbar-default(ng-hide='currentPath=="/"', role='navigation')
....
....
....
Then upon successful login, the currentPath variable gets set to false to bring the navbar back.
$rootScope.currentPath = false;
I would like to keep this set up because that means any changes to the navbar can be made in a single file and would be inherited across the app, cutting maintenance down tremendously, but I would like for the navbar to wait to load until login. As opposed to flickering from shown, then to hidden, and then to shown again.
Yes, it's possible to do this.
The reason you're seeing things flash up is because the page loads before angular has bootstrapped and applied ng-hide.
There are two approaches to solve this.
1. Put your script files in the head of the page
This is my preferred approach. By putting the script files in the head element, the page won't render until the scripts have loaded. This means angular will bootstrap the page first, and when it does render, the ng-hide will be correctly applied.
Some people prefer the page to start loading first, so won't use this method, but I personally don't think it matters.
2. Use ngCloak on the elements you need to hide
Basically, by applying the ngCloak directive to elements, and embedding the style provided in the link, you can hide certain elements until after the page is loaded. Essentially all ngCloak does is applies display:none to elements and removes it when angular finishes loading.
Related
In my current app there are quite some complex calculations to do after $routeChangeSuccess before the new page is really fully shown. This causes a bit of "flickering" as the content changes position and size. I'm already preloading the needed JSON and images before the route changes (via resolve in the $routeProvider).
My idea to prevent this is to stop ngView from deleting the old content before the new one gets inserted. Instead I want to insert the new content with display:none set, so the newly compiled directives can execute their linking procedures while the old route content is still showing. After this is all finished, the old content would be deleted and the new content would be displayed which would happen instantly with no flickering.
Is there a way to do this? I didn't find any option in the docs or in google where you could define such a behaviour. The only option I see now is a custom build of ngRoute where I change the ngViewFactory to my needs. But I don't really like that idea as this will be stressful when I want to upgrade my angular version etc. Maybe there's a better way?
We have a parent site that provides the real estate for our applications to be added. The flow is described as below
Parent site has a menu.
One of the "links" on the menu points to our
application
When you click on it, the parent site internally parses
the response from our application (including html and javascript)
and loads it within a container. Sort of a portlet. This parsing is problematic, because once the javascript is loaded, it remains in the head tag.
Thereafter, we can use our code to control the application in a SPI manner.
Problem arises, when the user clicks on the menu again, because steps 1-4 get repeated. Thus we end up reloading javascript, which fails spectacularly. Some of the problems include
Angular is reloaded.
Modules get reloaded.
If I defer the loading of Angular conditionally via document.write, then I have to ensure that angular is loaded before the modules are defined.
If I manually bootstrap the application, then I cannot bootstrap it again and I need flags to maintain.
I was able to write a script to ensure that everything is loaded only once, but now the problem is that the DOM does not get "processed" once the user clicks the link again. It is as if the entire DOM content has refreshed with the angular tags and directives, and the javascript is already loaded, but it does not "process" this new DOM content.
What can I do to ensure that newly added DOM via a third party plugin/script/code is recognized by existing angular code?
I'm making a game using JavaScript, currently I'm using window.location = "somepage.html" to perform navigation but I'm not sure if that is the correct way to do it. As I said in the title I've choosed Blank App Template so I do not have any navigator.js or something like.
Can you guys tell me the best way to do it?
Although you can use window.location to perform navigation, I'm sure you've already noticed a few of the downsides:
The transition between pages goes through a black screen, which is an artifact of how the underlying HTML rendering engine works.
You lose your script context between pages, e.g. you don't have any shared variables or namespaces, unless you use HTML5 session storage (or WinRT app data).
It's hard to wire up back buttons, e.g. you have to make sure each destination page knows what page navigated to it, and then maintain a back stack in session storage.
It's for these reasons that WinJS + navigator.js created a way to do "pages" via DOM replacement, which is the same strategy used by "single page web apps." That is, you have a div in default.html within which you load an unload DOM fragments to give the appearance of page navigation, while you don't actually ever leave the original script context of default.html. As a result, all of your in-memory variables persist across all page navigations.
The mechanics work like this: WinJS.Navigation provides an API to manage navigation and a backstack. By itself, however, all it really does is manage a backstack array and fire navigation-related events. To do the DOM replacement, something has to be listening to those events.
Those listeners are what navigator.js implements, so that's a piece of code that you can pull into any project for this purpose. Navigator.js also implements a custom control called the PageControlNavigator (usually Application.PageControlNavigator) is what implements the listeners.
That leave the mechanics of how you define your "pages." This is what the WinJS.UI.Pages API is for, and navigator.js assumes that you've defined your pages in this way. (Technically speaking, you can define your own page mechanisms for this, perhaps using the low-level WinJS.UI.Fragments API or even implementing your own from scratch. But WinJS.UI.Pages came about because everyone who approached this problem basically came up with the same solution, so the WinJS team provided one implementation that everyone can use.)
Put together then:
You define each page as an instance of WinJS.UI.Pages.PageControl, where each page is identified by its HTML file (which can load its own JS and CSS files). The JS file contains implementations of a page's methods like ready, in which you can do initialization work. You can then build out any other object structure you want.
In default.html, define a single div for the "host container" for the page rendering. This is an instance of the PageControlNavigator class that's defined in navigator.js. In its data-win-options you specify "{home: }" for the initial page that's loaded.
Whenever you want to switch to another page, call WinJS.Navigation.navigate with the identifier for the target page (namely the path to its .html file). In response, it will fire some navigating events.
In response, the PageControlNavigator's handlers for those events will load the target page's HTML into the DOM, within its div in default.html. It will then unload the previous page's DOM. When all of this gets rendered, you see a page transition--and a smooth one because we can animate the content in and out rather than go through a black screen.
In this process, the previous page control's unload method is called, and the init/load/processed/ready methods of the new page control are called.
It's not too hard to convert a blank app template into a nav template project--move your default.html/.css/.js content into a page control structure, add navigator.js to default.html (and your project), and put a PageControlNavigator into default.html. I suggest that you create a project from the nav app template for reference. Given the explanation above, you should be able to understand the structure.
For more details, refer to Chapter 3 of my free ebook, Programming Windows Store Apps with HTML, CSS, and JavaScript, Second Edition, where I talk about app anatomy and page navigation with plenty of code examples.
I'm adding a log-in screen to my angular app, and I would like to hide the main nav bar while the log-in screen is displayed. Once the log-in is passed, I need to show the main nav again. Currently the main nav is a part of the Index.html, which is the first file being served, and also is the one in which the ng-app is defined. I understand, that I can use ng-show attribute, but I do not know how to specify the condition for ng-show, which can be access and changed from within different parts of my single page app. Perhaps, a good example of using $rootScope or something similar for this purpose would really help.
Every scope has a reference to $rootScope via its $root property. So anywhere in your HTML you can write
ng-show="$root.mainNavVisble"
where mainNavVisible is a property on $rootScope indicating whether the main nav should be visible or not.
Imagine you have one page app using Javascript MVC, which should switch between sub-apps and still stay on the same page. You can load additional controllers and views into the page, but to avoid the conflicts between different controllers, you need to enable the current controller and disable others. You can even destroy the controller and add the current sub-app controllers if needed.
Is it possible? if so, how?
Thanks.
Usually you have some kind of hierarchy on your page (e.g. a page controller, some for navigation etc.) and you only replace the controllers of the part of your page that actually changes.
For a central content element that means either destroying the controllers (by calling destroy on it) or replacing the element that will change (which will remove the controller attached to it as well). So you don't really need to disable anything because you are actually removing the whole thing.