Ember: get target url from afterModel - ember.js

I have two paths pointing to the same route:
this.route('items', { path: ':fruitName/rotten' });
this.route('items', { path: ':fruitName' });
I am trying to get the current URL from within the afterModel hook of the /items/fruitName route. If I use this.get('router.url'), it will give me the previous URL before the transition. I need to detect if the target has 'rotten' at the end of the path.
I found that transition.intent.url has the path as a string, but only when its manually entered into the browser. If I click a link to transtion, transition.intent.url is undefined.
How can I determine if the transition URL is /items/fruitName/ or /items/FruitName/rotten?

Before determine which url you have, my question is : how do you make a transition with a different url to the same route (by using {{link-to}}) ?
In your case, you have the same route for 2 different purpose, I understand what you want to accomplish but you will break ember rules (which force you to make a bad design).
You can accomplish what you want to do by using nested routes. let me explain:
/:fruitName and /:fruitName/rotten have the same base (same data): a page for a fruit but in the rotten route, you want to display in another tab.
It's a design problem not a route problem, you can make the most of nested route to:
use index to display main content
subroute to display other thing
you can check an example here with a basic css tab.

Could you use queryParams for this? So your URL would look something like this:
items/tomato?rotten=false
or perhaps you want to go with something more generic:
items/tomato?state=rotten
The route and controller will be set up something like what can be found here: https://guides.emberjs.com/v2.14.0/routing/query-params/

Related

Ember router breaks on redirect to '/'

I'm having a hard time making my router understand that we are on a certain page and it should be displayed in the navigation as active. The situation is as follows:
this.route('mainRoute', function() {
this.route('list');
});
The path we are interested in is /mainRoute. Unfortunately, there are a lot of legacy links that point to /mainRoute/list. The workaround for this was to redirect from the /mainRoute/list component back to the /mainRoute component.
beforeModel() {
this.replaceWith('/mainRoute');
}
Now, my issue is that the /mainRoute navigation link will never be seen as active. I've tried adding a path for the /mainRoute ('/', '/mainRoute', 'mainRoute'), I've tried transforming it to a resource and a bunch of other things that passed my mind. But it either won't work, or will go in an infinite redirecting loop.
Any thoughts on it? Thanks so much, I really need a solution for this!
If the navigation links are {{link-to}} components. There is a current-when property you could use here. It accepts either a boolean or a string. The string is a space separated values with the route names you want this link to be active when.
From the docs
If you need a link to be 'active' even when it doesn't match the current route, you can use the
current-when argument.
<LinkTo #route='photoGallery' #current-when='photos'>
Photo Gallery
</LinkTo>
{{#link-to 'photoGallery' current-when='photos'}}
Photo Gallery
{{/link-to}}

How to transition without changing the url in ember 1.11

I have a situation where the back button actually causes harm in my application and I seem to remember a solution in ember where I could have a single link-to helper not update the url (but keeping the routes /link-to helpers for other routes working as usual).
Is this still an option/possible in ember 1.11? If so - how? If no - what other options do I have if I need to prevent a single link-to from allowing the user to go back?
{{#link-to "foo.bar" bar}}details{{/link-to}}
Unfortunately the link-to helper doesn't pass the replace property down to the view itself, the LinkView does have a property replace which will replace the current route in history instead of just adding it to the history.
Option 1
Use an action instead of a link-to, and use this.replaceRoute/this.replaceWith instead of this.transition....
Option 2
Extend the LinkView and set replace: true, dupe the link-to helper code and call it link-to-replace and use your extended LinkView.

How do I display a route parameter?

I'm trying to understand Ember. I can't quite work it out. I currently have the routes:
/participants
/list
/search/:query
And I'm trying to figure out how to get my search page to display that query parameter. The navigation works, I just can't figure out how to display that "query" bit (ie, "You searched for Bennie")
(One thing I tried is that I have an App.ParticipantsSearchController with a 'searchtext' in it, and I know I can display that with {{searchtext}} in the template, but even if I try to later do an App.ParticipantsSearchController.searchtext = 'abc', that doesn't get updated. So that doesn't seem to do me any good.)
I would really appreciate the help from somebody who understands Ember better than I do.
Part of the problem is the parameter is supposed to be representing a unique id of a model representing that resource. If you are going in and randomly changing the unique id, technically your model should be completely different. If your model is completely different you should be transitioning to the route using transitionTo from the route(or transitionToRoute from controller) to switch out models.
And intuitivepixel is correct, you need to be using the set on your model, model.set('searchtext', 'mooooooo');
What will really help you will be the query params that Alex Speller is implementing for Ember. See http://discuss.emberjs.com/t/query-string-support-in-ember-router/1962/44. Until then you'll be doing some really weird transitioning in order to get the url to represent the model. Maybe the url shouldn't update until they've pressed search, or something along those lines. And then in that case, you could call transitionTo/transitionToRoute and then the url would be able to match the current model, so you could type in the url and get straight to that search result. BTW, you can add multiple slugs to a single resource if you are going to have multiple search things. If you do that you'll need to add the serialize method to specify each property...
/search/:age/:sex/:country
serialize: function(model) {
// this will make the URL `/search/12/M/Brazil`
return { age: model.age, sex: model.sex, country: model.country };
}

Transition from one route to another with a different model in Emberjs

I have a search page where we are getting different types of search results. In the list of search results I would like to use
{{#linkTo 'someResources.someResource' result}}{{result.Name}}{{/linkTo}}
And on the route someResources.someResource I want to use a totally different model than on the search page. How do I do that? When I click on the link for the linkTo it doesn't load the model again, instead it tries to use the model named result here.
So what I would like to do is to reload the model when I navigate to someResources.someResource based on the values in result.
The I do have a model named App.SomeResource and a find method for it that works if I go directly to that page.
Ember will bypass the model() hook when using linkTo as you've discovered. The assumption is that you passed a model to it, so it and will use that(result) as the model.
The next hook you can use is setupController. Since you have a model hook that works on the direct route, you can use call it directly from here.
One caveat is that you need to also allow for the direct route loading where the model will already have loaded.
setupController: function(controller, model) {
if (!model.isModel) {
this.model().then(function(result)) {
controller.set('model', result)
}
}
}
model.isModel is this check via an isModel property on the directly loaded model, which should be absent when passed with linkTo.
Note: the above code assumes that you are returning a Promise in your model() hook.
Since the problem is that I want a full reload of the model when doing the transition using linkTo won't work since that is using the model given to it. The solution to the problem is actually quite simple, just use a regular html a-tag instead. What I ended up doing was this:
<a {{bindAttr href="somePropertyInYourModel"}}>{{someTextProperty}}</a>
The property somePropertyInYourModel is a property containing the url to the new page. If the url is in the ember routes it will be as if you where typing that address in the address bar and pressing enter, but without the full reload of the page.
I think this is something that could be improved in ember, it would be much nicer if I could write something like:
{{#linkToRoute "resourceA.routeB" params="val1,val2,val3"}}Go here{{/linkToRoute}}
given I have this routes set up:
App.Router.map(function() {
this.resource("resourceA", {{path: "/resourceA"}}, function() {
this.route("routeB", {{path: "/:prop1/:prop2/:prop3");
}
});
I would like to get:
Go here
The order of the val1,val2,val3 matters, if the order is changed they should also be changed in the final url.

How to make a one page menu in Ember?

I'm wondering how can I make a menu like in this website with Ember ?
The page is split in different sections and we can scroll to go to each section, a click on the menu make the page scroll to the wanted section.
I'm not sure if I should have different routes in the router for this behavior, I would guess it's not the case as when we change route the view is remove from the DOM.
Then, how should I build the anchor link to each section ?
The best solution will automatically updates route when we scroll the page but any solution to handle the link and URL recognition will be fine.
Some may argue otherwise, but Ember may be a little overkill for a website landing page like you've shown. Ember is meant more for robust web apps that have multiple views and data they need to be connected with.
First off, if you look at their script, they're using jQuery to animate the body's scrollTop position to the respective div and setting window.location.hash to the hash of the menu element's href which also happens to be the ID of the <section/> the body scrolls to:
$(document).on('click', '#nav a, .clients-capabilities a', function(){
var target = $(this);
var hash = this.hash;
var destination = $(hash).offset().top;
stopAnimatedScroll();
$('#nav li').removeClass('on');
target.parent().addClass('on');
$('html, body').stop().animate({
scrollTop: destination
}, 400, function() { window.location.hash = hash; });
return false;
});
Secondly, they are not doing anything special to load to a specific position on page load. If you load any page on the web with a hash, the browser will look for an element with that ID and load at that position. For example, http://emberjs.com/#download.
Even if you still want to use Ember for this, you'd probably end up doing something similar with a single view loaded from the / route so I wouldn't even worry about Ember until your site becomes a full fledged web app.
Try using a *: catch all pattern in the router on the page you want to handle this scenario.
so lets say that index will work as a single page that you have to be able to automatically scroll to certain elements from the url.
Also you have posts and about sub pages that you can go to from the index page via links.
then...
App.Router.map(function() {
this.route('about');
this.route('posts');
this.route('index',{path:'*:'});
});
so if you have an element with id="elementToScrollTo" then the url /#elementToScrollTo would load the index page and scroll to that element.
See How to handle 'no route matched' in Ember.js and show 404 page? also for some other ways to solve this.
I hope this helps you.