Angular - how to access multiple url parameters using $state - javascript

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

Related

Vue 3 - Best way of using URL parameters for bookmark (like filtering)

I want to extend my application with a URL parameter functionality:
If a filter is activated, the URL needs to be updated
If someone goes directly to the URL you should get the same data as you filtered manually
I see different ways in this world:
The parameter story based on: domain.com/?status=pending&relation=1
Clearer/neat way: domain.com/filter/status:pending/relation:1
I'm more looking for the last example. How can I do this within Vue? I am currently working as an example within Router with props: route => ({ query: route.query }).
Can someone help me and maybe others on my way to realize this?
It dependes....maybe is better to create an api that refresh your table...
In this way you pass the parameter to the api that will get you the book array, and in this way you refresh your content...
In this way you will have a url like:
domain.net/page?f=1p=filterparamete
Or you can use vue dynamic routing
/page/:filter/:filter_value
But in this case you shold have a fixed url structure in case of multiple filter setting..
In any case the first way is the most easy and scalable way...
You can use the query-string lib to parse URL parameters and then just filter items by params
const queryString = require('query-string');
console.log(location.search); // '?status=pending'
const parsedParams = queryString.parse(location.search);
console.log(parsedParams) // { status: 'pending' };

How to persist optional state parameter on browser back in ui-router?

I'm having one parent state that has two children's state inside that I'm going to show one state based on the URL.
Out of those two states one is having to parameters like param1 and param2, I have use params option of ui-router inside state definition.
State
$stateProvider.state('tabs.account', {
url: '/account',
views: {
'content#tabs': {
templateUrl: 'account.html',
controller: function($scope, $stateParams) {
//This params are internally used to make ajax and show some data.
$scope.param1 = $stateParams.param1;
$scope.param2 = $stateParams.param2;
},
}
},
params: {
param1: { value: null }, //this are optional param
param2: { value: null } //because they are not used in url
}
});
If you look at my route the params option is not really introduced inside the URL, that's why I'm considering then as optional.
Problem
Look at plunkr, I've shown two tabs Account & Survey,
Click on Survey tab, then add some data in the textarea which are shown.
Click on Go to Account that will pass those textarea values to
the other Account tab by doing ui-sref="tabs.account({param1: thing1, param2: thing2})" on the anchor
Now you will see the param1 & param2 values on html which has been assigned to scope from $stateParams
Now again Click on Survey tab, you will land on the survey page.
Just click browser back, you will notice that param value is not getting null.
Problem Plunkr
I believe you got what I wanted to ask, why the optional parameter value has not been store? as they have been a part of state.
I know I can solve this issue by below two solutions.
By creating one service that will share data between two views.
By adding parameter inside the state URL. like url: '/account/:param1/:param2', (But i wouldn't prefer this)
I already tried angular-ui-routers sticky states but that doesn't seems to work for me. What is the better way to this?
Is there any way by which I can make my use case working, Any ideas would appreciate.
Github Issue Link Here
I would move the params definition to the parent state, so as to share the optional state params between your two child states.
The child states will inherit the $stateParams from your parent, as such there is no real 'workaround' needed.
Simply inject $stateParams as per usual in your child controllers and you will have full access to the params being passed around. If you don't want to utilise the params in a specific child state, simply avoid injecting them.
This works with;
Back button
Forward button
ui-sref (without params (will keep as-is))
ui-sref (with params (will overwrite))
$stateProvider
.state('parent', {
params: { p1: null, p2: null }
})
.state('parent.childOne', {
url: '/one',
controller: function ($stateParams) {
console.log($stateParams); // { p1: null, p2: null }
}
})
.state('parent.childTwo', {
url: '/two',
controller: function ($stateParams) {
console.log($stateParams); // { p1: null, p2: null }
}
})
If you at any point want to clear the params while travelling within the state tree of parent, you would have to do so manually.
That would be the only real caveat I can see by using this solution.
I realise manual clearing may not be desirable in the case you present, but you haven't taken an active stand against it, as such I feel the suggestion has merit.
updated plunker
One workaround solution is to cache the state params and conditionally load them when entering the tabs.account state. UI Router state config actually lets you provide an onEnter callback for these types of "do something on entering the state" situations.
Here's the basic logic using localStorage as the cache, with working Plunker here:
When you enter the tabs.account state, check for your state params
If you have them, cache them to local storage
If you don't, load them from local storage into $stateParams
Here's an example code snippet for reference (taken from the Plunker):
$stateProvider.state('tabs.account', {
...
onEnter: ['$stateParams', '$window', function($stateParams, $window) {
if($stateParams.param1) {
$window.localStorage.setItem('tabs.account.param1', $stateParams.param1);
} else {
$stateParams.param1 = $window.localStorage.getItem('tabs.account.param1');
}
if($stateParams.param2) {
$window.localStorage.setItem('tabs.account.param2', $stateParams.param2);
} else {
$stateParams.param2 = $window.localStorage.getItem('tabs.account.param2');
}
}],
...
}
One caveat is that your params will persist indefinitely (e.g. across refreshes and sessions). To get around this, you could clear out the cache on application load like in app.run.
One last note is that in the Plunker, I'm accessing local storage directly (through the Angular $window service). You might want to use some AngularJS module - I've used angular-local-storage in production.
I believe that what you want to achieve is not possible without using one of the two solution you provided.
The browser back-button is just keeping the URL history. He have no clue about the ui-router internal states and will just force the URL to change.
Forcing the URL to change will trigger internal ui-router machine but unfortunately ui-router will see the URL change the same as if someone would have change the url by hand.
Ui-router will fire a new route change to the route pointed by the URL. That mean he doesn't know you wanted to go "back" and will just change state to the new one without any parameters.
Summary
Clicking on back button will fire a state change to a new state according to the URL instead of going back to the previous state.
This is why adding the params to the URL solve the issue. Since the URL is discriminatory you'll finally land on the state you wanted.
Hope it helped.
To me this sounds as X Y problem. There are suggested ways to make state params persistent whereas the problem is located out of this surface.
By definition of the question there is data that should be kept independent of states. So it is kind of global relative to states. Thus there should be a service that keeps it and controllers of both states maintain it as required. Just don't pass data that is out of one state's scope in state params.
Sticky states would fit this approach easily since it allows to keep DOM and $scope while another state is active. But it has nothing to do with state params when the state is reactivated.

get angular ui router $location.search() to use Basic URL Parameters

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 ui-router

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.

how to pass "question mark" in url javascript

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`

Categories