In Angularjs app, i have a url like http://url.com/my_app/#/store/items.
Now i want to append query string for example, http://url.com/my_app/#/store/items?page=2. but in url, javascript encodes the "?" to "%3F" which i don't want. It should remain "?" only in the url as angularjs $location.search() returns nothing for "%3F".
How it can be done ?
There is not enough details in your question so I will assume that you are using AngularJS routing - or at least the $location service - in non-HTML5 mode. If so, the part after the # character represents your URL from the single-page-application point of view (more about AngularJS here).
If the above assumptions are correct it means that you shouldn't try to add or manipulate the question mark "by hand". Instead you should change the search part of the $location to manipulate query string (part after ?) and the question mark will be added / removed to the final URL as needed.
In your case you could write:
$location.path('/store/items').search('page', 2)
This is assuming that you are manipulating URLs from JavaScript, as stated in your question.
If you are using the $location service then use $location.url('/store/items?page=2') instead. This has been a setter method from at least 1.0.7 and works a treat in my 1.1.5 app.
you can create a parameter object like:
var param = {
page: 2
}
$location.url("/store/items").search(param)
If you're using the ui-router which is highly recommended, you could use $state.go(to, params, options) as described here.
As prerequisite you need to define your state properly, that means every possible query parameter must be made known to the ui-router. See the following example (page and otherParam):
$stateProvider.
state('storeItems', {
url: '/store/items?page&otherParam',
templateUrl: '/modules/store/views/item.client.view.html'
});
And then you can just switch locations for instance from a controller by calling
$scope.gotoItemsPage = function(page) {
$state.go('storeItems', {
page: page,
otherParam: 'Just a show off'
});
};
No fiddling with the encoding needed and highly readable!
You can use decodeURIComponent.
For example:
decodeURIComponent('http://url.com/my_app/#/store/items%3Fpage=2');
// will give you `http://url.com/my_app/#/store/items?page=2`
Related
I have the following state in Angular routing:
.state("supplier/document", {
url: "/supplier/document/:supplierid/:docid",
controller: "ctrlSupplierDocument",
templateUrl: "views/supplier/document.html"})
And I get to this state with the following code:
$state.go('supplier/document', { 'supplierid': $scope.supplierid, 'docid': item.QualificationID });
This results in me correctly going to the view in question, with a url formatted as expected:
http://localhost:60437/index.html#/supplier/document/14/70
I now need to grab the two ids from the url (14 being supplierid and 70 being the document id). BUT $state.params is undefined (obviously it doesn't see these as GET params). Normally, with one parameter $state.param.id works fine. Difference here is the two parameters.
Q. How do I grab these params? OR is there an alternative method to achieve this where I can use $state.params on the target view controller?
Thanks!
Try: $state.current.params.supplierid and $state.current.params.docid
See: http://angular-ui.github.io/ui-router/site/#/api/ui.router.state.$state
I have ui-router set up as follows
.state('root.event', {
url : '/event/:id',
templateUrl : 'templates/event.html'
})
(the controller is initiated in the template)
which gives nice looking Basic URL Parameters like:
www.mysite.com/event/1234
When a user navigates directly to my www.mysite.com/event path (ie param is missing) the template controller looks the most recent id parameter from either:
- a js variable stored in a value
- localstorage / cookie etc
I then return this to my state using $location.search('id', 1234)
...however, this results in URLs which have Query URL Parameters like:
www.mysite.com/event/?id=1234
Is there a technique to ensure that $stateparams updates present the url in basic format on update ?
...or is it possible to get the URL parameter & update the $state before the state change ?
(I looked at Resolve but this seems mostly to be about passing parameters to controllers)
I've had a look here, here and here - but most of the questions relate to how to avoid reload on update of $state params
$location.search does exactly that. It adds query URL parameter. I think what you're looking for is
$state.go('root.event', {id: 1234})
AngularJS state machine extension ui-router declares a directive that converts routes with attribute ui-sref into href paths and populates it with requested variables. Is there a way to access the same route parser from a scope?
Update
I am looking for a hopefully built-in yet undocumented resolver (or a way to get the same outcome) that gives the path to a named argument. In the spirit of a named route:
<a ui-sref="management.person({personId: 1})" />
Which matches a route
$stateProvider.state('management', {
url: '/absolute/part'
});
$stateProvider.state('management.person', {
url: '/relative/part/:personId'
});
and outputs #/absolute/part/relative/part/1 - and in case I switch to use ! fragment, all the URLs are converted. Directive itself does this already, but its arguments cannot be constructed dynamically.
As of March 2015 I got 'UrlMatcher is not defined' for Chad Robinson's answer. But I succeeded by injecting $urlMatcherFactory and replace urlParams in a ui-router template url.
$urlMatcherFactory.compile("/about/:person").format({
person: "bob"
})
ui-router provides several services in an API that you can use to do things this. Try one of these examples:
From http://angular-ui.github.io/ui-router/site/#/api/ui.router.state.$state
var url = $state.href('about-person', {
person: "bob"
});
From http://angular-ui.github.io/ui-router/site/#/api/ui.router.router.$urlRouter
var url = $urlRouter.href(new UrlMatcher("/about/:person"), {
person: "bob"
});
These two patterns convert state names and URL templates into fully formatted URLs. There are additional API calls available as well.
For some of the pages in my application, I would like to enable a printable mode, wherein some elements of the page are hidden when the URL parameters include ?print=true. Currently I have attempted a workaround that involves sending the URL parameters as a data context thru iron-router.
this.route('permitsList', {
path: '/permits/',
path: '/',
waitOn: function(){
return Meteor.subscribe('openPermits');
},
data: function(){
return this.params;
}
});
Accompanied by a global handlebars helper which is used to show and hide elements appropriately.
In this case, when the URL contains ?print=true, it's trivial to show and hide the appropriate elements. However, this solution has two major issues. The first, is the fact that some of the pages for which I wish to implement this printable view already have a data context. Overwriting the data context is not viable, and embedding both data contexts into a larger object is rather disgusting. The second issue is that I wish for the printable view to apply not only inside the template itself, but also in the surrounding layout template in which the page is rendered, so that extraneous headers and so on are removed.
Is there any reasonable way to access URL parameters inside of a Spacebars helper without specifying the parameters in the data context through Iron Router?
To sum up as answer:
Query parameters can accessed even without meteor
if ( window.location.search.indexOf( '?print=true' ) > -1 ) { ... }
window.location returns the current URL, window.location.search only the query parameters as string.
I'm using angular in an application which is, basically, a table with search results.
Access to this table can be achieved via an url like http://myapp/?client=clientName
An angular controller is instantiated for the table, among other things, for opening a modal dialog (also angular-based with bootstrap-ui) with the row details.
These row details are brought via a service which has some common functionality for both controllers: the one for the table and the one for the modal.
Now, within this service, I have the following snippet to retrieve:
service.fetchRelatedElements = function(element, cb) {
var url = '/search.json?results=20&type='+element.type;
if ($location.search()['client']) {
url += '&client=' + $location.search('client');
}
return doFetch(url, cb); // actual server json GET
};
The goal is to know if the table already has this specific client parameter set as a filter.
If I put a breakpoint at the beginning of this call, I see that $location.absUrl() returns the current browser URL (which, in my case, has the client parameter I'm interested in).
But $location.search() returns an empty object.
I am injecting the $location service within my service with the defaults (that is, not configuring it by a .config() call).
And, as doc says:
The $location service parses the URL in the browser address bar (based
on the window.location) and makes the URL available to your
application.
Am I missing something? Shouldn't the URL, at this point, be parsed?
Thanks!
UPDATE: I've managed to make it work. The problem was exactly that I wasn't configuring at all the service. I did so because I assumed that in that way it would take defaults, but it seems that that's not the way it works.
I was having the same problem before I configured $locationProvider in my app's module config:
appModule.config(['$locationProvider', function($locationProvider) {
$locationProvider.html5Mode(true);
}]);
If you don't want to specify the base tag, you can specify require base false.
myapp.config(function($locationProvider) {
$locationProvider.html5Mode({
enabled: true,
requireBase: false
});
});
When I encountered this problem, another thing that worked for me besides setting the configuration is to add "#" in front of the query string.
So if you are the one creating the query string, then changing
myapp/?client=clientName
to
myapp/#?client=clientName
allowed $location.search() to give me a non-empty object which you can then access each parameter using $location.search()['client']
The API for $location.search is pretty confusing. Calling
$location.search('client');
will set the search object to {client: true} and return $location. Furthermore, you have a typo client instead of 'client', so it's setting search to an empty object. So you probably want:
url += '&client=' + $location.search()['client'];
You can write a function that parses the $window.location.search based on this comment https://github.com/angular/angular.js/issues/7239#issuecomment-42047533
function parseLocation(location) {
var pairs = location.substring(1).split("&");
var obj = {};
var pair;
var i;
for (i in pairs) {
if (pairs[i] === "")
continue;
pair = pairs[i].split("=");
obj[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1]);
}
return obj;
}
$scope.query = parseLocation($window.location.search)['query'];