Lookup route for URL in Ember? - ember.js

Does Ember expose an API I can use to manually look up a route (as a dot separated path) from a URL?
For example:
Ember.routeForURL('/foo/bar')

There is no public API for that as far as I know. What you can do is use router's recognizer.
let owner = Ember.getOwner(this);
let router = owner.lookup('router:main');
let handlers = router.router.recognizer.recognize('/foo/bar')
"handlers" will contain an array of objects where handler property will be something like this ["application", "foo", "foo.bar"]
And then you can probably use the last handler to do
owner.lookup('route:' + lastHandler)

Related

How to maintain unknown/wildcard queryParams through a transition?

I have a route (route-a) that transitions to another route (route-b) and I am trying to find a way for the destination URL to maintain the all query parameters, even if route-b does not know about them in advance.
For example, if a user visits https://example.com/route-a/?var1=x&var2=y, and the transition to route-b happens like this:
afterModel(model, transition) {
this.transitionTo('route-b', model, {queryParams: transition.to.queryParams}) // transition route-a to route-b
}
...the ultimate URL will be https://example.com/route-b/ — without the query params.
Now, I realize the "Ember way" is to define the queryParams on route-b's controller in advance, but in this particular use-case, I do not know the queryParams in advance. Route B consumes any and all query params provided to it, which means they would be impossible to enumerate in advance.
How can I transition to a new route without dropping query parameters that are not specifically enumerated on the destination route's controller?
Is there a way to handle unknown queryParams, or is there the notion of a wildcard for queryParams (similar to *path routes)?
Update: I'm not marking this as the answer, because as jelhan notes below, using a computed property for this key is explicitly identified as a no-no in the docs. But it worked for our use-case, and it might for others, though I'm guessing it may break down if you have additional queryParams in other routes that might conflict when Ember attempts to combine them.
Previous answer:
My solution here ended up using Ember's computed method to auto-generate the Array of query params by parsing the URL.
queryParams: computed("router.location", function () {
let qp = this.get("router.location").getURL().split("?")[1];
if (qp) {
let qpAsObj = JSON.parse(
'{"' +
decodeURI(qp)
.replace(/"/g, '\\"')
.replace(/&/g, '","')
.replace(/=/g, '":"') +
'"}'
);
return Object.keys(qpAsObj)
}
})
If you don't want to subsequently maintain those query params on the page/model the next time a user re-visits that page ("sticky query params"), you will also need to remove the queryParams on the route:
resetController(controller) {
// unset all queryParams when leaving the route
controller.queryParams.forEach(v => {
controller.set(v, null)
})
}
This solution is... not ideal, but it works and we have tests written to ensure that we will catch any errors if it breaks going forward.

How to determine the Ember route name from a URL?

I need determine the route name from a URL string.
This is normally work that the Router does internally, but because of {insert long story here} I need to do it manually. I am given a piece of data from the API that looks like 'gallery/123' and I need to know the route name is 'gallery.post'. So that I can do route.replaceWith(determinedRouteName);
Need to turn 'gallery/123' into 'gallery.post'
Need to turn 'stuff/99/comments' into 'stuff.post.comments'
Etc
Ember relies internally to the router-recognizer micro lib. I think that your best option is to use it as well.
Unfortunately, accessing the router instance is currently requiring to rely on the private -routing service. (Note: here is a pending RFC about offering a public router service).
Injecting this private service:
import Ember from 'ember';
export default Ember.Route.extend({
router: Ember.inject.service('-routing'),
...
});
The recognize function returns the list of all handlers that you can join if you want to build the complete string or anything else.
Ex:
this.router.recognize("stuffs/99/comments");
> [{handler: "application", ...},
handler: "stuffs", ...},
handler: "stuff", ...},
handler: "comments", ...},
handler: "comments.index, ...}]
Hope it helps
Are you going to always only have one ID in the route? Or will the first ID always be the 'post' ID at least? If so you this isn't really an Ember issue it would just be a JavaScript find/replace that always follows the same format assuming the API data always come back in the same format.
Assuming the API always provides this format:
"something/:post_id/optionally_something_else"
You could take the string that the API provided and run it through a couple replace methods:
var apiString = "stuff/99/comments";
apiString = apiString.replace(/[0-9]+/, "post").replace(/\//g, "."); // => "stuff.post.comments"
// Also works with:
var apiString = "gallery/123";
apiString = apiString.replace(/[0-9]+/, "post").replace(/\//g, "."); // => "gallery.post"
DISCLAIMER: This is pretty icky and will break if the string doesn't follow this format. It will also only covert the first set of digits to "post". But as usual, use it if you must :P

Ember.js: Is it possible to inject a dependency on a specific Route/Controller Mixin?

Let's say I have a SessionManager instance which I want to be accessible in every Route extending my ProtectedRoute Mixin, is it possible to inject this dependency into a "group of routes" as I can reference a single Route instance?
So instead of:
App.inject('route:protected1', 'sessionManager', 'session_manager:main');
App.inject('route:protected2', 'sessionManager', 'session_manager:main');
....
I could do something like
App.inject('route:protectedmixin', 'sessionManager', session_manager:main);
You certainly can, but it might involve a bit of juggling. You could define any logic to decide what to inject and where if you want to rely on the default conventions you could manually find this objects and then use the fullname when injecting.
Another option would be to do it for each route, regardless of whether they include the Mixin or not. Inject doesn't need the full name, if you call `App.inject('route', ...) it would work by default.
If going with option one, it would look something like this. You basically need to find those routes implementing their mixins and then inject into all of those.
var guidForMixin = Ember.guidFor(App.YourMixin);
var routesToInjectInto = Ember.keys(App).filter(function (key) {
var route, mixins;
if (key.match(/Route$/))
route = App[key];
mixins = Ember.meta(route).mixins;
if (mixins) {
!!mixins[guidForMixin];
}
return false;
);
routesToInjectInto.each( function (key) {
var keyForInjection = Ember.decamelize(key);
App.inject('route:' + keyForInjection, 'sessionManager', 'session_manager:main');
});
Also I would suggest doing all of this inside an initializer, but that might be a minor consideration.
Ember.onload('Ember.Application', function(Application) {
Application.initializer {
name: "sessionManager"
initialize: function (container, application) {
// do the above here. Refer to app as the namespace instead of App.
// use the container instead of App.__container__ to register.
};
});

route query for play framework 1.2.5

I need to add a route for the following syntax:
http://www.testsite.com/select?term=query1
In my routes file, I tried using the following
GET /select/{term}
However, the above does not catch the URL - instead it goes to another handler in the config (placed beneath the handler for select/{term}:
GET /{auth}
Any thoughts on fixing or troubleshooting this would be most welcome. thanks
?term= means that term is a parameter - not part of the route you are trying to match
so you'd write
GET /select YourControllerClass.yourMethod
....
YourControllerClass extends Controller {
public static void yourMethod(String term){
Logger.debug("term=" + term);
}
}
If your URL was http://www.testsite.com/select/query1 then the route definition you provided above should work

sitecore query items by client url

I am looking for a quick and dirty way to query the layouts files of a particular page by its friendly url. This is probably easy, but I can't find the solution.
Basically I want to say something like the following. Pseudo-code:
var mainpage = Sitecore.EasyQueryUtility.GetItemByFriendlyUrl(requestedUrl);
or
var mainpage = Sitecore.EasyQueryUtility.GetOppositeOfFriendlyUrl(friendlyurl);
It sounds like you want to do two things here:
Determine an item based on its rendered URL in the address bar (i.e. friendly URL)
Determine the layout being used by the item once you determine the item.
If those are correct, hopefully this can help you out:
Note: untested code I did on-the-fly
// if you have the full URL with protocol and host
public static Item GetItemFromUrl(string url)
{
string path = new Uri(url).PathAndQuery;
return GetItemFromPath(path);
}
// if you have just the path after the hostname
public static Item GetItemFromPath(string path)
{
// remove query string
if(path.Contains("?"))
path = path.split('?')[0];
path = path.Replace(".aspx", "");
return Sitecore.Context.Database.GetItem(path);
}
Once you have the item you can get the layout's name like so:
item.Visualization.GetLayout(Sitecore.Context.Device).Name;
Or the layout's physical file path to the ASPX:
item.Visualization.GetLayout(Sitecore.Context.Device).FilePath;
If you want to get the path of the aspx file which is used for the layout of your page, you can use:
Sitecore.Context.Item.Visualization.Layout.FilePath
I may have misunderstood you but if you want to control the format of friendly URLs you can set several attributes via the Sitecore.Links.UrlOptions class and pass an instance of this in to the link manager. See here for more details. (Note - the LinkManager class is only available from SiteCore 6 I beleive).
The code you would end up with looks like this:
Sitecore.Links.UrlOptions urlOptions = (Sitecore.Links.UrlOptions)Sitecore.Links.UrlOptions.DefaultOptions.Clone();
urlOptions.SiteResolving = Sitecore.Configuration.Settings.Rendering.SiteResolving;
string url = Sitecore.Links.LinkManager.GetItemUrl(item, urlOptions);
You can then set fields like AddAspxExtension on the urlOptions you pass in.
As you can see, the process is reliant on you passing in an item - whether it be obtained via the current context or retrieved from the URL you start off with.
If you were asking about obtaining the layout definition item, take a look at this which shows you how.