Angularjs route html5Mode direct url in .net MVC - angularjs

I've seen a couple of similar questions/answers, but I still seem to be missing something. Everything works fine until I refresh the page or go to a URL directly.
I can either get a 404 or create the same url in mvc, but then it serves up the partial only on refresh and doesn't include the layout page.
There were a couple that suggested changing the MVC routing to:
routes.MapRoute(
name: "Application",
url: "{*url}",
defaults: new { controller = "Home", action = "Index" }
);
When that is implemented, it means I can't access any other URL on the site normally and unless I am missing something, basically everything has to be put into a rest api or write a custom route for every url. Neither sounds very good.
So how can I have an html5 url (no hash tags in valid browsers) with angularjs and be able to browse to eg. Home/About or Home then click a link to About and have them show up the same with the same base layout page?

This may not be the best answer, so if anyone has any better ideas, please comment, otherwise maybe this will help someone else.
I realized that the MVC Ajax directive didn't detect angular calls, so I couldn't automate that side.
So in angular I did something like
.when('/Home/Contact', {
templateUrl: '/Home/NgContact'
In my MVC controller I have 2 actionresults:
public ActionResult NgContact(){
ViewBag.IsFromNg = 1;
return Contact();
}
public ActionResult Contact() {
return View("Contact"); //have to type in name, may look for NgContact.cshtml
}
Finally on any views these may call I put:
#if (ViewBag.IsFromNg == 1){ Layout = null; }
So there is a little repetition with each Actionresult having 2 copies, 1 for a full page load and 1 for any calls angular makes, but only 3 extra lines each.

Related

Angular: Multiple templates for single URL?

I have a 'manager' panel which is used by users of all roles (admin and user currently).
The main problem is that I want to restrict any admin HTML views from being loaded (I will do this as a simple check on the backend, and will return 401 if they're not authorized to load the template). There are a bunch of things in the HTML I need to hide.
My problem is that means there are now 2 views for several sections.
So /settings while a user will show an entirely different view as /settings when you're an admin.
The controller will actually be shared, because the controller code is very close, but the HTML is very different.
I am currently using angular-router but I also checked out ui-router, I just have no clue how to structure either. I've spent a good bit of time looking at UI router, and while it is amazing looking I don't know the best way to lay it out.
I have about 10 routes/views that need to belong to each role, that will be different.
How about emitting a global variable says the current user is admin:
<script type="text/javascript">window.isAdmin = true</script>
And then in the route definition check for that variable:
...
when('/setting', {
templateUrl: isAdmin ? 'templates/admin/setting.html' : 'templates/user/setting.html',
controller: 'SettingController'
})
...
The other way around is to have the web server serve different view for the same view URL, based on user's role. As I understand you can do this already, right?
app.get('/templates/setting.html', function(req, res) {
if (user.role === "admin") {
res.send(...);
} else {
res.send(...);
}
});

Angular choose html file based on url parameter

I don't know very much about angular, and I'm trying to get the hang of best practices regarding the use of URL routing and states and whatnot. I've got a scenario. It's a simple question, but I'm using it to get a handle on what's available to me.
Say that I have two completely separate web pages for displaying information on Ford cars and Toyota cars. When you access the pages, all you have is the car ID number, so you just hit the url "cars.com/info/id:198273918273". What's the best way, using angular.js, to immediately strip the id number from the url, use it to look up the car make, and display the appropriate html page, all without changing the url displayed at the top of the browser?
you can use functions in your route templateUrl
.when('/your_url/:car_id', {
templateUrl: function(attrs){
//Example of the login yours will be complex i guess :P
if(attrs.car_id == 1) { return 'template_ford.html' }
if(attrs.car_id == 2) { return 'template_toyota.html' }
},
controller : 'someController'
})
and by that your template can be chaged before the page is rendered and no need to send the user to a different url
Assuming that you are using angular-ui router
$stateProvider
.state('car-get', {
url:'/info/{car_id}/',
controller: ['$scope','$stateParams',function($scope,$stateParams){
var car_id = $stateParams.car_id;
// now you can get your car info
// and bind it to your template.
$scope.car = myservice.getcarinfo(car_id) //Here goes your service or your api calls to get car info
}],
templateUrl: 'path_to_detail_car_page.html',
});
Here is a good begginer tutorial for Angular-ui Router

AngularJS register controller once

That's what I'm doing. There is application with pages and different controls that may be put on pages by site admin/editor. All pages share one ng-app defined on master page. All controls are supplied with .js files with angular controllers. Let's suppose that I have an image gallery block:
<div ng-controller='imageGalleryCtrl'>
do something amazing here
</div>
<script src='imageGallery.js'></script>
Inside script there is a simple controller registration like:
angular.module('myApp').controller('imageGalleryCtrl', ... );
So. If I have 10 image galleries, I'll execute controller registration 10 times. It looks like this will work, but hell - I don't want it to be so =)
For now I just have all controls' scripts registration on a master page, but I don't like it as well, because if there is no image gallery on a page, I don't want it's script be downloaded during page load.
The question is - is there any proper way to understand if controller have been registered in a module already and thus prevent it from re-registering?
---------------
Well, though I've found no perfect solution, I must admit that the whole idea isn't very good and I won't think about it before my site will grow too big to assemble whole angular app on master page.
You should declare your controller but once. Instead of having one controller per gallery, have your single controller handle all image galleries. The controller should make a request to the REST backend to fetch the images of the desired gallery.
I see that instead of ng-view, you're using the ng-controller directive, indicating that probably you're not using Angular's routing. Try switching to using routes.
Have a look at Angular.js routing tutorial. It shows you how to use the ngRoute module. Then, in the next chapter, the use of $routeParams is described. Via the $routeParams service, you can easily say which gallery should be displayed by providing its ID in the URL; only one controller will be necessary for all your galleries.
If you really must check whether a given controller has been declared, you can iterate through the already declared controllers (and services... and pretty much everything else) by checking the array angular.module("myApp")._invokeQueue. The code would probably look something like this (not tested!):
var isRegistered = function(controllerName)
{
var i, j, queue = angular.module("myApp")._invokeQueue;
for (i = 0, j = queue.length; i < j; ++i) {
if (
queue[i][0] === "$controllerProvider"
&& queue[i][1] === "register"
&& queue[i][2][0] === controllerName
) {
return true;
}
}
return false;
};
Bear in mind however that while this may (or may not) work, it's far from being the correct thing to do. It's touching Angular's internal data that's not meant to be used in your code.

How to redirect in AngularJS without rendering template

I'm trying to redirect to an external page from my AngularJS file if the user enter a special url, for instance /test. I have gotten this to work in multiple different ways but all the different ways show a "flash" of the design from index.html. I would like it to go direct without rendering any html at all!
Here is a fiddle of one of the examples, but it is not the best place to test since I cant redirect from jsiffle.net :-)
$routeProvider.when("/test", {
resolve: {
controller: "Redirect"
}
});
Also had one example where I just used a controller and a empty template in the routing, but it gave me the same result.
Any ideas?
If you know the URL(routing) then use,
$location.path('the_URL');

Backbone.js change url without reloading the page

I have a site that has a user page. On that page, there are several links that let you explore the user's profile. I'd like to make it so that, when one of those links is clicked on, the url changes, but the top third of the page containing the user's banner doesn't reload.
I'm using Backbone.js
I have a feeling that I'm in one of those situation where I have such a poor understanding of the problem I'm dealing with that I'm asking the wrong question, so please let me know if that appears to be the case
My mistake was assuming that there was a special, built-in way of doing this in backbone. There isn't.
Simply running the following line of code
window.history.pushState('object or string', 'Title', '/new-url');
will cause your browser's URL to change without reloading the page. You can open up the javascript console in your browser right now and try it with this page. This article explains how it works in more detail (as noted in this SO post).
Now I've just bound the following event to the document object (I'm running a single page site):
bindEvents: () ->
$(document).on('click', 'a', #pushstateClick)
pushstateClick: (e) ->
href = e.target.href || $(e.target).parents('a')[0].href
if MyApp.isOutsideLink(href) == false
if e.metaKey
#don't do anything if the user is holding down ctrl or cmd;
#let the link open up in a new tab
else
e.preventDefault()
window.history.pushState('', '', href);
Backbone.history.checkUrl()
See this post for more info.
Note that you CAN pass the option pushstate: true to your call to Backbone.history.start(), but this merely makes it so that navigating directly to a certain page (e.g. example.com/exampleuser/followers) will trigger a backbone route rather than simply leading to nowhere.
Routers are your friend in this situation. Basically, create a router that has several different routes. Your routes will call different views. These views will just affect the portions of the page that you define. I'm not sure if this video will help, but it may give you some idea of how routers interact with the page: http://www.youtube.com/watch?v=T4iPnh-qago
Here's a rudimentary example:
myapp.Router = Backbone.Router.extend({
routes: {
'link1': 'dosomething1',
'link2': 'dosomething2',
'link3': 'dosomething3'
},
dosomething1: function() {
new myapp.MyView();
},
dosomething2: function() {
new myapp.MyView2();
},
dosomething3: function() {
new myapp.MyView3();
}
});
Then your url will look like this: www.mydomain.com/#link1.
Also, because <a href=''></a> tags will automatically call a page refresh, make sure you are calling .preventDefault(); on them if you don't want the page to refresh.

Resources