AngularJS load different data to same partial based on URL - angularjs

The problem I'm having here is not being able to find the right question to ask.
I'd like to use a single partial and populate it with different data based on a url. The url would look something like this
localhost:8080/#/users/USER_ID
Where users directs to a user profile partial, and corresponding controller, and USER_ID would be sent in to an HTTP request to retrieve user data that would then populate the user profile partial.
Any direction in solving this is greatly appreciated.

If you are using ui-router which I highly recommend:
$stateProvider
.state('users', {
url:'/users/:userId',
templateUrl: 'user.html',
controller:'UserCtrl'
})
You can then access the userId in your controller:
App.controller('UserCtrl', ['$scope', '$stateParams', '$state', 'User', function($scope, $stateParams, $state, User) {
'use strict';
/* controller code */
var req = User.$find($stateParams.userId);
}]);
I am also using angular-rest-mod to make HTTP calls to an api when I do User.$find(id)

I found a solution that was a lot more straight forward than I had anticipated
app.js
$routeProvider.
when('/user/:id', {
templateUrl: 'user.html',
controller: 'userController'
});
Then in the implementation of userController, $routeParams can be used to retrieve the value of id from the url.

Okay so I would probably go like this. First I would recommend Ui-Router instead of ngRoute this allows you to create your states for example
$stateProvider
// setup an abstract state for the tabs directive
.state('A', {
params: [A,B,C,D,E],
url: "/A",
templateUrl: "templates/YourView.html",
controller: "YourController"
})
.state('B', {
params: [F,G,H,I,J],
url: "/B",
templateUrl: "templates/YourView.html",
controller: "YourController"
})
Basically this says when your Url is "/A" the "YourController" is used and the YourView.html is used so If I understood correct you have 1 view where you want to show different data depending on the Url.By Injecting 'ui.router'into your module and $state into your Controller you can access $state.current.params
Example Controller
.controller('ExampleController', ['$rootScope', '$scope', '$state', function ($rootScope, $scope, $state){
//Here you get your params
//This will return you either [A,B,C,D,E] or [F,G,H,I,J] depending if Url is /A or /B
$scope.showList = $state.current.params;
//Another Possibility with this is to listen for a StateChange
$scope.$on('$stateChangeSuccess', function (ev, to, toParams, from, fromParams) {
//Here you can access all Params from the state you just left to the state you are going
});
}]);
Now you can just show this in the YourView.html like this
<div ng-repeat="item in showList">
<p>{{item}}</p>
</div>
So If your at /A the list shows A,B,C,D,E and if you are on /B it shows F,G,H,I,J
I hope this was helpful

Related

How send send parameter for $routeProvider in angularJS

I want send parameter to templateUrl i want append some numbers after /folder/stockInventoryController.do?param=loadGroupStyles_Controller&fabId=(here I need to add)
myApp.config(function($routeProvider){
//setup Router for widgets page
$routeProvider
.when('/relatedStyle',{
controller:'groupStylesLoad',
templateUrl:'/folder/stockInventoryController.do?param=loadGroupStyles_Controller&fabId='+needParameterHere
})
});
templateUrl can be used as a function if you need to work some magic on the url. It accepts 1 parameter which takes in the current url.
Looking at your example, there aren't any parameters in /relatedStyle; but if there were you'd access and modify them like so:
.when('/relatedStyle/:arbitraryParam',{
controller:'groupStylesLoad',
templateUrl: function(url) {
var modifiedParam = url.arbitraryParam++;
return '/folder/stockInventoryController.do?param=loadGroupStyles_Controller&fabId=' + modifiedParam;
}
})
http://stackoverflow.com/questions/11534710/angularjs-how-to-use-routeparams-in-generating-the-templateurl
see above link ,it may be helpful for u
Here are two ways. One is routing
myApp.config(function($routeProvider){
//setup Router for widgets page
$routeProvider
.when('/relatedStyle/:fabid',{
controller:'groupStylesLoad',
templateUrl:'template/template.html'
})
});
myApp.controller("groupStylesLoad", ['$scope', '$routeParams',
function($scope, $routeParams)
{var fabId = $routeParams.fabid;}
]);
However, if you need to use the query sting.
myApp.controller("groupStylesLoad", ['$scope', '$location',
function($scope, $location)
{var fabId = $location.search().fabid;
// $location.search() returns object like {key1: value1, key2: value2, ...}
]);
https://docs.angularjs.org/guide/$location
Hope this helps.

how to execute the same init code on each controller instantiated by $routeProvider?

In my .config I have a router that instantiate a pair controller-router:
angular.module('reporting', ['ng', 'ngRoute', 'ngResource', 'reporting.directives', 'reporting.controllers', 'reporting.config', 'ngGrid', 'ui.bootstrap'])
.config(["$routeProvider", "$provide", function ($routeProvider, $provide) {
$routeProvider
.when('/dealersReq', {
templateUrl: 'reporting/partials/dealersReqs.html',
controller: 'DealersCtrl'
})
.when('/lmtReq', {
templateUrl: 'reporting/partials/lmt.html',
controller: 'lmtCtrl'
})
.when('/leadsCreated', {
templateUrl: 'reporting/partials/leadsCreated.html',
controller: 'LeadsCreatedCtrl'
})
...
but each controller share the same initialization code (think about it like a constructor) that sets in the rootScope some variable like a title and other useful information for some controllers outside the <view>:
.controller('DealersCtrl', ['$scope','$rootScope', 'CONFIG',
function($scope, $rootScope, CONFIG) {
//////////// duplicated code
var key = 'qtsldsCrtSncheQ';
$rootScope.openReport.key = key;
$rootScope.openReport.title = CONFIG.reports['' + key].title;
//////////// duplicated code
console.log('Initialized! Now I do what a controller should really do');
}]);
What I would like to do is finding a way to move that code - which is duplicated into every controller at the moment - into something smarter and neater. Soemthing that the route can call during the routing instanciation for example. Of course each controller should have a different key, but that one could be exactly the controller name actually. I really don't know how to improve this. Any suggestion?
Why don't create a method on the $rootScope which does that, and then call it from each controller, i.e.: $rootScope.init().
You could use a Service for shared code but you should avoid to use $rootScope
https://stackoverflow.com/a/16739309/3068081

Override AngularJS route to display template based on $scope variable

Using Angular I have a dozen or so routes setup similar to the following example code.
Is there a way to override which template and controller is loaded based on some other criteria while keeping the URL in tact? My goal is to display a login page when... lets say $scope.isLoggedIn = false. I don't want to change the URL to /login.
SomeApp.config(['$routeProvider', function($routeProvider) {
$routeProvider.
when('/place', {
templateUrl: 'routes/place.html',
controller: 'PlaceCtrl'
})
.when('/test', {
templateUrl: 'routes/test.html',
controller: 'TestCtrl'
});
}]);
ngRoute is a very simple library that can basically only maps urls to controller/views. If you want more flexibility, try ui-router which has the ability to route based on state.
This isn't really doable with ngRoute, but with ui-router you can dynamically provide different templates based on just about anything you want.
$stateProvider.state('root',
url: '/'
controller: 'HomePageController'
templateProvider: [
'$rootScope'
'$templateCache'
'$http'
($rootScope, $templateCache, $http) ->
templateId = if $rootScope.isLoggedIn then "home-page-logged-in" else "home-page-not-logged-in"
templateId = "/templates/#{templateId}.html"
return $http.get(templateId, cache: $templateCache)
]
)
The catch is, as far as I know, you can't change the controller, only the template. Which kinda stinks.

AngularJs with routes and anchor tags, working on second click

I have a simple view representing a simple menu which should be using anchor behavior. On the same page there's a bunch of H2 tags with id that the links should scroll to.
I'm using the $anchorScroll and $location.
THE ISSUE: The first time I click a link, I can see that the route is updated, e.g.:
http://localhost:60002/#!/docs/view/somedoc#someResourceId
But it triggers a route, the SECOND time I click it, it behaves as expected.
UPDATE: It's not the anchorScroll() did it manually using element.scrollIntoView(true) same behavior. If I don't use $location.hash it works, but then I loose the possibility of linking to anchors.
Any ideas?
VIEW:
<div ng-controller="DocsMenuCtrl">
<ul ng-repeat="menuItem in menuItems">
<li><a ng-click="foo(menuItem.resourceId)">{{menuItem.title}}</a></li>
</ul>
</div>
...
...
<h2 id="...">Test</h2>
...
CONTROLLER:
module.controller('DocsMenuCtrl', ['$scope', '$http', '$location', '$anchorScroll', 'session', function ($scope, $http, $location, $anchorScroll, session) {
$scope.foo = function (resourceId) {
$location.hash(resourceId);
$anchorScroll();
};
$http.get('/api/menu/').success(function (d) {
$scope.menuItems = d;
}).error(function () {
session.logger.log(arguments);
});
}]);
ROUTEPROVIDER CONFIG etc
$locationProvider.hashPrefix('!');
$routeProvider
.when('/default', {
templateUrl: 'clientviews/default',
controller: 'DefaultCtrl'
})
.when('/docs/view/:id', {
templateUrl: 'clientviews/docs',
controller: 'DocsCtrl'
})
.otherwise({
redirectTo: '/default'
});
$location does not reload the page even if it is used to change the url. See the "What does it not do?" section of this page: $location ngDoc.
As Ganonside said, the location service does not reload the url. Once you are certain that the url changes you can use the route service, specifically $route.reload() to trigger your routing.
The best solution I've found is here: https://github.com/angular/angular.js/issues/1699#issuecomment-22509845
Another option, if you don't use search params, is to tell the route provider not to reload on hash or search changes (unfortunately, it is one option for both).
app.config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/group/:groupName', {
templateUrl: '/templates/groupView.html',
reloadOnSearch: false
}).otherwise({redirectTo: '/'});
}]);

How to redirect to state if specific stateParam is empty

I'm not sure if the way I am doing it is correct, any advice would be appreciated.
I have a Restaurant Selector, which the user can select a restaurant from. Then all other child states load up content specific to the restaurant selected. But I need to have a child state selected by default, including a restaurant, which will be either selected based on the users closest location or on cookie data if they have previously selected one. But, i'm not sure how I can redirect to a child state by default without knowing the restaurant id already?
A bastardised version of my code below to illustrate.
app.config(function ($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise("/restaurant/[some id based on cookie info]/our-food"); // if no id is set, then I want to get it from a cookie, but then how do i do the redirect?
$stateProvider
.state('restaurant', {
url: '/restaurant/:restaurantId',
template: "<ui-view/>",
controller: function($state, $stateParams, Data, RestaurantService, $cookieStore) {
if(typeof $stateParams.restaurantId !== 'undefined') {
// get the restaurantID from the cookie
}
}
})
.state('restaurant.our-food', {
url: '/our-food',
templateUrl: function($stateParams) {
return 'templates/food-food.html?restaurantId=' + $stateParams.restaurantId;
},
controller: 'SubNavCtrl'
})
.state('restaurant.glutenfree-vegetarian', {
url: '/glutenfree-vegetarian',
templateUrl: function($stateParams) {
return 'templates/food-vegetarian.html?restaurantId=' + $stateParams.restaurantId;
},
controller: 'SubNavCtrl'
})
An image below to illustrate what is happening on the front end:
www.merrywidowswine.com/ss.jpg
I would create an event that is fired every time you open that specific state.
Check out their doc: https://github.com/angular-ui/ui-router/wiki#onenter-and-onexit-callbacks
So my guess is either something like this
1. onEnter callback to restaurant state (recommended)
$stateProvider.state("contacts", {
template: '<ui-view>',
resolve: ...,
controller: function($scope, title){
},
onEnter: function(){
if(paramNotSet){ $state.go(...)}
}
});
I've never used an event as such myself so you might have to do some gymnastics with resolve, but I believe this is the cleanest, easiest to understand and most maintainable solution.
2 Global onStateChangeStart event
A global event (although this would get fired for every state change)
$rootScope.$on('$stateChangeStart',
function(event, toState, toParams, fromState, fromParams){ ... //check cookie, change state etc ...})
3 In the controller
Alternatively If you want to use the controller like you started doing.
controller: ['$state', '$stateParams', 'Data', 'RestaurantService', '$cookieStore',
function($state, $stateParams, Data, RestaurantService, $cookieStore) {
if(typeof $stateParams.restaurantId !== 'undefined') {
sate.go('restaurant', $cookieStore['restaurant'])
}
}]
This is probably the fastest solution in terms of development but I believe using events is cleaner and makes for more understandable code.
Note: I haven't actually run any of this code so it might not work, it's just pseudo-code to give you an idea of where to go. Let me know if you run into issues.
EDIT: Acutally I'm not sure if stateParams are passed on to the controller. You might have to use resolve to access them.
EDIT: to access stateParams in onEnter callback or the controller, I believe you have to use resolve as such:
resolve: {
checkParam: ['$state','$stateParams', '$cookieStore', function($state, $stateParams, $cookieStore) {
//logic in here, what it returns can be accessed in callback or controller.
}]
see the ui-router doc on resolve for more examples/better explanation
I needed to get this working, so to add details to the answer from #NicolasMoise:
.state('restaurant', {
url: '/restaurant/:restaurantId',
template: "<ui-view/>",
onEnter: function ($state, $stateParams, $cookies) {
console.log($stateParams.restaurantId);
if (!$stateParams.restaurantId) {
$stateParams.restaurantId = $cookies.restaurantId;
$state.go('restaurant.restaurantID');
}
},
})
I didn't test the cookies portion of this, but the conditional and state change worked.

Resources