Misunderstanding of Single-Page Routing in Angular - javascript

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.

Related

AngularJS - Navigating inside a directive/component

I have a component (directive) which should be used as a stand alone component by other applications (bower component, for example). I want to add navigation inside my directive (using ngRoute or ui-router) - but this could conflict with the host application navigation (if it uses one).
For example:
Main application has a routing for my component:
http://address.com/route-to-my-component
Now, inside my application I should have an inner route (I am not aware of the main application routing):
$routeProvider.
when('/route1', {
template: `<comp1></comp1>`
}).
when('/route2', {
template: `<comp2></comp2>`
}).
otherwise({
redirectTo: '/route1'
});
There are several problems with this solution:
Main application might not recognise my routing, so it will fall to its default route.
I cannot know what is my parent router solution, which makes it hard for me to configure my own routes.
Is there a solution to this problem?
Thanks
EDIT
I ended up with two optional solutions:
Using angular-widget, which is a great solution but is too complex for my case (it will be an overkill for me)
Using history.pushState.
So, I implemented the second option, like this:
When the use click the navigation (inside my component), I do pushState:
history.pushState({someData}, 'some-title', url );
And I added an event for user's pressing the back button:
window.onpopstate = function(event) {
//My back logic here
}.bind(this);
It is kind of hackey solution but it was perfect to my situation and needs.

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.

How can I get an environment specific URL into my AngularJS controller?

Situation
Our web project in production has a root URL like so: http://example.com. Our local dev instances (don't ask me why) default to a URL like so: http://localhost/SubDir where SubDir is a placeholder for the actual virtual subdirectory in IIS.
This is not the problem. As much as I would like to abolish that subdirectory URL thing, that is only illustrating a problem. If we were to move to a different domain or URL later on that incorporates a subdirectory URL, it would not be a problem for all of the instances in code where we use helpers to generate URLs (e.g. #Url.Action("GetUpdates"), etc).
Currently we have quite a bit of javascript that has been moved to external .js files that uses jQuery to get URL strings from hidden inputs whose values have been set to a Url helper like above. This is not too bad, it works.
The Problem
AngularJs. It is not the problem. It has however uncovered the problem. We want to remove jQuery from the project eventually. Right now, I am getting the URLs in my controller using jQuery (I am willing to break rules in an effort to get something out on time if I can be reasonably assured I will be given time to fix it later). It is now time to fix it, and I am at a loss.
Between the two environments, I get the following from #Url.Action("GetUpdates"):
On http://example.com/: => /Contest/GetUpdates
On http://localhost/SubDir: => /SubDir/Contest/GetUpdates
The Question
How can I get an environment dependent URL into my AngularJs controller without the use of the helpers in that controllers file? I originally thought it might be as simple as using the hidden inputs and setting the ng-model, but does not seem to have worked. I have also looked into using an extension, RazorJS, but hoped that there would be a better way of doing it more inline with the Angular paradigm.
Anyone have any ideas? How do you get URLs into your controllers?
If you are able to change your environment config server side you can put the variable inline in a module constant. Then you can inject into your main app.
Here's a Plunker
// inline
angular.module('Preload',[]).contstant('CONFIG', {'BASE_URL':'http://localhost/foo'});
// inject
var app = angular.module('MainApp', ['Preload']);
// Controller
app.controller('MainCtrl', function($scope, CONFIG) {
$scope.base_url = CONFIG.BASE_URL;

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!

Angular sub-views

I google a bit about the topic but I couldn't get a clear answer on the subject, so apologies if this seems a pretty beaten down question. I've started with Angular not long ago, and I really want to be on the good path.
The application is bootstraped by app.js which defines the routes in the configuration. The index.html has a body with a ng-app directive an just a div inside with a ng-view.
$routeProvider
.when('/', {
templateUrl: 'views/main.html',
controller: 'MainController'
})
.otherwise({
redirectTo: '/'
});
This main.html and controller are the bulk of the app, which is quite simple.
Now I wanted to have a header, which either shows Login or the information from the user. I though that should be another Controller and another View, since the header should encapsulate all that code instead of polluting the main view.
What should I do?
I could remove the ng-app and create two different controllers for the header and the main app, but then I don't know how to associate each view to each ng-controller like the routeProvider is doing, although if I don't mind writing all the html inline, this should work. I would also lose routing which I don't really want to.
I could just create a ng-controller=headerController inside the app and still have the code inline. Is there an option to associate a template with a controller without the route definition?
What I'm currently going to do until I have a better option is to add all of this logic to the mainController. I just feel that I'm building big blocks instead of small ones that I can just compose. Imagine I do three more routes that need a header. Using option 1) or 2) I would have to write the template html for the header again in those views.
I would appreciate any links or help for this matter, I'm really curious how to approach this in a module fashion.
Thank you in advance.
I could remove the ng-app and create two different controllers for the header and the main app, but then I don't know how to associate each view to each ng-controller like the routeProvider is doing, although if I don't mind writing all the html inline, this should work. I would also lose routing which I don't really want to.
You will just write two different modules which have the same routeConfig and things will probably work. However, I do not think that it is the best solution in this case.
To answer your second question:
I could just create a ng-controller=headerController inside the app and still have the code inline. Is there an option to associate a template with a controller without the route definition?
You can use ng-include to include the template:
<body ng-app="MyApp">
<section ng-include="'header.html'" ng-controller="HeaderController"></section>
<ng-view></ng-view>
</body>
Moreover, you can keep the template inline by using either the $templateCache or by using <script> tag.
You can use ng-include to insert your template. I personally like to use ui-router

Categories

Resources