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
Related
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?
I want to get part of a path in URL via Angular.js and i found solution:
http://mywebsite.com/one/HEREiWANT/three
first i do this:
app.config(function($locationProvider){
$locationProvider.html5Mode(true);
});
then i define my controller like this:
app.controller("mainCtrl", function ($scope,$location) {
//...
}
then with this method i can get what i want and it works!:
$scope.getURLPart = function () {
return pId = $location.path().split("/")[3]||"Unknown";
};
But this has a huge problem, right now after this changes, all of my linkes in my website doesn't work. When i click on a link, address in browsers address bar changes but i stay at the same page and redirection process doesn't happen. Why? How i can achieve what i want without with this problem?
In your state if your using state and yor passing params to your state then you can use
$stateparams to get the params
$stae.go("particular state name") to route to states
I'm trying to update a url without refreshing my page and i'm working with this solution: https://github.com/angular/angular.js/issues/1699#issuecomment-45048054
I notice that this code works:
$route.current.pathParams.program = "someValue";
$location.path('/myapp/' + $routeParams.program);
But this code does NOT work:
$routeParams.program = "someValue";
$location.path('/myapp/' + $routeParams.program);
I'm wondering what the difference is and why one works but not the other?
It doesn't work because AngularJS does not recognize any changes to $routeParams until after the route changes, per 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.
Abstract
Hi, I'm using angular + ui-router in my project, I have huge amount of nested states and different views that in turn contain huge amount of different inputs, a user fills these inputs incrementally step by step.
The problem
Sometimes users require additional info that is located on the previous step, and browsers "back" button helps the user to sneak peek into that data, but as soon as the user presses it, the info he already entered is lost due to state transition, which is obviously a bad thing.
Strategy
In order to overcome described problem I have the following plan:
Associate each user's "navigation" (guess this is a proper term) with a random id
To prevent scope-inheritance-and-serialization issues, instead of putting viewmodel into $scope use ordinary javascript object that will be storing immediate values that are bound to UI.
Add watcher to look for changes on that "storage object"
As soon as the change spotted, serialize the object and persist it
Explanations
Why do we need a random parameter in URL?
We don't want to store all data in URL, since there might be quite some amount of data that wont fit into URL. So in order to provide the guarantees the URL won't break, we put only small random GUID/UUID into it that later allows obtaining the data associated with current "navigation" by this random GUID/UUID.
The storage
There are multitude of storage scenarios available out there: LocalStorage, IndexedDB, WebSQL, Session Storage, you name it, but due to their cross-tab, cross-browser, browser-specific nature it would be hard to manipulate and manage all of the data that gets into the storage. The implementation will be buggy / might require server-side support.
So the most elegant storage strategy for this scenario would be storing data in special window.name variable which is capable of storing data in-between requests. So the data is safe until you close your tab.
The Question
On behalf of everything written above, I have the root view called "view" that has a state parameter id (this is the random GUID/UUID)
$stateProvider.state('view', {
url: '/view/{id}',
controller: 'view',
templateUrl: 'views/view.html'
});
All of the other views derive from this view, is there way to make ui-sref directive to automatically inject a random GUID/UUID into id state parameter of my root view, instead of writing each time ui-sref's like:
<a ui-sref="view({id:guid()}).someNestedView({someNestedParam: getParam()})"
I would like to have something like:
<a ui-sref="view.someNestedView({someNestedParam: getParam()})"
The AOP and Decorator pattern are the answer. The comprehensive description could be found here:
Experiment: Decorating Directives by Jesus Rodriguez
Similar solution as described below, could be observed:
Changing the default behavior of $state.go() in ui.router to reload by default
How that would work? There is a link to working example
In this case, we do not solve from which source the random GUID comes from. Let's just have it in runtime:
var guidFromSomeSource = '70F81249-2487-47B8-9ADF-603F796FF999';
Now, we can inject an Decorator like this:
angular
.module('MyApp')
.config(function ($provide) {
$provide.decorator('$state', function ($delegate) {
// let's locally use 'state' name
var state = $delegate;
// let's extend this object with new function
// 'baseGo', which in fact, will keep the reference
// to the original 'go' function
state.baseGo = state.go;
// here comes our new 'go' decoration
var go = function (to, params, options) {
params = params || {};
// only in case of missing 'id'
// append our random/constant 'GUID'
if (angular.isUndefined(params.id)) {
params.id = guidFromSomeSource;
}
// return processing to the 'baseGo' - original
this.baseGo(to, params, options);
};
// assign new 'go', right now decorating the old 'go'
state.go = go;
return $delegate;
});
})
Code should be self explanatory, check it in action here
How can I pass actual URL (with slashes, commas, etc.) as a $routeParam to AngularJS App?
this will work:
http://paprikka.github.io/le-bat/#/preview/asdadasda
this won't:
http://paprikka.github.io/le-bat/#/preview/http://page.com
neither will this:
http://paprikka.github.io/le-bat/#/preview/http%3A%2F%2Fpage.com
or this:
http://paprikka.github.io/le-bat/#/preview/?url=http%3A%2F%2Fpage.com
Details
AngularJS routing mechanism by its design does not allow to pass strings with slashes as query parameters. I can understand the reasoning behind this decision - we don't want to create a stateless server here.
However, there are still cases when using different separators or regular expressions in routes might be necessary.
I wanted to create an app that takes a url hash string parameter and loads its content to an iframe (link here). Routes are set up in pretty standard way (I'm using Coffeescript, but this snippet does not differ from pure js):
$routeProvider
.when('/preview/:src', {templateUrl: 'partials/preview.html',
controller: 'PreviewCtrl'})
.when('/preview', {templateUrl: 'partials/preview.html',
controller: 'PreviewCtrl'})
Of course, I can load url from hash before AngularJS gets bootstrapped and then pass it to the library, but it would be nice if I could also update current route parameter when changing data in scope - that's why I think it's much better not to avoid AngularJS API.
Using $routeProvider in Angular 1.2, you can pass in a url if it's at the end of the path by adding an asterik to the pattern. The following should work whether or not you URLComponentEncode the url.
The route:
angular.module('angularApp', ['ngRoute'])
.when('/frame/:picture_url*', {
templateUrl: 'views/frame.html',
controller: 'PictureFrame'
});
The controller:
.controller('PictureFrame', function($scope, $routeParams, $sce){
//whitelist the URL
$scope.picture_url = $sce.trustAsResourceUrl($routeParams.picture_url);
});
Then in your template:
<iframe ng-src="{{picture_url}}"></iframe>
Ok, I've managed to find a solution working with current stable version (#1.0.7).
Current way of handling this problem will involve $route-related events, parsing angular-incompatible urls on the fly and handling them via an additional service working in a similar way as $http interception.
You can see working code examples here: http://embed.plnkr.co/fIA2xj/preview
Main steps
pass an angular-incompatible url as usual, eg. go to site.com/url/http://site.com
listen to a $routeChangeStart event and extract correct url parameter for paths beginning with /url/
encode the correct url parameter to an angular-compatible form (in this particular case, I use base64). Don't use encodeURIComponent, because angular will treat as any other url
redirect to another route with your business logic, eg. site.com/parsed-url/BASE64_GOES_HERE
decode the URL in the controller and use it as usual :)
Code
Create angular app module as usual
angular.module('routes',[]).config([
'$routeProvider',
function($routeProvider){
$routeProvider
.when('/test', {templateUrl: 'test.html'})
// This one is important:
// We define a route that will be used internally and handle
// parameters with urls parsed by us via the URLInterceptor service
.when('/parsed-url/:url', {templateUrl: 'url.html', controller:'URLCtrl'})
.when('/', {redirectTo: '/test'})
.otherwise({templateUrl: '404.html'});
}
])
URL Interceptor service (singleton)
.service('URLInterceptor', function($rootScope, $location){
// We listen to $routeChangeStart event and intercept it if
// the path matches our url scheme. In this case, every route
// beginning with /url/ will be caught
$rootScope.$on('$routeChangeStart', function(e, next, current){
// $location.path does change BEFORE actual routing happens,
// so in this case we get parsed new location object
// for free.
// To be hones, a better way of handling this case might be using
// $locationChangeStart event instead, but it would require us to parse urls
// manually.
var path = $location.path();
// check if string begins with '/url/'
var matcher = path.slice(0,5);
var cleanPath = '';
if (matcher === '/url/'){
// Yes it does, yay!
// Remove leading '/url/' to extract the actual parameter
cleanPath = path.slice(5);
// Encode our url to a safe version. We know that encodeURIComponent won't
// work either, so a good choice might be base64.
// I'm using https://code.google.com/p/javascriptbase64/downloads
$location.path('/parsed-url/' + Base64.encode(cleanPath));
// Prevent default event execution. Note that, it won't cancel related $location Events
e.preventDefault();
}
});
return {
decode: Base64.decode,
encode: Base64.encode
}
})
Controllers
// Main application controller
// We instantiate our URLInterceptor service here
.controller('AppCtrl',function($scope, $location, URLInterceptor){
$scope.navigateTo = function (path) {
$location.path('/url/' + path);
}
})
.controller('URLCtrl', function($scope, $routeParams, URLInterceptor){
$scope.url = URLInterceptor.decode($routeParams.url);
});
Two things you should remember:
Although I tried to create a solution as clean as possible, usually passing the data this way to angular isn't considered a good practice, so try not to use it unless you really need to.
You can handle this issue with only one route. I just find it cleaner this way.
I have a solution but I don't know if it will help you. From Angular documention http://docs.angularjs.org/api/ng.$location $location has a function search(search, paramValue)
To pass the parameter:
parameter = encodeURIComponent url
$location.search({ yourURLParameter: parameter }).path('/preview')
To read the parameter:
url = decodeURIComponent $location.search().yourURLParameter
Of course you need to inject $location dependency
I have mixed search params with routes. Your search needs to come before your routes.. specifically for older browsers. I think ie7 blows up if its not url/?search/#/hash
Try this format:
domain.com/?my=params&another=param/#/my/hashes