optional parameters in ui.router url - angularjs

I am trying to show the same view regardless of whether the :id parameter is set in the url. I have this but the /cases route doesn't seem to work without the :id.
.state 'messages',
url: '/cases',
views:
'':
templateUrl: 'views/messages.html',
controller: 'MessagesCtrl'
'ticketList#messages':
templateUrl: 'views/messages/list.html'
'ticketComments#messages' :
templateUrl: '/views/messages/comments.html'
'ticketDetail#messages' :
templateUrl: '/views/messages/detail.html',
.state 'messages.id',
url: '/cases/:id',
views:
'':
templateUrl: 'views/messages.html',
controller: 'MessagesCtrl'
'ticketList#messages':
templateUrl: 'views/messages/list.html'
'ticketComments#messages' :
templateUrl: '/views/messages/comments.html'
'ticketDetail#messages' :
templateUrl: '/views/messages/detail.html',

You are almost there - just child inherits url from its parent. So to make just cases working, we should do:
.state 'messages',
url: '/cases',
....
.state 'messages.id',
// url: '/cases/:id', // instead of this
url: '/:id', // we need this
And we can do even more, e.g. use params :{} to define more precise settings. Check these for example:
Angular ui router passing data between states without URL
Angular js - route-ui add default parmeter
Prepend optional attribute in angular ui-router URL
Angular UI-Router more Optional Parameters in one State

Related

Angular ui-router parameter causes conflicts with other states

Just to give some context, I have an Angular application with several separate modules. I am working with ui-router to provide routing to these modules, and I want to use the names of the modules in the URLs. In my Angular app config block I have defined a state for both module1 and module2 with a parameter on each like so:
.state('module1', {
url: '/:module_name',
templateUrl: '/app/modules/module1/views/index.html',
controller: 'someCtrl'
})
.state('module2', {
url: '/:module_name',
templateUrl: '/app/modules/module2/views/index.html',
controller: 'someOtherCtrl'
})
I also have a few links that should take me to the home page of each module.
Naturally, the problem is that the first state will catch all of the rest of my module2 routes, since their URLs all have the same form:
http://localhost:3000/#/module1
http://localhost:3000/#/module2/users
http://localhost:3000/#/module2/books
and so on. I can see how the order that we define the stats is important, but I can't seem to come up with a way to be able to have the module name as a state parameter (this is important since I need it in the corresponding controllers to distinguish from which module an operation is coming from) and avoid this hierarchy problem altogether.
Any ideas?
In your case ui-router will not know which route your are pointing to as they are exactly the same. You would either have to hardcode the module name(assuming there are only a few):
.state('module1', {
url: '/module1',
templateUrl: '/app/modules/module1/views/index.html',
controller: 'someCtrl'
})
.state('module2', {
url: '/module2',
templateUrl: '/app/modules/module2/views/index.html',
controller: 'someOtherCtrl'
})
.state('module2', {
url: '/module2/users',
templateUrl: '/app/modules/module2/views/users.html',
controller: 'someOtherCtrl'
})
.state('module2', {
url: '/module2/books',
templateUrl: '/app/modules/module2/views/books.html',
controller: 'someOtherCtrl'
})
or dynamically inject the html based on the module number
.state('module', {
url: '/module/:moduleId',
templateUrl:
function (stateParams){
return '/app/modules/module' + stateParams.moduleId + '/views/index.html';
}
controller: 'someOtherCtrl'
})
so now to hit module one the path looks like this
http://localhost:3000/#/module/1

UI Router params exception

I'm trying to create a structure for creating, reading, updating and destroying that consists on indenting params:
/items/create
/items/1/view || /items/1/edit || /items/1/remove
The states for those are like this in $stateProvider:
.state('items.create', {
url: '/create',
templateUrl: 'item/create.html'
})
.state('items.item', {
abstract: true,
url: '/:_id',
templateUrl: 'item/itembody.html'
})
.state('items.item.view', {
url: '/view',
templateUrl: 'item/item.html'
})
.state('items.item.edit', [... and so on ...]
I'm also redirecting /1 to /1/view using $urlRouterProvider:
.when('/items/:_id', '/items/:_id/view');
Problem is when trying to reach /items/create I'm being redirected to /items/create/view. Is there a way to protect or make an exception to this word so I can reach its URL?
I think your problem is that the urls are being combined, like so:
Appended Routes (default)
When using url routing together with nested states the default behavior is for child states to append their url to the urls of each of its parent states.
$stateProvider
.state('contacts', {
url: '/contacts',
...
})
.state('contacts.list', {
url: '/list',
...
});
So the routes would become:
'contacts' state matches "/contacts"
'contacts.list' state matches "/contacts/list". The urls were combined.
Try using different state names.
This is a syntax error, change this url: '/item/:_id.view' for this url: '/item/:_id'.

angular ui-router for dynamic page url

I have an angular app where I am using ui-router module. I am storing a "page" in database with URL and content. I also have some other states/URLs that have their own template. For example:
$stateProvider
.state('landing', {
url: '/',
templateUrl: 'landing-page.html'
})
.state('admin', {
url: '/admin',
templateUrl: 'admin.html'
})
.state('user', {
url: '/user',
templateUrl: 'user.html'
})
I want to define a state for the pages using something like
.state('page',{
url: '??',
templateUrl: 'page.html'
})
What should be in the url above if my page is dynamically stored in database with a URL/slug and content. How can I add the URL/slug here ? If I try this below:
.state('page', {
url: '/{path:.*}',
templateUrl: 'page.html'
})
Then it routes every page including the other states to the same template. I can always prefix the URL with something like /page but I don't want to do that. I want to be able to load the page as :
www.mysite.com/page-1
www.mysite.com/whatever-url
etc
Never mind. I figured this out. The trick was more about using regular expression. Here is my solution
.state('page', {
url: '/{path:(?!admin|user)[a-z0-9\-]+}',
templateUrl: 'page.html'
})
This will ignore routes starting with /admin and /user which we want first. Then, it will check if the url has at least 1 character.

AngularJS ui-router with different URL parameters

While using ui-view in AngularJS, I'm trying to use URL parameters inside of nested views.
For entities of a given type, I want to be able to show all of the entities when navigating to the url /entities, but I would also like to see only the entities of a given type if I go to entities/ofcategory/categoryName. Lastly, I also want to be able to navigate to /entities/details/entityName to see the details of one entity.
Is this structure possible?
This is my ui-routercode:
app.config(['$stateProvider', function ($stateProvider) {
$stateProvider
.state('entities', {
url: '/entities',
templateUrl: 'app/entities/views/entities.html'
})
.state('entities.ofcategory', {
url: '/ofcategory/:categoryName',
templateUrl: 'app/entities/views/entities.ofcategory.html'
}
.state('entities.details', {
url: '/details/:entityName',
templateUrl: 'app/entities/views/entities.details.html'
});
}]);
If I'm navigating to entities/ofcategory/aname or /entities/details/aname I enter the regular entities controller instead of the category or detailsController
One option is to add an abstract state, which serves as a parent to all your entities states. In that case all your urls become relative to this parent state. Please note that you have to define a ui-view in the template of the abstract state, so it could be used for loading the child templates.
app.config(['$stateProvider', function ($stateProvider) {
$stateProvider
.state('entities', {
url: '/entities',
abstract: true,
templateUrl: 'app/entities/views/entities.html'
})
.state('entities.all', {
url: '/',
templateUrl: 'app/entities/views/entities.all.html'
})
.state('entities.ofcategory', {
url: '/:categoryName',
templateUrl: 'app/entities/views/entities.ofcategory.html'
}
.state('entities.details', {
url: '/details/:entityName',
templateUrl: 'app/entities/views/entities.details.html'
});
}]);
app/entities/views/entities.html:
<div>
<h1>Entities<h1>
<div ui-view></div>
</div>

ionic routing issue, shows blank page

I started building ionic app on top of the sidemenu starter app. The starter app has a base state 'app' which is abstract and all the sidemenu pages are children of the app for example app.search, app.browse, app.playlists etc.
I have similar hierarchy. However, I want the start page to be some other page, which means it is at the app level.
The states look like this:
$stateProvider
.state('app', {
url: "/app",
abstract: true,
templateUrl: "templates/menu.html",
controller: 'AppCtrl'
})
.state('join', {
url: "/join",
views: {
'menuContent' :{
templateUrl: "templates/join.html",
controller: 'joinCtrl'
}
}
})
.state('app.search', {
url: "/search",
views: {
'menuContent' :{
templateUrl: "templates/search.html",
controller: 'searchCtrl'
}
}
})
.state('app.results', {
url: "/results",
views: {
'menuContent' :{
templateUrl: "templates/results.html",
controller: 'resultsCtrl'
}
}
});
// if none of the above states are matched, use this as the fallback
$urlRouterProvider.otherwise('/join');
When I run the app, the url defaults to
http://192.168.1.4:8100/#/join
and shows a blank page. Obviously, the join.html is not blank. Also, the console.log messages in joinCtrl are not outputted.
I am not able to figure out why is it not loading the join page. When I change the otherwise to point to '/app/search', everything works.
Any idea what's going on? How do I load the initial page by default and then navigate to the 'app.search' state?
I would expect that because the app is abstract - it is there for a reason. To be parent/layout state. In its template should most likely live all other states.
If yes - check this working example I created to demonstrate that. What we need is to mark the join as a child of the app state. Then the 'menuContent' placeholder will be properly searched in the app template:
.state('join', {
parent: 'app',
url: "^/join",
views: {
'menuContent': {
templateUrl: "tpl.join.html",
controller: 'joinCtrl'
}
}
})
There is a working plunker
The definition url: "^/join", is there to support the idea, that the url defined like this:
// if none of the above states are matched, use this as the fallback
$urlRouterProvider.otherwise('/join');
will work even for nested state (join is child of app). See:
Absolute Routes (^)
If you want to have absolute url matching, then you need to prefix your url string with a special symbol '^'.
This is just one way... we can do the similar stuff if the join is not nested state, but then it should target the unnmaed view '' instead of 'menuContent'

Resources