Angular JS: encode url & replace browser history - angularjs

An array param, like this:
var paramArray = {page: 1, per_page: "10", shipperCompany: "s&g"};
I need to encode the paramArray.shipperCompany variable. In project, I use $location.search to build url.
$location.search(paramArray);
Then I looked for the comments of the angular js, got the result:
If the argument is a hash object containing an array of values, these
values will be encoded as duplicate search parameters in the url.
This method will change search part when called with parameter, but I do not want the browser to save the last url and i wish replace it.
window.location.replace(url);
However, how can I meet these two points?

Eventually I solved this problem with fellow code。
$location.search(paramArray).replace();
It works.

Related

Use Angular's $location to get URL parameters from URL string instead of current URL

Can I (re)use Angular's $location or another Angular module to get URL parameters from a url? Or do I need to add (yet) another separate JS package to do this?
I have a URL string which I want to get the URL parameters from (aka searchstring). I know there's logic to do this in Angular.js, because $location has the search method. This returns the url parameters part as an object. For instance for a url https://www.domain.org/cool?minPrice=40&maxPrice=50 I can get the maxPrice value using: $location.search().maxPrice.
But this works only for the current url in the browser bar. I'm setting up an ngMock function that has to get url params from a URL passed in as a string parameter. I DON'T want a DIY solution as there is so much debate about what is correct, performant, etc due to things you might not think of it at first like:
- bad performance of regexp
- needing to url encode parameters
- order dependence, etc.
So I'd love to get this gift-wrapped. And ideally as an included-in-Angular solution so there's also no work for wrapping things up in an Angular service :P.
Note: If it's not possible I'll probably use uri.js, which I used to satisfaction in a non-Angular project a while ago.

Get query string form $location.search() object / Call internal Angular method

In Angular, $location.search() returns an object, which is handy to modify: add new params, alter or remove (set to null) existing ones. And $location.search(object) sets this object to the search component of $location. I'm looking for a way to get the composed query string from this object leaving the $location intact. I don't need to get the actual query string, I need to compose the query string from an object.
I don't want to reinvent the wheel and write a javascript function that transforms an object to the string of &-separated key-value pairs, Angular already has one. Basically what I'd like to do is to use toKeyValue method from Angular.js, which is used to compose query string in the $$compose function in location.js. However, it seems like toKeyValue method is inaccessible from outside Angular (unlike, for example, forEach), as I'm getting angular.toKeyValue is not a function error when trying to call it. Is there any way to call toKeyValue method from my controller or just compose the query string from an object by means of Angular?
You can use $httpParamSerializer that converts objects to strings.
This will do from your controller.
app.controller('MainCtrl', function($scope, $httpParamSerializer) {
var querystring = $httpParamSerializer({ width:1680, height:1050 }); //height=1050&width=1680
});

angular form submit get action append key value pairs

My goal was to have off a form submit for a get to be performed and as part of the uri, key value pairs appended like the following:
// GET /pets/42;q=11;r=22
Reading http://www.w3schools.com/tags/att_form_method.asp
description of form with setting form method to "get" I would have thought this was possible. In the world of angular, it seems like the expected behavior for a submit of a form results in post method. The controller can be written to generate any http verb but has the $http.get doesn't do what plain form get method would automatically and to generate a url like above, the controller would have to build the uri itself.
My apprehension of always using post off a form submit was the form in this case was part of a query/search action and not a data creation exercise. Maybe that's not the proper way to use form but has angular done away with automatically appended values from controls in key value pairs for a form with the $http.get service?
Of course you can do GET with query params in url.
The easiest way is to pass an object representing the key/value pairs to the params property of the $http config object.
var params = {q: 11, r:22};
$.get('/path/to/server/', {params: params}).then(....
Alternatively you can also create your own url string when you only have small number of params.
For further details read through the Usage section of $http docs

AngularJS routing for dynamic urls, how?

I'm trying to understand how can i configure my angularJS routing given the following case:
We have a search page where we display the search results based on tags provided (1..n tags). we would like that a user to be able to parse enter a url as the following and our system to do the search and show the respective results.
The url format should be:
http://mywebsite.com/search/<term1>/<term2>/<termN>...so it could be different number of terms.
I was looking into the route provide and couldn't figure out a way to do it dynamically.
i saw that i could put in the routeprovid:
.when('/search/:searchParams',... but that handles only when i have one term...is there anyway to configure it to take as many terms as is given?
Does this help you at all? Seems to support dynamic routing and you could probably cut apart the :name parameter to do what you wish, perhaps.
http://gregorypratt.github.io/AngularDynamicRouting/
Ken
You could try base64ing your searchParams:
.when('/search/:searchParams', {controller:'SearchCtrl'})
function SearchCtrl($routeParams, $location){
//Assuming your params are an array like ['param1', 'param2', 'param3']
//You could easily adapt this to base64 a JSON object
function encodeParams(params){
return window.btoa(params.join(';'));
}
function decodeParams(string){
return window.atob(string).split(';');
}
var searchParams = decodeParams($routeParams.searchParams);
scope.search = function(params){
$location.path('/search/' + encodeParams(params));
}
}
My solution may be looks not so glad, but it's works at least:
You may organize your routs in way
yoursite.com/term1Name/**:param1**/term2Name/**:param2**/term3Name/**:param3**
To make it's clear, you may do your routes seems like REST routes. For example I'm want to go to a list of a services:
www.yoursite.com/servises/
Go to the one of the services:
www.yoursite.com/servise/:id
And if I'm want to see some of the service details, I'll do:
www.yoursite.com/servise/:id/details
and so
www.yoursite.com/servise/:id/detail/:id

Handling view options via Backbone routes

I've been developing large Backbone Marionette applications for about a year now. One thing that has always been challenging is passing around options for view states in routes. Examples of options for view states would be active tabs, temporarily selected items, or sorting options on the page that need to be linkable.
Before updating to Backbone 0.9.9+ the best way that I found to deal with these cases was to add query parameters to the end of my routes. My router would look something like this:
"/questions/:id/" : "showQuestions"
"/questions/:id/?*params" : "showQuestionsWithFilters"
Which would match something like:
"/questions/1/?search=help&sort=name"
The real advantage to this that I found is that the router will match different routes based on the presence of url parameters. Clearing all url parameters and then triggering navigation will actually cause a route change.
After Backbone 0.9.2 routers no longer recognize url parameters. In the above example, the "showQuestions" method would get fired regardless of the presence of a url parameter. The general consensus in this GH issue (https://github.com/documentcloud/backbone/issues/891) and the opinion of the Backbone contributors seems to be that url parameters should NOT be used on the client side at all and instead all information that needs to be passed on to a view should be stored in the main url path (https://github.com/documentcloud/backbone/issues/2440).
A router using this method might look something like:
"/questions/:id/(search/:term)(sort/:type/)"
The problem with this method is that every optional parameter needs to be explicitly added to the router and that all parameters must be ordered accordingly else they will not match. Because there is no delineator between the route and its options and the order is determined by the router, it seems unnecessarily difficult to add or edit options on the fly.
At this point I'm stuck between keeping my current url structure and trying to figure out a way to make it work or migrating over to the latter approach. Before I go too far in either direction I'm wondering if there are other opinions on best practices for similar use cases.
What would you recommend?
There's another piece of a route called a splat. From http://backbonejs.org/#Router:
Routes can contain parameter parts, :param, which match a single URL
component between slashes; and splat parts *splat, which can match any
number of URL components.
In my app, I'm using one required param, and then any number of optional "filters":
var BrowseRouter = Marionette.AppRouter.extend({
appRoutes: {
'browse/:page(/*filters)': 'browse'
}
});
My URL is then formatted with a series of key/value pairs separated by slashes: #/browse/3/type:image/sort:date/count:24.
In my controller, I'm passing the function two arguments: page and filters. page is a simple value ("3"). filters is optional, and is a longer string that contains everything after the page value ("type:image/sort:date/count:2").
I have an "explode" underscore mixin to take that string and convert it to an object.
_.mixin({
/*
* Take a formatted string (from the URL) and convert it into an object of
* key/val pairs. If the val looks like an array, make it so.
* _.explode("count:105/sort:date/type:image,video")
* => { count: 105, sort: date, type: ['image','video']}
*/
explode: function(str) {
var result = {};
if(!str){
return result;
}
_.each(str.split('/'), function(element, index, list){
if(element){
var param = element.split(':');
var key = param[0];
var val = param[1];
if (val.indexOf(",") !== -1) {
val = val.split(',');
}
result[key] = val;
}
});
return result;
}
});

Resources