Using angular route url formation #!/ issue - javascript

I'm following the course Staying Sharp With AngularJs.
The course put some code in app.ts:
angular
.module("NoteWrangler", ["ngRoute"])
.config(function ($routeProvider: angular.route.IRouteProvider) {
$routeProvider
.when("/notes", {
templateUrl: "templates/pages/notes/index.html"
});
});
Ok, so the links are formed like this:
somedomain/index.html/#/myPage
But when I try my urls are build like this:
somedomain/index.html#!/myPage
Why the difference?
Between ".../#/..." and "...#!/..." I mean.
How can I change between these two?

Why the difference?
Old versions of Angular used #.
Some years ago, it was changed to use #! so it would play nicely with the (now deprecated) Google Ajax crawling spec.

In angular it's called a shebang and works closely with your ngroute class. This topic contains some elaborate answers

Related

Angular routes contain #! in the url instead of # [duplicate]

This question already has answers here:
angularjs 1.6.0 (latest now) routes not working
(5 answers)
Closed 6 years ago.
Recently I have noticed that when using ngRoute module in an AngularJS app, the route contains #! in the URL, which was earlier just the #.
For example, www.webiste.com/#/login becomes www.website.com/#!/login
I have to enable the html5Mode and also disable the requireBase which removes the base as a whole using the code,
$locationProvider.html5Mode({
enabled: true,
requireBase: false
});
and the URL changes to www.website.com/login which works fine but is misleading and is not what Angular SPA URLs look like.
If I do not enable the html5Mode, the URL is encoded and I cannot get around it. So www.website.com/#/login becomes www.website.com/#!/#%2Flogin (Notice the later / is encoded as %2F).
Is this a change implemented by the developers for some specific purpose? What difference does it make? What changes do I need to make to my app to keep it working? Am I doing something wrong?
Github issue: https://github.com/angular/angular.js/issues/15547
It's called the hash bang.
For a while Twitter was using the same thing. It allows for AJAX calls and let search engines know your path without using a "real" path. It's considered obsolete though.
https://developers.google.com/webmasters/ajax-crawling/docs/getting-started
There is another stackoverflow answer about that:
Doing links like Twitter, Hash-Bang #! URL's
Update:
One of the reasons for not having a need for the hash bang anymore is that we can push the history state without a page reload. Something so called "one page" websites, like React, do.

How to avoid angular loading multiple times when adding directive?

In my app.js file I have the app being created like this:
angular
.module('AngularRails',[
'ngRoute',
'templates',
'firebase',
'mySharedElements',])
i'm attempting to load a directive in one of my views like this:
angular.module("mySharedElements", []).directive('userItem', [function()
However, this doesn't work? I receive an error in Developer Tools stating that Angular attempted to load multiple times and thus the tab locks up. I tried solving that but adding 'mySharedElements' as you can see from the code but that didn't work. From various sites I've read, I'm doing it the right way so I'm confused what I'm doing wrong because obviously I am.
Thank you for your help, I appreciate it. :)
UPDATE:
I double checked and i'm not using ng-app more than once. The error only occurs when I attempt to go to the page where the directive is being used.
I update the app.js file and the directive to this to see if that fixed it:
app.js:
angular
.module('AngularRails',[
'ngRoute',
'templates',
'firebase',])
.config(function ($routeProvider, $locationProvider) {
// etc.
directive:
angular.module("AngularRails").directive('userItem', [function() {
// etc.
And that fixed it. It looks like I was suffering from a combination of this and I had the templateURL wrong in the directive and it was screwing stuff up. THANKS!
angular.module("mySharedElements", []) will create a new app because you are passing second argument to module with empty dependencies.
If you have already created the app somewhere else in your code then you just need a reference to it. Change it to angular.module("mySharedElements").directive then it should be fine.
However looking at the error description mentioned in the question Angular attempted to load multiple times, it looks like you have multiple references to angular js on your page. Try to check for that and remove multiple references.

Debugging Unknown provider in minified angular javascript

I'm having a hard time trying to pinpoint which, of the very many, methods I have in my angular app that would be causing the error:
Uncaught Error: [$injector:unpr] Unknown provider: nProvider <- n
This only happens once the javascript has been bundled & minified by ASP.Net.
I have ensured that all the controllers, and any other DI, is using the minification-safe method, I.E My controllers/service etc are using the method:
appControllers.controller('myCtrl', ['$scope', function($scope){
//......
}]);
I've gone through every JS file in our app - there are a lot... and can't find anything that violates this way of injecting dependencies - though there must be one somewhere...
Is there a better way to pinpoint which method could be causing this error?
Thanks
For anyone else struggling with this problem, I found an easier solution. If you pull open your developer console (on chrome) and add a breakpoint where angular throws the error:
Then, on the stack trace on the right, click on the first "invoke" you see. This will take you to the invoke function, where the first parameter is the function angular is trying to inject:
I then did a search through my code for a function that looked like that one (in this case grep "\.onload" -R public), and found 8 places to check.
For anybody reading this, using Angular 1.3
You can now use Angular's ng-strict-di check like this:
<div ng-app="some-angular-app" ng-strict-di>
...
</div>
This will give you an appropriate error message if you didn't load your dependencies using the array syntax.
I had the same problem and I found a solution that could be helpful for the rest. What I propose is basically what I saw in the comments and docs. If you are using Angular 1.3.0 or above, you can use this:
<html ng-app="myApp" ng-strict-di>
<body>
I can add: {{ 1 + 2 }}.
<script src="angular.js"></script>
</body>
</html>
In my case, I have everything within a file app.js so the only thing I need to do for finding my DI problems is to add this little code at the end:
angular.bootstrap(document, ['myApp'], {
strictDi: true
});
It's better documented in Angular Docs
I hope that helps. Good luck!
As mentioned in the comments, These are the steps I took to try and find my JS error.
If there is another, easier, solution, please feel free to post it and I may mark it as accepted.
Trying to debug minified code is a nightmare.
What I eventually did was copy my minified javascript, directly from the inspector in Chrome.
I then pasted the JS into http://www.jspretty.com/ - I had tried http://jsbeautifier.org/ but found their site froze with such large JS code.
Once it was 'pretty-fied' I created a test.js file in my solution and pasted the, now easier to read code, into it.
Quick step to comment out the #script tag in my _layout and add a link to the test.js file and I was ready to debug a now, far easier to read, chunk of Javascript.
It is still pretty awkward to traverse the call stack, though now you can see actual methods it makes it far less impossible.
Something that helped me solve this (finally!) was actually already in the angular docs! If you add the ng-strict-di attribute to your code wherever you define your ng-app, angular will throw a strict warning so you can more easily see what's going on in development mode. I wish that was the default!
See the argument list at the bottom of the ngApp docs.
https://docs.angularjs.org/api/ng/directive/ngApp
The way this works for me is the following:
1) have two test specification html files (unit test) minimized and plain
2) make sure the bundling of the files are in the same order as the plain spec file (JS script reference)
3) make sure to explicitly declare all dependencies (array or $inject declares see http://www.ozkary.com/2015/11/angularjs-minimized-file-unknown-provider.html)
When there is a mistake on the unit test (miminized reference) file, I can compare and make sure the reference of the files is in the correct order as the working file.
hope that help.
I had the similar issue and used lots of time to investigate and figured out it was the Chrome extension Batarang that was injecting the bad code and error in Angular looked exactly the same. It's really a pity it's so hard to find what exactly is causing the problem.
I had the similiar issue too. The solution is exacly the answer from ozkary point 3, that is to make sure to explicitly declare all dependencies including "resolve" part of your route.
Below is my code.
when('/contact/:id', {
controller: 'contactCtrl',
templateUrl: 'assets/partials/contact.html',
resolve: {
contact: ['ContactService', '$route', function(ContactService, $route) {
return ContactService.getContactDetail($route.current.params.id);
}]
}
})
For those who's bootstrapping their angularjs app.
angular.bootstrap(body, ['app'], { strictDi: true });
Don't forget to debug in non minified code and you should be able to figure out pretty quickly the malformed dependency injection.
The malformed injection is usually formatted like this :
...
.run([ function(ServiceInjected){
...
But should look more like this
...
.run(['ServiceInjected', function(ServiceInjected){
...
This is tested in angularjs 1.7.2

AngularJS hashbang mode duplicating URL path

I'm working on a AngularJS app with a Laravel 4 backend. I've recently had to switch to hashbang mode from html5 in the $locationProvider service in order to support IE. The application works, but the URL paths are duplicating after the hashbang in all browsers.
Ex. - http://domain.com/resources/resource is displaying as http://domain.com/resources/resource#!/resources/resource
I've listed my main module below. Any assistance will be greatly appreciated.
angular.module('agent', ['agent.controllers', 'agent.directives', 'ngRoute']).
config(['$routeProvider', '$locationProvider',
function($routeProvider, $locationProvider) {
//
$locationProvider.hashPrefix('!');
$routeProvider
.when('/resources/resource', {
template: templatePath,
controller: 'ResourcessController'
})
.otherwise({redirectTo: '/resources/resource'});
}]);
I have seen this issue a number of times. The only thing I have found as a work around is to forward to the angular page directly. Take the following as an example:
http://example.com/product/1234#/1234
If this came from another page, you could instead link directly to the hash link:
http://example.com/product#/1234
Now the URL doesn't repeat and routine still works as expected. Basically the point here is to route based on whether this is a server/controller page versus a client/angular page. I'm not sure that this really is the best answer since I am still learning angular. Hopefully others have excellent suggestions as well!

Misunderstanding of Single-Page Routing in Angular

I think I have a fundamental misunderstanding about the way angular intercepts my routes in a single-page application.
My problem, I think, is pretty simple. When I enter the url:
localhost:3000/streams/
I would like to load the 'streams' page. The way I thought it works is as follows:
My express server receives the request, and answers with a layout.
app.get('/streams/',function(req,res){
res.render('layout');
})
My layout page is rendered. It calls a client app.js and has ng-view.
Angular intercepts the '/streams/' path, and then makes a call for the 'streams' template. Like this:
$routeProvider
.when('/',
{
templateUrl: '/templates/mainpage'
}
)
.when('/streams/',
{
templateUrl: '/templates/streams'
}
)
For some reason, reality is very very different.
When I load '/streams', angular retrieves /templates/streams, and
when I load '/streams/, angular retrieves /templates/mainpage.
Why?
This misunderstanding has been trolling me for days now...
Any help will be rewarded with 5 quanta of good energy.
Thanks.
It turns out that the real issue was a little different.
It's not, as was described, that Angular didn't know that I'm referring to 'streams', when I load 'streams/', it's that html had a relative base.
Basically, this relative base made it seem as though I have already found a template, namely, '/streams', and am now retrieving another one, namely, '/'. This issue can be simply resolved by adding the root base in your html.
<base href="/">
This should do it.

Categories

Resources