AngularJS MVC 4 routing, html5 hashbang urls - asp.net-mvc

I have angularjs and mvc4 app. For using disqus I enabled hashbang and html5Mode url.
With html5 mode, server side url rewriting needs to be fixed. otherwise a full page refresh leads to 404 error.
The entry point of my application is Index.chtml in home controller and it uses _layout.chtml (for bundling and minification.)
My webconfig route is :
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{*url}",
defaults: new { controller = "Home", action = "Index"},
namespaces: new[] { "Flashspark.Controllers" });
and my AngularJS config is:
(function () {
'use strict';
var app = angular.module('app');
// Collect the routes
app.constant('routes', getRoutes());
// Configure the routes and route resolvers
app.config(['$routeProvider', '$locationProvider', 'routes', routeConfigurator]);
function routeConfigurator($routeProvider,$locationProvider, routes) {
routes.forEach(function (r) {
$routeProvider.when(r.url, r.config);
$locationProvider.html5Mode('true').hashPrefix('!');
});
$routeProvider.otherwise({ redirectTo: '/' });
}
// Define the routes
function getRoutes() {
return [
{
url: '/',
config: {
templateUrl: 'app/thoughts/thoughts.html',
title: 'thoughts',
settings: {
nav: 1,
content: '<i class="fa fa-book"></i> Thoughts'
}
}
}, {
url: '/faq',
config: {
title: 'faq',
templateUrl: 'app/faq/faq.html',
settings: {
nav: 2,
content: '<i class="fa fa-info"></i> FAQ'
}
}
},
{
url: '/timeline',
config: {
templateUrl: 'app/timeline/timeline.html',
title: 'timeline',
settings: {
nav: 3,
content: '<i class="fa fa-arrows-h"></i> Timeline'
}
}
},
{
url: '/about',
config: {
templateUrl: 'app/about/about.html',
title: 'contact',
settings: {
nav: 4,
content: '<i class="fa fa-list fa-1x"></i> About'
}
}
},
{
url: '/thoughts/:article',
config: {
templateUrl: 'app/article/article.html',
title: 'article',
}
}
];
}
=================================================================================
THE PROBLEM I AM HAVING:
With this configuration, All the routes which are only 1 deep work without any issues
like:
/faq , /timeline
even after refresh, the url's are preserved.
However for URL's like:
/thoughts/:articleid (2 deep)
the styling for the whole app is stripped out when I refresh from this page.

You need to have to a default route for thoughts
{
url: '/thoughts',
config: {
templateUrl: 'app/article/article.html',
title: 'article',
}
}

Related

#nuxt/auth $auth.loggedIn is not reactive

I have two problems with #nuxt/auth, the first is that $auth.loggedIn is not reacting to change, I have the below code for my app and when I login or logout I have to chage the route in order for the header to reacte and change state (hide or show login/register and user info) below is my code for template.
<userdown #logout="$auth.logout()" v-if="$auth.loggedIn"/>
<div v-else>
<nuxt-link :to="localePath('/login')" class="text-white mx-4">
{{$t("links.login")}}
</nuxt-link>
<nuxt-link :to="localePath('/register')" class="text-white mx-4">
{{$t("links.register")}}
</nuxt-link>
</div>
The second one is that the redirect is not working automatically (example when login it should redirect to home page but nothing happen)
auth: {
strategies: {
local: {
token: {
property: 'token'
},
user: {
property: 'user'
},
endpoints: {
login: { url: '/api/auth/login', method: 'post' },
logout: { url: '/api/auth/logout', method: 'post' },
user: { url: '/api/auth/user', method: 'get' }
}
}
},
redirect: {
login: '/login',
logout: '/',
callback: '/login',
home: '/'
}
}
I've encountered the same issue in production. Locally, everything works as expected. Anyways, I've ended up using:
v-show="$store.state.auth.loggedIn"

Angular routing redirect to that same page all time

I have problem with routing in my application. I use Angular2+ and WebApi2. I created Angular from quickstart project and I added it to my WebApi solution. After configurating it, I launched first time app allthing work fine. Problems appear after I added routing. When I try to navigate to link included in routing table, the browser redirect me all time to one component. I searched how to deal with it but I didn't find anything. Below I present codes and file names:
RouteConfig.cs
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{*url}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
Share _Layout.cshtml
<script src="/node_modules/core-js/client/shim.min.js"></script>
<script src="/node_modules/zone.js/dist/zone.js"></script>
<script src="/node_modules/systemjs/dist/system.src.js"></script>
<script src="~/src/systemjs.config.js"></script>
<script>
System.import('./src/main.js').catch(function (err) { console.error(err); });
</script>
system.config.js
packages: {
app: {
defaultExtension: 'js',
meta: {
'./*.js': {
loader: '/src/systemjs-angular-loader.js'
}
}
},
rxjs: {
defaultExtension: 'js'
}
}
app.module.ts
import { NgModule } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import { RouterModule, Routes } from '#angular/router';
import { AppComponent } from './app.component';
import { HomePage } from './HomePage.component';
import { Test } from './Test.component';
import { HttpModule } from '#angular/http';
const appRoutes: Routes = [
{ path: '', redirectTo: 'home', pathMatch: 'full' },
{ path: 'home', component: HomePage },
{ path: 'test', component: Test },
{ path: '**', component: HomePage }
];
#NgModule({
declarations: [
AppComponent, HomePage, Test
],
imports: [
BrowserModule,
HttpModule,
RouterModule.forRoot(appRoutes)
],
providers: [],
bootstrap: [HomePage]
})
export class AppModule { }
Index.cshtml
<home-page></home-page>
Answer: all problems are caused by #RenderBody(). When I moved <home-page></home-page> under #RenderBody() all is working fine.

AngularJS Devise authorization

I'm trying to add authorization functionality to my app, sow for example when I want to go to /admin/posts/create it will redirect me to /login if I'm not already logged in.
My angular module
angular.module('flapperNews', ['ui.router', 'templates', 'ngResource', 'formly', 'formlyBootstrap', 'ngMessages', 'Devise'])
I'm using this service
angular.module('flapperNews')
.factory('authorization', [
'$state',
'Auth',
'$location',
function($state, Auth, $location) {
return {
authorize: function() {
var isAuthenticated = Auth.isAuthenticated();
if (isAuthenticated === false) {
$state.go('login');
}
}
};
}
]);
These are my routes
$stateProvider.state('home', {
url: '/',
controller: 'PostsCtrl',
templateUrl: 'posts/_posts.html'
});
$stateProvider.state('admin', {
abstract: true,
resolve: {
authorize: ['authorization', function(authorization) {
return authorization.authorize();
}]
},
template: '<div ui-view />'
});
$stateProvider.state('postsCreate', {
parent: 'admin',
url: '/admin/posts/create',
controller: 'PostsCtrl as vm',
templateUrl: 'posts/create.html'
});
Through this link I'm trying to access route where I shouldn't be able to get
<a ui-sref="postsCreate" class="btn btn-primary">Create a post</a>
I don't get any errors and I end up in section which I should be able to access.

Deep linking to AngularJS app doesn't work consistently... what's up?

I have an AngularJS app that uses ui.route. This is hosted within ASP.NET MVC, which is intended to only serve a single View that points to this app and ideally links into it as needed. My state provider looks like the following:
$stateProvider
.state('root', {
url: '',
abstract: true,
templateUrl: 'root.html'
})
.state('internal', {
url: '/internal/',
abstract: true,
templateUrl: 'root.html'
})
.state('root.home', {
url: '/',
templateUrl: 'rootHome.html'
})
.state('root.about', {
url: '/about',
templateUrl: 'rootAbout.html'
})
.state('internal.home', {
url: '/internal/home',
templateUrl: 'internalHome.html'
});
Within my app.js, I also specify that html5Mode is set to true and have this router provider in there (though it might be unnecessary):
$locationProvider.html5Mode(true);
$urlRouterProvider.when("", "/");
My RouteConfig.cs looks like the following:
public static void RegisterRoutes(RouteCollection routes)
{
routes.MapRoute(
name: "Home",
url: "home",
defaults: new { controller = "Home", action = "Index" });
routes.MapRoute(
name: "About",
url: "about",
defaults: new { controller = "Home", action = "Index" });
routes.MapRoutes(
name: "InternalHome",
url: "internal/home",
defaults: new { controller = "Home", action = "Index" });
routes.MapRoutes(
name: "Root",
url: "",
defaults: new { controller = "Home", action = "Index" });
}
Now, if I visit http://localhost:123/ by typing it into my browser URL bar, I will get to the rootHome in my app (within the root.html file) just as I expect. If I visit http://localhost:123/about the browser URL bar, I'll find myself on the About page as I expect.
If I visit http://localhost:123/internal/home, I'll find myself at this link, but looking at a blank page. I can put a breakpoint in Chrome on the $stateChangeStart event it won't even get hit.
If I visit http://localhost:123/nonexistantpage, I'll find myself on a blank page here too.
First, how do I set up my routes so that if I type to an address that isn't a child from the root abstract state, it will still show the proper state? Is it related to the parents at all or is there something else I'm missing?
Second, how can I capture all those routes that I haven't explicitly given (at least in terms of the first and second arguments of the path after the host (e.g. /internal/home) and redirect all of those to the Home controller and the Index action, but in a way that it points to the root on the Angular application?
Thanks!
If you try going to internal/internal/home you will arrive at the expected route, here is why, you have the internal state:
.state('internal', {
url: '/internal/',
abstract: true,
templateUrl: 'root.html'
})
Which has a url of /internal, now internal.home, a child state of internal, should not be declaring the /internal bit in it's url again, ui.router realises form the internal prefix in inernal.home that this is a child state of internal, and will automatically append /internal to the child states URL, so your internal.home state should have the following url:
.state('internal.home', {
url: '/home',
templateUrl: 'internalHome.html'
})

How to fetch index data in Angular using rails server

I am starting with Angularjs + rails backend and trying to fetch users data from the server - equivalent to to controller/index action in rails.
I have followed several tutorials and found this code as the most clear one....
questions
1. How to properly link angular module into views ?
2. How to fetch data using typeahead and sample data in this post.
here is plunker version of the code
Code is as follows:
views
<div ng-app='users'>
<div class='container-fluid' ng-controller="UsersIndexCtrl">
<pre>Model: {{result | json}}</pre>
<input type="text" ng-model="result" typeahead="suggestion for suggestion in users($viewValue)">
</div>
</div>
controller
<script>
// ['ui.bootstrap', 'ngResource'])
var app = angular.module('users', ['ui.bootstrap', 'ngResource']);
// factory - resources users
// equivalent to rails users/index
app.factory('Users', function($resource) {
return $resource('/users.json', {}, {
index: { method: 'GET', isArray: true}
});
});
// factory - user resource
// equivalent to users show, update
app.factory('User', function($resource) {
return $resource('/users/:user_id.json', {}, {
show: { method: 'GET' },
update: { method: 'PUT' }
});
});
// controller - users/ index
// equivalent to rails controller rails/index
var UsersIndexCtrl = function($scope, users) {
$scope.users = users;
};
</script>
and I am stack here, as I am getting this error:
Error: Unknown provider: usersProvider <- users
The goal of this code is to use typehead and provide data to the user.
My '/users.json' url is as follows:
[{"full_name":"Lia Cartwright","id":1,"image_url":"no-icon.jpg"},{"full_name":"Hilton Turner","id":2,"image_url":"no-icon.jpg"},{"full_name":"Aubrey Barrows","id":3,"image_url":"no-icon.jpg"},{"full_name":"Donnie Kris","id":4,"image_url":"no-icon.jpg"},{"full_name":"Eryn Rath","id":5,"image_url":"no-icon.jpg"},{"full_name":"Caden Fay","id":6,"image_url":"no-icon.jpg"},{"full_name":"Arlie Tromp","id":7,"image_url":"no-icon.jpg"},{"full_name":"Rico Klein","id":8,"image_url":"no-icon.jpg"},{"full_name":"Gudrun Dare","id":9,"image_url":"no-icon.jpg"},{"full_name":"Nathan Langworth","id":10,"image_url":"no-icon.jpg"},{"full_name":"Deanna Stroman","id":11,"image_url":"no-icon.jpg"},{"full_name":"Shania Stroman","id":12,"image_url":"no-icon.jpg"},{"full_name":"Lupe Harvey","id":13,"image_url":"no-icon.jpg"},{"full_name":"Constance Armstrong","id":14,"image_url":"no-icon.jpg"},{"full_name":"Reagan Tremblay","id":15,"image_url":"no-icon.jpg"},{"full_name":"Murray Sipes","id":16,"image_url":"no-icon.jpg"},{"full_name":"Dandre Klocko","id":17,"image_url":"no-icon.jpg"},{"full_name":"Haylee Monahan","id":18,"image_url":"no-icon.jpg"},{"full_name":"Florence Harber","id":19,"image_url":"no-icon.jpg"},{"full_name":"Norberto Hoppe","id":20,"image_url":"no-icon.jpg"}]
You must inject Users not users, it's case sensitive.
Side notes:
No need to create two models, replace:
app.factory('Users', function($resource) {
return $resource('/users.json', {}, {
index: { method: 'GET', isArray: true}
});
});
app.factory('User', function($resource) {
return $resource('/users/:user_id.json', {}, {
show: { method: 'GET' },
update: { method: 'PUT' }
});
});
with:
app.factory('User', function($resource) {
return $resource("users/:id", { id: '#id' }, {
index: { method: 'GET', isArray: true, responseType: 'json' },
show: { method: 'GET', responseType: 'json' },
update: { method: 'PUT', responseType: 'json' }
});
})
Other thing, in your controller, do:
var UsersIndexCtrl = function($scope, User) {
$scope.users = User.index();
};
Last thing, consider using: Angular Rails resource

Resources