AngularJS, UI Router - Navigating to "foo/bar" goes to "foo" - javascript

For a particular app I've got several states defined, but I'm having trouble with two in particular.
Here's what they look like:
$stateProvider.state('foo', {
url: '/foo',
views: {
"main": {
controller: 'fooController',
controllerAs: 'ctrl',
templateUrl: 'a.html'
},
}
}).state('bar', {
url: '/foo/bar/:id',
views: {
"main": {
controller: 'barController',
controllerAs: 'ctrl',
templateUrl: 'b.html'
},
}
});
Issue: Whenever I navigate in browser directly to /foo/bar/123 the route works. However if I navigate to /foo, and then to /foo/bar/123 the state briefly loads and then navigates back to /foo.
Question: Apart from changing '/foo/bar' to be '/bar' how can I resolve this issue?

I believe all you are looking for is one change to your config.
$stateProvider.state('foo', {
url: '/foo',
views: {
"main": {
controller: 'fooController',
controllerAs: 'ctrl',
templateUrl: 'a.html'
},
}
}).state('foo.bar', {
url: '/bar/:id', //This will still evaluate to /foo/bar/:id
views: {
"main": {
controller: 'barController',
controllerAs: 'ctrl',
templateUrl: 'b.html'
},
}
});
your url should still be /foo/bar/:id, but ui-router will concat them together for you because you are saying that foo is a parent route to bar.
It's likely getting confused right now because it sees two routes that use /foo and doesn't know which to use, so it defaults to the first one defined.
Reference:
https://github.com/angular-ui/ui-router/wiki/URL-Routing

Related

Error loading child state with ui-router

I have a working app though I am changing the architecture, cutting views down into smaller, more manageable documents. I currently have a state with a child state.
.state('patents', {
url: '/patents',
templateUrl: 'p3sweb/app/components/patents/views/list-patents.htm',
controller: 'listPatentsCtrl',
controllerAs: '$ctrl',
})
.state('patents.patent', {
url: '/{patentId}/:patentHref',
templateUrl: 'p3sweb/app/components/patents/views/patent-item.htm'
})
When I click on a table row in state patents, up pops patents.patent view below it.
I have now changed it so the child patents.patent state has multiple views like so:
.state('patents.patent', {
url: '/{patentId}/:patentHref',
templateUrl: 'p3sweb/app/components/patents/views/patent-item.htm',
views: {
'#': {
templateUrl: 'p3sweb/app/components/patents/views/patent-item.htm'
},
'patentinfo#patents.patent': {
templateUrl: 'p3sweb/app/components/patents/views/ui-views/patent-info.htm',
controller: 'patentInfoCtrl',
controllerAs: '$ctrl'
},
'patentcostanalysis#patents.patent': {
templateUrl: 'p3sweb/app/components/patents/views/ui-views/patent-costanalysis.htm',
controller: 'patentCostAnalysisCtrl',
controllerAs: '$ctrl'
},
'patentrenewals#patents.patent': {
templateUrl: 'p3sweb/app/components/patents/views/ui-views/patent-renewals.htm',
controller: 'patentRenewalsCtrl',
controllerAs: '$ctrl'
}
})
When I now click on the row in state patents, the patents.patent view replaces the parent view. So instead of displaying below it, it's the only view displayed.
Question
How do I resolve the issue that has occurred now I have included multiple views in patents.patent state?
So it turns out, after reading ui-router wiki, using # creates an absolute path, and I wasn't targeting the view in the parent state patents.
So instead of
views: {
'#': {
templateUrl: 'p3sweb/app/components/patents/views/patent-item.htm'
}
It should of been
views: {
'#patents': {
templateUrl: 'p3sweb/app/components/patents/views/patent-item.htm'
}

Need to handle dynamic params in angular UI router, and load templates accordingly

I need to handle dynamic params in angular ui-router and load templates according also if someone use link to come on my site, he should be able to reach at desired page. I need to use it for multiple parameters and get the value form server to related values.
.state('home', {
url: '/:shop',
views: {
"mainbox": {
templateUrl: "app/shop/main.html",
controller: "shopMainCtrl",
controllerAs: "shop"
}
// xyz.com/wallmart should be landed here
}
})
.state('course', {
url: '/:shop/:area',
views: {
"mainbox": {
templateUrl: "app/area/nav.html",
controller: "areaNavCtrl",
controllerAs: "areaNav"
}
//xyz.com/wallmart/california should be landed here
}
})
.state('area.food', {
url: '/food',
views: {
"mainboxcontent": {
templateUrl: "app/area/food.html",
controller: "foodMainCtrl",
controllerAs: "food"
}//xyz.com/wallmart/california/food should be landed here
}
}).state('area.cloths', {
url: '/cloths',
views: {
"mainboxcontent": {
templateUrl: "app/area/cloths.html",
controller: "clothsCtrl",
controllerAs: "cloths"
}
//xyz.com/wallmart/california/cloths should be landed here
}
})
.state('buy', {
url: '/:shop/:area/:buy',
views: {
"mainbox": {
templateUrl: "app/buy/buynow.html",
controller: "buyMainCtrl",
controllerAs: "buyNow"
}
//xyz.com/wallmart/california/iphone should be landed here
}
})
https://github.com/angular-ui/ui-router/wiki
templateProvider is something you may try.
stackoverflow: Angular UI Router: decide child state template on the basis of parent resolved object

Error: Could not resolve 'storysolo' from state 'index'

I have my index.php page with a ui-sref link as follows
<a ui-sref="storysolo({ storyId: headline.nid })">
I have my main js file loading the angular code as follows
var rebelFleet = angular.module("CougsApp", ["ui.router","ngAnimate", "ui.bootstrap", "ngSanitize", "slick","CougsApp.headlines","CougsApp.story","CougsApp.recentstories" ]);
rebelFleet.config(function($stateProvider) {
// For any unmatched url, redirect to /state1
$stateProvider
.state('index', {
url: "",
views: {
"navViewPort": { templateUrl: '/components/nav/nav.html'
},
"contentViewPort": {
templateUrl: '/components/headlines/headlines.html',
controller: "headlinesCtrl"
},
"eventsViewPort": { templateUrl: '/components/scroller/scroller.html' },
"bottomContentViewPort": { templateUrl: '/components/recentstories/recentstories.html',
controller: "recentstoriesCtrl"
},
"rightsideViewPort": { templateUrl: '/components/social/social.html' },
"footerViewPort": { templateUrl: '/components/footer/footer.html' }
}
})
Then I have my story.js file trying to load with it's own routing. as follows
var ywing = angular.module('CougsApp.story', ["ui.router"]);
ywing.config(function($stateProvider, $urlRouterProvider) {
$stateProvider.state('storySolo', {
url: '/story/:storyId',
views: {
"navViewPort": { templateUrl: '/components/nav/nav.html'
},
"contentViewPort": {
templateUrl: '/components/story/story.html',
controller: "storyCtrl"
},
"footerViewPort": { templateUrl: '/components/footer/footer.html' }
}
})
});
So when I load my page and click on the ui-sref link I get this error
Could not resolve 'storysolo' from state 'index'
my order of files being loaded is as follows
angular.js,
angular-sanitize.js,
angular-ui-router.js,
rebelFleet.js, (the main js file)
story.js
I'm guessing I'm doing something wrong with the way the routes are being loaded and UI-Router hates it. Any help would be much appreciated.
There is a working example
Believe or not, it is very simple - it is about case sensitivity. State names must fit on the 1) definition as well on the 2) call side
// small solo
<a ui-sref="storysolo({ storyId: headline.nid })">
// capitalized Solo
$stateProvider.state('storySolo', {...
so just use one or the other, e.g.:
// not small solo
<a ui-sref="storySolo({ storyId: headline.nid })">
// the same name here
$stateProvider.state('storySolo', {...
Check the example here

How to update only the named view using UI-Router

I am creating a web app to help students in science, history and math. When you first land on the site I have a home/landing page. When you click get started I route to /exam/instructions. Each of my steps instructions, math and science our templates that I load into the ui-view="exam-detail". Currently the whole ui-view loads when I navigate to and from instructions through sciences. Ideally I simply want an area for pagination and an area for the subject matter and only want the ui-view="exam-detail" to update with the correct template.
I have not used UI-Router at all and any assistance would be greatly appreciated.
index.html
<div ui-view></div>
state-exam>exam.html
<div class="state-exam">
<nav ui-view="exam-pagination"></nav>
<section ui-view="exam-detail"></section>
</div>
route.js
(function() {
'use strict';
angular
.module('studentPortal')
.config(routeConfig);
function routeConfig($stateProvider, $urlRouterProvider) {
$stateProvider
.state('home', {
url: '/',
templateUrl: 'app/main/main.html',
controller: 'MainController',
controllerAs: 'main'
})
.state('exam', {
url: '/exam/:step',
abstract: true,
templateUrl: 'app/state-exam/exam.html',
controller: 'ExamController',
controllerAs: 'examController',
})
.state('exam.instructions', {
url: '/instructions',
views: {
'exam-pagination':{
templateUrl: 'app/state-exam/exam-pagination.html'
},
'exam-detail' : {
templateUrl: 'app/state-exam/exam-instructions.html'
}
}
})
.state('exam.math', {
url: '/math',
views: {
'exam-pagination':{
templateUrl: 'app/state-exam/exam-pagination.html'
},
'exam-detail' : {
templateUrl: 'app/state-exam/exam-math.html'
}
}
});
$urlRouterProvider.otherwise('/');
}
})();
There is a working plunker
There is a similar Q & A in fact, with working plunker:
Angular UI Router - Nested States with multiple layouts
Solution here, is to move the static view from child to parent. It won't be reloaded for each child (view is reloaded only if parent state is changed). We will use absolute naming (see included links for more details)
So this is the code adjustment
.state('exam', {
url: '/exam/:step',
abstract: true,
// the root view and the static pagination view
// will be defined here, so we need views : {}
views: {
'':{
templateUrl: 'app/state-exam/exam.html',
controller: 'ExamController',
controllerAs: 'examController',
},
// absolute naming targets the view defined above
'exam-pagination#exam':{
templateUrl: 'app/state-exam/exam-pagination.html'
},
}
})
.state('exam.instructions', {
url: '/instructions',
views: {
// 'exam-pagination':{}, // defined in parent
'exam-detail' : {
templateUrl: 'app/state-exam/exam-instructions.html'
}
}
})
.state('exam.math', {
url: '/math',
views: {
// 'exam-pagination':{}, // defined in parent
'exam-detail' : {
templateUrl: 'app/state-exam/exam-math.html'
}
}
});
Also check this to get more details about absolute view naming
Angular UI router nested views
Angular-UI Router: Nested Views Not Working
The working example is here

Angular ui-router load specific view before resolve

I know it sounds counter-intuitive, but please hear my situation out. I have a "topbar" view and a "main" view. The topbar has no specific data associated with any one particular view, but it can change depending on the user's login status. This really helps to keep that part of my website robust, however it comes at a terrible cost: When I want to use "resolve", the topbar goes completely missing. I understand the logic behind this, but I am wondering if there is anyway to target which view to actually block with resolve?
If I could only block my "main" view, but allow my "topbar" view to render, then that would be perfect. I also don't want to avoid using resolve to avoid the main view flashing nonsense when the view is first loaded.
What my routes look like:
$stateProvider..state("about", {
url: "/about",
views: {
"topbar": {
templateUrl: "/app/templates/topnav.html"
},
"main": {
templateUrl: "/app/home/about.html",
controller: ["$rootScope", function ($rootScope) {
$rootScope.pageTitle = "About";
}]
}
}
}).state("courses", {
url: "/courses",
views: {
"topbar": {
templateUrl: "/app/templates/topnav-loggedin.html"
},
"main": {
templateUrl: "/app/courses/courses.html",
controller: "coursesController"
}
},
resolve: {
currentCourse: ["$http", function($http) {
// load course
}]
}
});
I'd probably make a parent, abstract state for all states requiring the logged-in topbar template. For example
.state('loggedin', {
abstract: true,
views: {
topbar: {
templateUrl: '/app/templates/topnav-loggedin.html'
}
}
}).state('courses', {
parent: 'loggedin', // or name the state 'loggedin.courses'
url: '/courses',
views: {
'main#': { // the "main" view in the root state
templateUrl: '/app/courses/courses.html',
controller: 'coursesController'
}
},
resolve: { ... }
});

Categories