Ember CLI path based on server response - ember.js

I'm developing a substantial ember app, using Ember CLI, and I'm struggling with a few aspects of it.
What I want to do is:
Show a dropdown list of options
When the user picks an option, post their choice to the backend
The response from the server contains data based on what the user picked in the dropdown. After getting the server response I want to transition to a new route where the path ends with one of the values returned by the server.
For example:
/path/to/dropdown -- shows the dropdown for the user to pick from, which is then POSTed to the backend. The backend responds with, amongst other data:
slug: <stringValue>
This then transitions to:
/path/to/slug -- where slug is <stringValue>
So far I've got 1 & 2 above working, but I can't figure out how to make step 3 work. I've tried using a serialize function in the /path/to/slug route and the /path/to/dropdown controller, but it always returns undefined.
The AJAX call to the server, based on the user's dropdown choice, happens in the /path/to/dropdown controller.
I've set up the router as:
this.route('options', { path : ':slug' });
Would be great if someone could point me in the right direction; I hope my example is clear enough but let me know if not.
Thanks.

To be honest I don't understand why do you use this.route('options', { path : ':slug' });. You just created the only route for all possible options (in fact, for all urls of form /anything), but that's not what you want.
I think your solution is this.transitionToRoute(url_string) which is available in any controller. Check the api example there. But before you should declare all that routes in the router and create operating files for them, of course.
If you don't want to create a route for each possible slug, so then your route is pretty excellent, but at least I'd consider to add one more path section. For example, this.route('options', { path : '/slugs/:slug' });.
After that you can run transitionTo and pass data (in any format) to it. The data will be assigned to the route model and you will be able to use it in the SlugRoute (and SlugController, if you didn't redefined the setupControler method) as a this.get('model') variable.
If you want to run transition from the view, firstly you need to obtain the controller and send a special command to it.

Related

EmberJS "detail" page fetches the model automatically - is this normal?

Long time reader - first time questioner here.
I am developing a medium sized application in EmberJS which is a framework that I have been using for a while.
Today I have realised that it fetches model data from the server without me writing any code.
I have a main route called "students". Then there is a "list" sub route where the model() function of this route calls the store to fetch all the students and lists them on a table.
On each row of this table I link to another sub route called "detail" where it accepts the ID of each student as an argument. However inside the route.js file for this route there is no model() function querying any information about the specific student from the server.
Ember does this automatically somehow as I can see the appropriate network request being made using chrome dev tools.
How is this happening and is it normal?
Thank you in advance.
The Ember router will automatically load a model if it detects a dynamic segment that ends in _id.
Ember follows the convention of :model-name_id for two reasons. The first reason is that Routes know how to fetch the right model by default, if you follow the convention
You mentioned that your api route is /api/student/details/:student_id and I would expect that your ember route is fairly similar.
It detected _id, and called store.find('student', params.student_id) automatically for you when you navigated to that route.
This is completely normal, and is one of the ways Ember encourages you to follow convention - If you do, you don't have to create as much boilerplate.
If you want to avoid the second request, possibly because the list route pulls all relevant data, you can pass the student model instead of the student id.

How do I access the URL that Ember Data will PUT to?

I'm adapting an old JS (no framework) + Rails app as an Ember learning exercise. The idea of the application is that I'm producing a pdf from some data input. In the initial version, there was no user persistence - you could modify the data provided to you in the tables, and then download the PDF of it.
As part of this, I decided to run with a decidedly non-standard ember framework - I'm essentially using Ember Data to load the initial value of the tables. Ember has been a really natural fit for the models I have on the Rails side, and it's made a lot of the more complicated calculations a lot easier. The issue I have is that my initial idea was that when I came to download the PDF, I'd respond to the "save" action on Ember Data with binary data (with an application/pdf header), which I could then use something like FileSaver.js to serve up to the client. Then, I found that EmberData needs JSON return value.
So I base64 encoded my PDF response and fired it back..but it didn't fit the model schema. I thought I'd then do a manual AJAX save -
CalculateYourTV.RostersShowController = Ember.ObjectController.extend({
actions:{
download: function(){
var roster = this.get("model");
var team = roster.get('team');
return this.ajax('*URL GOES HERE*', record.toJSON(), "PUT").then(function(data) {
console.log('called')
console.log(data)
});
},
}
})
And this is where I'm currently stuck. Is there any way to access the URL that EmberData is posting to? I could hard-code a route in the Rails side of things, but I don't like hardcoding routes in here, and I'd like to keep it as reusable as possible (I'm planning to eventually allow data persistance).
Just open chrome dev tools (or firebug) and monitor what's going on in the network tab. You should see any ajax request your application sends out, including the EmberData's save request.
You can change the URL that a specific model will hit by creating custom Ember Data adapters per model.
For example, say you have a person model that needs to not hit the default /persons URL.
App.PersonAdapter = App.ApplicationAdapter.extend({
pathForType: 'special/custom/endpoint/for/folks'
});
That said, Ember Data may not be the best tool here for your PDF "model". You can always use Ember Data for the majority of your models, but use a quick $.ajax for other stuff that doesn't fit your definition of a true model.
You can ask the adapter to build a URL for you -
adapter = #store.adapterFor('application')
url = adapter.buildURL(type, id)
where type is the name of the model, and id is its id.
If want to look up the adapter directly in the container it is
#container.lookup('adapter:application')

How to change a URL in the Ember.js router before a route is assigned?

My Ember.js app requires backwards compatibility for links that went to specific file extensions. (i.e. .pdf) In other words, I an example link like this, to return the PDF:
http://www.example.com/docs/my.pdf
I'm trying to preprocess the URL to remove the .pdf before the Ember.js Router assigns a Route to it, by taking a substring, and assigning it back as the URL to process:
http://www.example.com/docs/my
Obviously, getting the substring is trivial, but I don't know how to inject the updated URL back into the Ember.js Router.
Your approach is non-ember compliant from the start. The solution isn't to update the URL, but to simply use the URL you want in the first place.
Instead of sending the user to
http://www.example.com/docs/my.pdf
Send them to
http://www.example.com/docs/my
And then within one of the related route hooks (beforeModel hook would be my preference), send the my.pdf file to the user.
You could just use transitionTo().
Alternatively this answer suggests using
Ember.HistoryLocation.replaceState(<string>);
or
router.replaceWith('index');

Django Rest/Ember How to connect to models

I am getting started with Ember, and Django Rest Framework and I can't seem to peice together how to connect a model so that Ember can use the data in that model and create a simple drop down box. I have one model that I am starting with that is as such:
id
name
security
status
All I want to achieve is allowing Ember to use the data in this model and create a dropdown like so.
<select id="model">
<option value="model.ID">model.Name</option>
</select>
Can anyone help me with this? I am complete new to Ember and Django Rest.
Without going into a ton of detail, I've created a mini example of what you're looking for
http://emberjs.jsbin.com/Ozimatuj/2/edit
You'll note that I'm using mockjax, so instead of hitting any real endpoint, it's all mocked. Additionally I'd recommend using a client side record management solution (such as ember-data or ember-model). That's another discussion though.
In the application route (which correlates with the root of your app) it hits the model hook (which should return the model associated with that route. I'm returning a POJO of the users. That model is being assigned as the content of the application controller (automatically generated). The the application template is being built, and it's being backed by the application controller. Inside the application template we create an instance of ember select, and we tell it that the content backing it is model (which is the model/content in the application controller). We also say, use bind the user model (you could do id) and the name to the value and the label respectively.
I then bound the value of the select to selectedPerson, so anytime the value changes, the selectedPerson updates, the template which talks about that person will update. Magic. Ember does the rest.
This is a really broad question, so if you have any other questions, please ask a specific question, and I'd really recommend going through the getting started guide, it's really short, but will give you a decent foundation of terminology and methodology of Ember. http://emberjs.com/guides/getting-started/
For Ember Data I'd do a quick read the of the transition document for ED 1.0 beta.
https://github.com/emberjs/data/blob/master/TRANSITION.md
DS.DjangoRESTSerializer = DS.RESTSerializer.extend();
DS.DjangoRESTAdapter = DS.RESTAdapter.extend({
defaultSerializer: "DS/djangoREST"
});

User flow assistance

I'm working on an Ember.js application that contains several models with dependencies. For example, when setting up a model for Client I include the attribute portfolios : DS.hasMany('Portfolio')
When a user enters the app, they are presented an option to immediately add a new portfolio at the route portfolio.add where among other form fields they are presented a drop down to select the client for whom they are creating the portfolio, as well as an option to create a new client via {{#link-to client.add}}. This is NOT the only way a user could get to the route client.add
I'd like for Ember to remember that the user got to the client.add route via portfolio.add, change the text of the submit button to indicate that they will return to portfolio.add after saving, and to transition back to portfolio.add after the promise returns successfully where it will auto select the newly created client in the drop down.
So far I've thought I'd use this answer: How can I get My previous route? to check the previous route, and possibly create a similar mixin for storing a reference to the created client record.
It's a hack, and I'd rather pass related objects/properties directly. Is there a better way?
I ended up advancing my Ember build to Canary and including Ember.FEATURES["query-params"] = true;
I then added a routedFrom parameter when shifting into a view that would need to route back on completion and in the original route's model I added this.transitionTo('originalroute',{routedFrom:null}); to clear the routedFrom parameter.