Dynamic variable in URL in AngularJS - angularjs

I have an Angular app which has several dynamic fields, each of these fields are changed updated based on config which comes from a backend database.
In order to control what config is used I need to dynamically switch a single variable - I've decided that the URL is the best way to set/switch the variable as there need to be multiple permutations of the site based on the URL so:-
/:dynamicVariable/
I'm looking for some guidance as to whether this is the best way to do it and what the best way to do it would be? I'm struggling as I don't want to have to set each route for each section like this /:dynamicVariable/homepage /:dynamicVariable/about-us etc etc. Ideally the core module checks it and sets it but the routing ignores it so /:dynamicVariable/ becomes the root.
Hope that makes sense, thanks in advance for your help.

I ended up doing this by using ui.router and nesting states within an abstract parent state which held the client, like so :-
.state('rootClient', {
abstract: true,
url: '/:client',
templateUrl: 'app/layout/layout.html',
controller: 'Layout',
controllerAs: 'layout',
noClient: false,
resolve: {
client: function ($stateParams, ClientService) {
return ClientService.getClient($stateParams.client);
}
}
})
.state('rootClient.home', {
url: '/homepage',
views: {
'content': {
templateUrl: 'app/homepage/homepage.html',
controller: 'Homepage',
controllerAs: 'home'
}
}
});
This way all the routes are under the parent route, I also added a resolve to make sure the client exists before moving to the route. Hopefully this will help someone else down the line.
Cheers

Related

Multiple named views with dynamic routing in angularjs

Edit: Here is the complete code at Plunker. Though I can not c anything in execution but same code working at local. However gives a console error though
It all works perfect. But due to :id in /news/:id/, i am getting jquery/angular errors in console which can not be tracked anywhere in my code
I can not c What i am doing wrong.
Edit: Solved plunker https://plnkr.co/edit/FWcuBgGpVdMj3CroFrYJ
First of all you are trying to use ui-router but you're including ngRoute script in your plunker. Change it to
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.3.1/angular-ui-router.min.js"></script>
Then everything should work fine!
I suggest you a few changes...
1. Use ui-sref instead of href because it's much easier to define
ui-sref="post({id:1})" which turns into href="#/news/1"
If you would like to change url some day, then you will have to just change your route file, not each href.
$stateProvider
.state('post', {
url: "news/:id"
or
$stateProvider
.state('post', {
url: "archive/:id"
or
$stateProvider
.state('post', {
url: "whatever/:id"
2. Use abstract state
In your example it's a way better to define abstract state which holds header, content and footer - it's a typical use case.
ui-router
Abstract States
An abstract state can have child states but can not get activated
itself. An 'abstract' state is simply a state that can't be
transitioned to. It is activated implicitly when one of its
descendants are activated.
Some examples of how you might use an abstract state are:
To prepend a url to all child state urls. To insert a template with
its own ui-view(s) that its child states will populate. Optionally
assign a controller to the template. The controller must pair to a
template. Additionally, inherit $scope objects down to children, just
understand that this happens via the view hierarchy, not the state
hierarchy. To provide resolved dependencies via resolve for use by
child states. To provide inherited custom data via data for use by
child states or an event listener. To run an onEnter or onExit
function that may modify the application in someway. Any combination
of the above. Remember: Abstract states still need their own
for their children to plug into. So if you are using an
abstract state just to prepend a url, set resolves/data, or run an
onEnter/Exit function, then you'll additionally need to set template:
"".
Here's a plunker which shows how I would do it.
https://plnkr.co/edit/5FvJaelyxdl5MuALt5VY?p=preview
Hope it helps.
Look at the documentation for ui router named views,
You can use following syntax for using multiple views
$stateProvider
.state('state',{
url: '',
views: {
'header': {
templateUrl: 'views/header.html',
controller: 'headerCtrl'
},
'content': {
template: '<div ui-view=" "></div>', //<-- child templates loaded to here
},
'footer': {
templateUrl: 'views/footer.html',
controller: 'footerCtrl'
}
}
})
.state('state.post', {
url: 'news/:id/:KeyWords'
templateUrl: 'views/post.html' //<-- This goes into content's ui-view
});
I'm guessing you want to keep the header and footer and change content views.
You can achieve this by making this state as parent to all other states
suppose
.state('main',{
abstract: true,
views: {
'header': ... ,
'content': {
template: '<ui-view></ui-view>',
}
'footer': ...
}
})
then all the child views will load their views in the ,
ex: in main.child etc, your template will load in the content's <ui-view></ui-view> tag
If you need to use a custom template depending on keywords you can do the following:
.config(['$routeProvider',
function($routeProvider, $routeParams) {
$routeProvider
.when('/news/:id/:keyWords', {
template: '<div ng-include="url"></div>',
controller: "exampleController"
})
then in the exampleController
function($routeParams, $scope) {
$scope.url = $routeParams.keyWords;
}

AngularJS: ui-router-tabs selecting a default tab

I am currently using the ui-router-tabs (https://github.com/rpocklin/ui-router-tabs) module in my application.
I have got most of it working as I need but I want to select a default tab.
Here is an example of how my states are currently configured (pretty much the way the example is from the site above!):
.state('state', {
url: "/foo/:id/bar",
controller: 'SomeController',
templateUrl: 'pageA.html'
}).state('state.substateA', {
url: "/somepath",
templateUrl: 'partials/pageB.html',
controller: 'SomeOtherController'
}).state('state.substateB', {
url: "/someotherpath",
templateUrl: 'partials/pageC.html',
controller: 'AnotherController'
});
So at present if the url is "/foo/:id/bar" I want to select my first tab by default, is this something I ought to be doing at the controller level, so sniff the current matched state and if equal to "/foo/:id/bar" then trigger another state change manually?
EDIT
OK, so as I was writing the question I came up with a way, but not sure of it's really the angular way of doing it.
So in my controller code I check the current state and set a default sub state accordingly to end up selecting one of my tabs:
if ($state.current.name === 'state') {
$state.go('state.substateA');
}
Does this seem like a sensible approach?

AngularJS ui.router abstract routes and trailing slashes

I have three route states - an abstract state, a state that shows the listing and a state that specifically shows a detail of one particular object.
My states are configured as follows:
.state('movies', {
url: "/movies",
template: '<ui-view ng-show="isLoaded" />',
abstract: true,
ncyBreadcrumb: {
skip: true
}
})
.state('movies.index', {
url: "?genres&tags&year&season&page&perpage",
templateUrl: "views/movies.html",
controller: 'MoviesViewController',
ncyBreadcrumb: {
label: 'Movies'
}
})
.state('movies.show', {
url: "/:id/:slug",
controller: 'MoviesItemController',
templateUrl: "views/movies/details.html",
ncyBreadcrumb: {
parent: 'movies.index',
label: '{{item.title_main}}'
}
})
I'd like to add the posibility of movies.index also beginning with a slash, so the URL can either be /movies or /movies/. However with my design, I have no idea how to do that.
I'm also not sure if I understand the concept behind abstract states correctly. I can either use this, or have movies.index be the parent state, in which case, how do I replace its content by the child's template? Also, I have noticed that since the parent controller also gets called, an unnecessary GET request is sent to my API, which can slow things down (especially since it's completely useless information). Can anyone give me a hand in this?
I understand that this use case is supported by $urlMatcherFactory.strictMode(false)
Take a look her
http://angular-ui.github.io/ui-router/site/#/api/ui.router.util.$urlMatcherFactory#methods_strictmode

ui-router routing 2 different states with different templates

I'm using ui-router 0.2.10. My application has two different templates, index.html & index2.html. I've created an abstract state, and i'm referencing both indexs' in their respective states, The problem is I can access the first route fine, but when I try to access the next route it just keeps defaulting to the first route. The abstract templates live in the same folder.
What am I missing here?
.config(["$stateProvider", "$urlRouterProvider", function(sp, urp) {
urp.otherwise("/index1");
sp.state("index1", {
abstract:true,
url: "/index1",
templateUrl: "index.html"
});
sp.state("index1.id", {
url: "/id",
template: "views/partials/index.partial.html",
controller: function($scope,$state){
$state.go('index1.id');
}
});
sp.state("index2", {
abstract:true,
url: "/index2",
templateUrl: "index2.html"
});
sp.state("index2.id", {
url: "/id",
template: "views/partials/index2.partial.html",
controller: function($scope,$state){
$state.go('index2.id');
}
});
}])
I'm assuming that you're trying to go to an abstract state and that won't work as abstract states will only be activated when you go to a child of that abstract state, i.e. you can't direct go to index1 or index2, so this is not legal:
urp.otherwise("/index1"); it should be: urp.otherwise("/index1/id"); instead.
also why are you going to the states again within their own controller? $state.go('index2.id'); is pointless since by the time that line of code is reached you are already in the state index2.id. I think you meant to put those lines of code inside the controllers of the abstract states! Last bit not least don't forget that your abstract states MUST have a ui-view themselves as they are hosting child states.
See plunk.

Angular alias routes in config without redirect

I'm probably just missing something simple, but I want to alias my routes. I am trying to get the route /hello_world to just forward to the existing route of /posttemplate. I want to be able to alias my routes like this to give users and easy to remember way to get to dynamic links... Like Permalinks in blogs. Also, this is sort of a separate question, does anyone know of a good way in angular to define all these routes in a json file or xml or something that will keep this clean as I add many routes to it?
application.config(['$routeProvider', '$locationProvider', function AppConfig($routeProvider, $locationProvider, $routeParams) {
$locationProvider.html5Mode(true).hashPrefix('!');
$routeProvider.when("/dashboard", {
controller: 'controllers.DashboardController',
templateUrl: 'templates/dashboard.html'
}).when("/wishlist", {
controller: 'controllers.WishlistController',
templateUrl: 'templates/wishlist.html'
}).when("/login", {
controller: 'controllers.LoginController',
templateUrl: 'templates/login.html'
}).when("/posttemplate", {
controller: 'controllers.PostTemplateController',
templateUrl: 'templates/posttemplate.html'
}).when("/hello_world", {
controller: 'DynamicRouteController',
templateUrl: function(params){ return '/posttemplate?id=1' }
}).otherwise({
controller: 'controllers.HomeController',
templateUrl: 'templates/home.html'
});
}]);
I think you should first plan your URL patterns carefully. It seems not a good idea to have /{{post_name}} and /posttemplate at the same level.
Maybe you could try to add a path prefix to all your individual articles, like /post/:post_name.
Then you can just add this to your router config:
.when("/post/:post_name", {
controller: 'DynamicRouteController',
templateUrl: 'templates/posttemplate.html'
}
Then in DynamicRouteController, read post_name from $routeParams and map it to your post IDs. You may add something like a unique_name field to your posts, in which stores the URL (/post/post_name) you want it to be accessible from.
Or, if you really want, you can also put them the same level. Just make sure that the "catch-all" item is at the end of your router configs.
And, if you want, you can definitely save the router configs into a JSON file. Just iterate over an array of config items and pass them to when().
You can use redirectTo to redirect from an "alias" to some other route.
.when("/hello_world", {
redirectTo: '/posttemplate'
}
See the docs on $routeProvider for more info.
Well... Here is what I ended up doing... If anyone knows a better way... just let me know.
routes["/dashboard"] = {
controller: 'controllers.DashboardController',
templateUrl: 'templates/dashboard.html',
aliases: ['/dash','/dasher'],
meta: {
title: "Dashboard",
description: 'This is my description'
}
};
routes["/bucket"] = {
controller: 'controllers.PostTemplateController',
templateUrl: 'templates/posttemplate.html',
aliases: [],
arguments: {
id: 1
},
meta: {
title: "Dashboard",
description: 'This is my description'
}
};
//Incontroller
if (!postId)
postId = $route.current.arguments.id;
Check out this project ui-router. It provides several features to enhance your route and template management.

Resources