How to to avoid angular app reacting on specific URL hash change - angularjs

I am currently rewriting an older version of and application where HTML is mostly generated server-side in angularJS.
Only some parts of the page are not powered by AngularJS while some of client side logic is still plain JavaScript. For URL routing we use UI-router
One of the cases is tabs that are used across all the application. It's current implementation contains above all rewriting location hash like this: myapp_url?foo=bar#1, myapp_url?foo=bar#2 etc.
Note - no slash "/" in hash part.
In my case angular block is in one of the tabs is not visible by default. So when user clicks tabs on a page, URL is changed to smth like myapp_url?foo=bar#TAB_id, which is not understaded by UI router and it redirects the app ( not the whole page but a angular-powered block) part to a 404 state.
Angular UI router relies on Url mask like myapp_url?foo=bar#/my_route - with slash symbol in hash part - so that could be a trigger.
I am asking how/where I could add this kind of check - for angular part whether to act or skip on url change?

I've solved it by creating a state with empty url, which does not interfere with url hash changes by javascript outside angularJS app.
$stateProvider
.state("base.emptyState", {
url: "",
template: '';
})

Related

AngularJS ui.router -- How to keep URL patterns manageable

If we are using "ui.router" of angular JS module, will that module take control of all the URL navigation in the entire page?
I am using the $stateProvider.state method to register the mappings of URLs and States but as I am using it, I am observing that the state provider is taking control of routing all URL patters. For example, if I am having a jquery tabs pane in the same page somewhere, it is not working. The reason being, the jquery tabs are based on the HREF of the Anchors and this ui-router is taking charge of mapping them as well, to some states.
Can someone please confirm if it really is supposed to work like this?
No, as per I know, it should work fine with HREF,for example
link
In your case, for tabs you are specifying #(hash) in href and thats why its going through ui-router, I would suggest you to use <uib-tab> instead of simple jQuery tabs and thing will work as you needed.
If you are using # in anchor tag then it will always try to match it with url and if not found then it will redirect to defualt one but you can actually intercept url change request in run function and use preventDefault function for specific request which will stop url change request

Angular html5mode prevents links outside of base href to be loaded

My setup is as follows:
I have a website for which I would like one of the pages to be handled by angular (javascript heavy one).
I have set base href for this specific page only as <base href="/myangularpage">
This page is being controlled over only by url params. There is only one page like this. No routing. I handle the state using url parameters only. Example url: http://domain.com/myangularpage?param1=2&param2=3
However this page contains links to some other pages which should be followed and not handled by angular. Like /external-page. By external I mean they are on the same domain but have different base.
However setting up html5mode causes those links to be "push stated".
According to the docs and the answer to Angularjs Normal Links with html5Mode /external-page has a different base so should not be handled by angular.
But the problem is it is!
Tried adding / to the base url but I got a meaningless exception. I don't want the trailing slash in my page url so this isn't a real solution anyway.
EDIT:
So it seems it works when my base url has a trailing slash and I serv the page with an url which contains the slash. But I don't want the slash as it is a single page only.

Prevent angular from handling a url

I have an angular web page in which I also have a twitter bootstrap carousel.
The carousel have arrow buttons to jump to the next/previous image with the following url: http://localhost:8080/#myCarousel
Whenever I click on it, it takes me to http://localhost:8080/#/
I tried removing every angular reference and just building an html static version of the page and it works ok, so I guess that the angular router is handling the url with the #myCarousel fragment.
How can I prevent this from happening?
On clicking the arrows the url changes in the address bar and the router handles the change which is the required behaviour. Use carousel directive from ui-bootstrap to implement the carousel or you can write ur custom function on click of those links
Angular uses # as the prefix for any route handled by it by default. This allows angular routes to be handled as if they are page anchors, and allows the page to update without a new browser request going to the server. Unfortunately, JQuery also uses this technique.
To avoid this conflict, you can change the prefix which is used by angular. From the angular Documentation:
$locationProvider.hashPrefix("!");
This will result in Angular links as /#! rather than /#. You can also optionally enable HTML5Mode, which uses HTML5 Push State to handle URLs without a hash at all, in browsers that support it. You should still consider adding a hash prefix as a fallback, for older browsers.

Using UIRouter templates with MVC 4 Routing

I'm trying to create an ASP MVC 4 project with Ui-Router, however I've come across a problem.
My current server-side routing configuration looks like this:
// Controller/Action route
routes.MapRoute(
name: "Default",
url: "{controller}/{action}");
// Redirect any other routes to Site/Index so AngularJS can handle routing
// Place routes above this otherwise they will be ignored
routes.MapRoute(
name: "Catch-All Redirect to Index",
url: "{*url}",
defaults: new { controller = "Site", action = "Index" }
);
And client-side
angular.module('loluk.home')
.config(['$stateProvider', function ($stateProvider) {
$stateProvider.state('index', {
url: '',
templateUrl: '/home/index'
});
}]);
Site/Index, the redirect action, simply contains the HTML file that has the ng-app directive. Any other actions/controllers will return API data, or a template. So, in my case, I have Home/Index which returns a template containing <h1>Hello, World!</h1>.
This is all fine and dandy if one of my states in ui-router requests "home/index" via templateUrl for my application. However, the problem I have now is that if I browse to http://localhost/Home/Index, I will see the template in it's raw form - rather than what I am expecting to see, which is the whole application in the Home/Index state. This makes sense as that is how I have configured it.
I initially thought "OK, well I can solve this problem by redirecting everyone to Site/Index (where the main file is stored) and using inline templates". Well, this works well, until you consider that
The HTML file containing index.html is going to get ridiculously large and contain every template
This breaks escaped_fragment crawling
So right now I am at a loss of how to make this work; I could use inlining, but that would make web pages load slowly and break SEO. I could stick with what I have.. but that will break any bookmarks that end-users create.
Making template calls a ChildActionOnly worked well until the fact that ChildActionOnly will return a server 500 (rather than a redirect), and UI-Router appears to not qualify as a "Child Action" as requesting the template through templateUrl also triggered the server 500.
I did come across this question, however it doesn't express how exactly to solve the template situation.
Another avenue I have just pursued is having a templates area that contains all of my templates, and an api area that contains all of my api details (/templates/ and /api/ respectively). This solves the whole reloading page problem, though I am still unsure of how to approach the escaped_fragment crawling from this point of view.
I've accomplished this by creating two Areas in MVC - one for API that routes to /api/ and one for Templates that routes to /templates/. AngularJS will make calls to /template/{controller}/{action} which will return a plain HTML view, and make RESTful calls to /api/{controller} for retrieving data.
It's not a perfect solution but it works.

AngularJs - Determining the next location's route in $locationChangeStart

Recently I found out about the undocumented $locationChangeStart event in AngularJS when trying to determine where in the framework I should be redirecting users to the login page if their session is invalid.
I'm listening for the event using the following:
$scope.$on("$locationChangeStart", function (event, nextLocation, currentLocation) {
// Logic goes here
});
where nextLocation and previousLocation are absolute urls to locations within the app.
My question is this: Does AngularJS expose the ability to be able to match a url against a route, much like its internal routing engine does to see if an absolute URL matches a defined route?
If not, what would be the best way to detect a route based on an absolute URL?
I located the relevant source code lines in the AngularJS github project. Here is the function that it uses to match the URL to a route:
Since this functionality is not exposed by Angular I decided to come up with a rudimentary way of matching the URL to a route since the routes I was matching were relatively simple compared to implementing the same route matching that Angular does.
It ain't pretty, but it works..

Resources