What is the equivalent of document.location.pathname in angular's $location? - angularjs

There is a mismatch between document.location.pathname and $location.path().
I have an angular SPA running out of something like http://myhost.com/services/coolstuff.
When you navigate to that location, I have some router rules to navigate you to something like: http://myhost.com/services/coolstuff#/users/1.
At this point, you can call $location.path() and it will give you /users/1. And document.location.pathname gives you /services/coolstuff.
Is there a mechanism to retrieve the actual URL path from $location? I don't want the Angular hash path (/users/1), but the actual URL path (/services/coolstuff). How can I get that?

A bit late to the party here, but the parsing section of the URL specification is very specific about this (and super tedious to read...):
The gist of the above specification is, that an unencoded # character denoted the start of the URL fragment, which is not part of the path.
This essentially means, that $location.path() behaves differently from what the URL specification defines. An implementation compliant with the spec has to return /services/coolstuff as document.location.pathname consequently does.
In general, if something is supported in native JS, I would always opt for that, since you can be sure (as you see from your example) that browser implementations adhere to the specified standards which is often not the case for third party libraries.

Related

Resolving relative $resource path in Angular 1.5

My Angular 1.5.8 web application is at http://www.example.com/foo/ and my RESTful list of bars is at http://www.example.com/foo/api/bars. When ui-router goes to the list of bars in Angular, my browser is at http://www.example.com/foo/#/bars. I simply want to connect to a RESTful resource to connect to http://www.example.com/foo/api/bars using HTTP GET.
So I try the most obvious thing:
$resource("api/bars/")
In my mind that should resolve api/bars/ to the current path http://www.example.com/foo/#/bars to give me http://www.example.com/foo/api/bar, right? But it doesn't work (even though I could swear it worked with $http). Instead it gives me a $resource:badcfg error.
Angular lets me do the following, but this doesn't produce the correct path, instead giving me http://www.example.com/api/bars:
$resource("/api/bars/")
So I try $browser.baseHref(), but that seems to be set to the empty string (why?), producing http://www.example.com/api/bars again.
$resource($browser.baseHref() + "/api/bars/")
I tried to use $location.path(), but Angular thinks I want the path after the hash sign, so that doesn't work, giving me http://www.example.com/bars/api/bars. Doh!
$resource($location.path() + "/api/bars/")
How can I simply resolve api/bars/ to the base path of the current URL http://www.example.com/foo/#/bars, producing http://www.example.com/foo/api/bars (or even just the path)?
Note that it is not acceptable for me to hard code an absolute path, or to change my HTML code. Why should I? Besides, this application will be mounted at two places on the same server (hey, it's easy with Java, Tomcat, and JAX-RS), at http://www.example.com/foo/ and http://www.example.com/foo-demo/. The application should run unmodified under each location, accessing the RESTful API list of bars at http://www.example.com/foo/api/bars and http://www.example.com/foo-demo/api/bars, respectively.
This is not complicated; this is simple "URI syntax 101" which has been outlined in RFCs for over two decades. I simply want to resolve api/bars/ to the base path of the current URL http://www.example.com/foo/#/bars. How do I do that in Angular 1.5?
OK, there's two ways to do this. If you absolutely want an absolute path, you can use this:
$resource(location.origin + location.pathname + "api/bars/")
Note the use of the location object location.origin to establish the protocol, domain, and port; and location.pathname to establish the base path. (Once again Microsoft will throw a wrench into the works: location.origin doesn't work on IE11 on some versions of Windows 10.)
But the better approach is simply to use:
$resource("api/bars")
"Wait, I thought you said that this will give you an error!" you might exclaim. Well it turns out I was wrong about that. I was indeed getting an error, but it was because I hadn't set the Accept header to ask for JSON, and the plain/text response I was getting (that's the default on my RESTful resource) was confusing $resource. It turns out that a relative URI will work after all.
It is possible to use relative-path syntax for $resource as you can use it with $http which is used by $resource. This can be done by omitting the leading slash (as you suggested) or by prefixing the resource with ./.
Your badcfg error seems more likely to be the case because your request works out correctly but the server response does not match the expectations. So probably you are returning a single object instead of an array. Please use the dev tools to debug what is really returned from the server.
See the docs on $resource for details.

How to configure angular ui-router state that will match any and all present query parameters?

The Problem:
I'd like a single ui-router state to match the following urls:
#/.../update?id
#/.../update?username
#/.../update?customerId&sandwichId
If/when the 'update' state is active (it's a routed component), the component's controller knows enough to expect which params will be there (via a provided array of Strings that should/will match whatever query params are in fact present).
Current Solutions (none of which I'm 100% happy with)
I could just leave the url at '#/.../update' with the implicit understanding that I cannot navigate to that url from anywhere but it's parent state, and just pass in its primary key fields as a component binding. The drawback obviously being if I just type the URL in my browser, it will not have enough information to load.
As per an example I found here, I defined my 'update' state with single query parameter: pkKeys. I then define pkKeys upon my state transition to be the entire query parameter string I desire. This effectively achieves what I am looking for. However, typing this just doesn't feel right:
#/.../update?pkKeys=username=test
Moreover, it looks ugly on the more complicated situations:
#/.../update?pkKeys=customerId%3D3ae2e6eb-3bf7-42f8-a09c-9c690c8dbe15%26sandwichId%3D2cb6d513-06a3-4aa4-93bb-e53d279d95cb
Ideal Target State
Ideally, I'm looking for a way to configure my state in a way that matches the above patterns of urls. I did not have much success with $location service, but something tells me that has something to do with it. It appeared to me that $location.search() was cleared whenever $state.go( ... ) was invoked.
Thanks for any help in advance! Happy to elaborate on anything that might not be clear. It's a rather unique problem set I find myself in here...
On Further Research
For reference, I'm using Angular UI Router 1.x. I have found they have the notion of dynamic parameters, which seems to nearly solve the problem I am encountering (see the GitHub issue for this change). However, where this fails me is the state configuration still expects you to list the dynamic parameter's name. As my query param names are data-driven, the set of names is not a finite set. So I need dynamic parameters...with dynamic names.

Marionette Router Query String Parameters In URL Fragment Routes

I'm working on a project that requires that most UI state is reproducible via URL. In a traditional (server-side) app, I could use both URL parameters like:
/resources/:id
and unordered optional query string parameters, like:
/resources/:id?page=5&sort=date
Is there an idiomatic way to achieve this with Backbone/Marionette routing? I don't want to have to configure routes for every possible combination of parameters.
The fact that I don't see this addressed much makes me think I may be barking up the wrong tree, approach-wise, but I do think being able to represent as much UI state as possible in the URL is pretty important to a lot of projects.
It looks like the best option is the now-orphaned backbone-query-parameters project.
It supports routes exactly in the form I'm looking for:
#resources/:id?flag=true
URL parameters are not really enforced by Backbone/Marionette. One possible reason is that URL parameters are not SEO friendly.
Instead, you can configure optional URL fragments which will work pretty much like URL parameters, this way:
/resources/:id(/page/:page)(/sort/:sort)
If you do this way, the only gotcha here is that this sequence of "parameters" need to be ordered.
HOWEVER if you need it to be unordered, you can simply use Regular Expressions with router.route() method inside your initialize, as explained in Router#route

React-router: Passing data through routes

I'm trying to figure out the best way to pass data through my routes. I know I can use params but there are certain types of data that don't belong in params.
For example: I have an index page that displays a list of applications. Each application has a button next to it which will route you to the view for that application.
I want to pass the application itself to the Application handler. However, it doesn't make sense to pass the entire application through params. Though it does make sense to pass the application identifier to params (i.e. :id or :name)
So the way I think I should be doing this is pass the application identifier to params, then in the Application component search my ApplicationStore for the appropriate application given the identifier.
Though, wouldn't it be easier and faster to pass the application itself? Is there a way to do this. Is there a reason not to do this?
Here is some code:
<Link to="showApplication" params={{name: application.name}}>View</Link>
or
<Link to="showApplication" params={{application: application}}>View</Link>
Thanks in advance!
The problem is that when the person refreshes, or in some other way directly loads the url, it needs to show the correct view. Because URLs are just strings, you need to represent the route as a string. You can't (easily) shove an actual application into the url.
The job of a router is to take that string (the URL) and map it to the actual code (the handler), and provide any extra data (the params, query, and/or hash).
Your job as a router user is to ensure there's enough information in the URL for the router to pick the right handler, and for the handler to have enough information to do its job (e.g. which application to show).
If the url is something like mysite.com/showApplication, there's clearly not enough information.
If it's something like:
mysite.com/showApplication/React.createClass(%7Brender%3A%20function()%7Breturn%20React.createElement('div'%2C%20null%2C%20%22I'm%20an%20application!%22%7D%7D)%3B
i.e. putting an application in the url, that's too much information, and generally a very bad idea.
But mysite.com/showApplication/applicationName is just right :-)
I'll provide an easy and hacky way, have a global object which you use to share information across routes eg.
window.CONTEXT = {'share':'this'}
Note that it's quite important only to use this way if the object you want to share can be recreated by the route itself, as FakeRain mentioned above the route has to contain just enough information for it to give the user the same experience if they reload.
The only reason you'd use this is to save bandwidth if you need to request information for what you want to share but yet you don't want a huge link.

Cakephp Routing not giving the correct result

I am using cakephp 1.3. here's my problem:
I have a controller named "learns" and a method named "classroom".
To access the classroom method, I use this link: http://www.url.com/learns/classroom/15
I wanted it to be like this: http://www.url.com/class/15
And this is how I setup the routes:
Router::connect('/:class/:id', array('controller' => 'learns', 'action' => 'classroom'), array('id' => '[0-9]+'));
I don't really know why its not working though. I read through the documentation and I just copied this solution from the cookbook..
Thanks for the help in advance.
I don't see anything wrong with your Router statement. Though I am not sure if you actually wanted /:class/:id instead of "/class/:id". See the difference? A Colon is missing in the 2nd version.
This tells the Router that any request that begins with /class/[an-id] should be mapped to whatever your rule is. Where as having it as /:class means you are passing an argument to the router. It can be anything /foo/15 or /bar/15 and these arguments will be available in your $this->params['class'] and $this->params['id']., assuming this rule -> /:class/:id
In your question you state that "I don't really know why its not working". Please avoid these kind of statements as it does not say any thing about the actual problem.
Instead tell us what were you expecting? And what did you see instead? Was it an error? Or a Warning? If you see something else entirely, for example a different action got executed, it is probably due to the fact how routers actually work. If you had a greedy route and a normal route like this:
/users/* and
/users/:id
The second url will not be matched for any request as /users/* is greedy and will hog all the requests to itself, unless the first routing rule returns false.
If this is your situation I would suggest you read up on how to write custom route classes. In summary custom route classes try to make a greedy route less greedy. For a better explanation here is an excellent article by mark story: http://mark-story.com/posts/view/using-custom-route-classes-in-cakephp
Routing in cakephp is one of the most confusing topics and might take a while before you get your head around it. Cookbook is your best friend. Read and Re-read everything until you are sure what each routing element does in a routing rule.

Resources