Can you somehow receive $stateParams without having a <ui-view>-tag in your html?
Basically, I want this code to work:
.config([
'$locationProvider',
'$stateProvider',
function($locationProvider, $stateProvider) {
$locationProvider.html5Mode(true);
$stateProvider
.state('schedules_show', {
name: 'edit_schedule',
url: '/schedules/:id/edit'
});
}])
So I can fetch the :id from any other controller that is being called via $stateParams.
Some more clarification: I don't want to use $stateParams to generate links or to move around my application, cause my app is an hybrid of RoR and Angular.js. I change views in server side with common links. I just want to use angular-ui-router to get some values from the URL to use in the Angular.js part of my app (in this case the :id). So because I don't want to navigate via Angular and don't want to use it's state dependent controllers or views, which again is the reason why I don't want to have <ui-view>-tags in my HTML.
Problem solved: I think my approach via angular-ui-router was wrong. I have a solution now, where I just pass the param from the HTML via ng-init to the controller, but it doesn't answer my question, so I think this should be closed.
If I understood you rigth you need state params. And the qnswer is: yes you can. First way is to use url params: /url/suburl/:param1/:param2/:paramN. Second way (if you do not want to see your params in url) use params option in your state. Then just call your state with this params inside. Example:
.state('schedules_show', {
name: 'state1',
url: '/state',
params: {
param1: null,
param2: null
}
});
Here, in state configuration null is for not to assign initial value; and call this state with
ui-sref="state1({ param1: 'test', param2: 10 })"
Then in injected $stateParams object you can get these params' values
Another possible solution is to use resolve in your state to provide specific params to your controller assigned with this state
More info about resolve
Does it makes sense?
Related
I want to load data and params for each state once when the app loads from my service settings (this service returns also promise since data are loaded asynchronously).
Something like this:
.state('tutorials', {
url: '/tutorials',
templateUrl: 'partials/tutorials.html',
controller: 'TutorialsCtrl',
data: {details: false}, // instead of false I want: settings.get('tutorials_data_details')
params: {popular: '512'} // instead of '512' I want: settings.get('tutorials_params_popular')
})
Those params must be loaded for all states before entering any state since they are used to build links with ui-sref directive that can be placed in any html pointing to any state (and those default params will be used).
Problem is that I cannot inject service into the config function. And using resolve will not handle all states at once.
I think $stateProvider.decorator could be used but I don't know how.
I would have commented, but not enough reputation for that.
If it's possible, one option is to create a parent abstract state such as app, so your state tree would become app.tutorials and then you can use resolve on the app state, allowing all sub-states to use the data/params.
something like this:
.state('app', {
url: '',
abstract: true,
templateUrl: 'partials/tutorials.html',
controller: 'AppCtrl',
resolve: { <resolve your dependencies here> }
})
.state('app.tutorials', {
url: '/tutorials',
templateUrl: 'partials/tutorials.html',
controller: 'TutorialsCtrl'
})
Note the Tutorials state wont load until the resolve is completed.
After some research and thinking I came up with these 3 possible solutions:
1) By using decorator we make all states resolving settings service.
.decorator('data', function(state, parent) {
state.resolve.SettingsLoaded = ['settings', function(settings) { return settings.$promise; }];
return parent(state);
})
Then in settings service use load success callback to setup states. You can use $state.get() to get all states (or with string parameter to get specific state by name) and modify the params object.
NOTE that you cannot use short version like state.params.popular = '512' but the full one: state.params.popular.value = '512'.
2) Those params could be actually functions that will be injected and invoked, and the result value will be used.
So the new params definition in the state will be:
params: {popular: ['settings', function(settings) { return settings.get('tutorials_params_popular') || '512'; }]}
Also I used again the same decorator to make sure settings will be resolved before any state is loaded.
I like this approach the most since all parameter values stays in settings service and the change is being dynamically reflected.
3) Since I'm using RequireJS, I could load settings using that and then inject it to the router file. This would however require more changes to the exising code in my settings service...
I want to build a multi step wizard with ajax calls in between:
I currently use ui.router for views of the wizard steps which works fine.
On the first page the users enters some data e.g. playerid.
On the second page i want to display some data pulled from the server corresponding to that playerid.
How should i structure that? Because i read that controllers should only write to the model, but i need to read playerid the user entered to make the ajax call..?
Here is a Plunk how i do it right now:
http://plnkr.co/edit/4ZEdYHUqovn2YfkUpp2y?p=info
I personally would have done it this way (plunker):
The routing :
$stateProvider
.state('view1', {
url: "/view1",
templateUrl: "view1.html",
controller:"WizardCtrlStep1"
})
.state('view2', {
url: "/view2",
templateUrl: "view2.html",
controller:"WizardCtrlStep2",
params:{
playerId:null
},
resolve:{
player:function($http, $stateParams){
//you can use the player id here
console.log($stateParams.playerId);
return $http.get("test.json");
}
}
})
I really really like to have a single controller per state. It avoid thing to get messy.
I also use a resolve to do the ajax call before the step2 view loading.
Here is the controller of the 2nd step
//I inject the "player" resolved value
controller('WizardCtrlStep2', function($scope, player) {
$scope.name = 'World';
//to access the result of the $http call use .data
$scope.player = player.data;
})
And finally the HTML
<input type="text" ng-model="main.playerId">
<button ui-sref="view2({playerId:main.playerId})">proceed</button>
Here i give ui-sref a param for "playerId" that will be used in the resolve function.
Hope it was clear, if you have any question feel free to ask.
Given the following code:
$routeProvider.when('/movies/:type', {
title: 'Movies',
templateUrl: 'pages/movies/movies.html',
controller: 'MoviesCtrl'
});
How can I access the :type param from inside the when function? I want to do something like so:
$routeProvider.when('/movies/:type', {
title: 'Movies' + ' - ' + :type,
templateUrl: 'pages/movies/movies.html',
controller: 'MoviesCtrl'
});
That value in title must be dinamically generated.
Thanks in adv.
I'm not sure why you are extending the route (config) object, but you are able to access routeParams from within your controller. That is also the recommended way.
The $routeParams service allows you to retrieve the current set of route parameters.
angular.module('MyModule').controller('MoviesCtrl',function($scope, $routeParams) {
$scope.currentMovieType = 'Filmes-' + $routeParams.type;
});
Let's say your route is something like that /movies/scifi. In this case $scope.currentMovieType becomes scifi and you can use {{currentMovieType}} in your view to populate this value. You can find detailed informations in the documentation.
Note that the $routeParams are only updated after a route change completes successfully. This means that you cannot rely on $routeParams being correct in route resolve functions. Instead you can use $route.current.params to access the new route's parameters.
It is not really possible, because the route config object is not as dynamic as you think. Whatever you put in the route configuration object, it cannot depend on the value that the route param is going to take in the future. Think of how this code gets executed : the configuration object will be evaluated only once, when the route is configured.
On the other hand, if you want to change the page's title when going through this route, you can do it using the $routeParamsservice to access the param value, and the $document service to change the page's title, either in a controller or in a resolveclause.
An example with the latter option:
$routeProvider.when('/movies/:type', angular.extend({
templateUrl: 'pages/movies/movies.html',
controller: 'MoviesCtrl',
resolve: {
title: ['$routeParams','$document', function ($routeParams, $document) {
var title = 'Filmes-' + $routeParams.type;
$document.title = title;
return title;
}]
}
}, routeParams));
That works also in a controller of course.
Some notes on your code :
I'm not even sure that there is a point setting a title property in a route config object, I don't see it in the documentation at least.
That second argument routeParams in that angular.extend call - the name is confusing, one could mistake it for the $routeParams service. I think you should call it routeDefaults or something like that instead.
Give a try to $location.absUrl(); requires some calculation too .
https://docs.angularjs.org/api/ng/service/$location
Setting a URL parameter via $routeParams, or setting it using $location.search() as a setter seem to achieve the same thing, other than how the parameter appears in the URL, and where in the app it is set.
From app.js config...
$routeProvider
.when('/myRoute/:myParam', {});
vs.
From a controller...
$scope.setLocationParam = function (name, param) {
$location.search(name, param);
};
I have a simple ajax app where I'm going step-by-step through a few pages and I want to maintain state in the URL so that each subsequent route is calling an api based on URL params set from the previous route.
When would one want choose one method over the other?
I'm leaning towards a search param via $location because it's more descriptive but I thought I'd ask you fine people!s
Having really big JSON object in Angular controller and ui-sref link I want to pass this object to controller of template that would be in ui-view.
I know, that I can pass parameters to state with ui-sref, but I don't want this object to appear in address bar. Also, I know that we can use 'resolve' option in state, but I can't find how to pass data to 'resolve' function from link.
Update
If I use $state.go like that:
router configuration
state('social.feed.detailed',
url: '/:activityID'
templateUrl: 'views/social/detailedactivity.html'
)
in template
<ums-social-activity ng-repeat="record in SOC_FEED_CTRL.records"
activity="record"
ui-sref-active="selected"
ng-click="SOC_FEED_CTRL.goToDetailed(record)">
</ums-social-activity>
in controller
$scope.SOC_FEED_CTRL.goToDetailed = (activity) ->
# here activity is real object
$state.go('social.feed.detailed', {'activityID':activity.id, 'activity':activity})
Then 'activity' param doesn't resolves at all.
Update 2
If I modify route configuration to this:
state('social.feed.detailed',
url: '/:activityID?activity'
templateUrl: 'views/social/detailedactivity.html'
)
Then activity is string "[object Object]"
You can use the ui-router module's $state.go function call to manually pass in $stateParams that won't appear in the URL. So, rather than using the ui-sref attribute, you'd set an ng-click handler that calls $state.go(STATE,{'param':JSON}).
Then, inject $stateParams into your controller, and read
$stateParams.param
To get your JSON object back.
Chances are
ui-sref-active="selected"
Selected represents an object
selected.name
or
selected.id
Selected looks like it represents a key value relationship. That is what I am experiencing anyway.
<a ui-sref="itinerary.name({name:person.id})">