Filtering Ember results - ember.js

I can work with Ember.js(rc0) and Rails, and have a simple app working as I'd expect, but want to focus on a specific story:
As a user, I want to type in "filter" text in a form, then have my ArrayController only show me those items that match the filter. For example, think of a Contacts app that shows people with the name like "Ya%"...
Caveat: Say the database holds thousands of Contact records. I don't want to filter those contacts on the client, it makes more sense to do that on the server.
Question:
How do I do this in ember.js/ember-data? On the server, I can easily allow for a search parameter in my index URL to filter data so it's a manageable list, or even limit the response to say, 20 items.
I can also use a view to have access to my filter text in my controller, but where do I go next? How can I pass that filter onto the server?
Update:
I was able to use "find" on the model object, and ember (ember data) went to the server to grab new data - as the client side only had a subset of all the Contact records to begin with. Instead of filtering on what on the client, it automatically deferred to the the server... which is nice.
App.ContactIndexController = Ember.ArrayController.extend
search_term: null
submit: (view) ->
this.set('content', App.Contact.find({search: "#{view.search_term}"}))

This is a good use case for findQuery. For example:
store.findQuery(App.Contact, {q: queryString})
This will in turn call findQuery on the appropriate adapter, and if successful, load the returned records into the store and return a DS.AdapterPopulatedRecordArray.
Note that you can completely customize the query object to include params that match your server's endpoints.
Update: As Michael pointed out in the comments, the above is equivalent to:
App.Contact.find({q: queryString})
... which is certainly a cleaner solution, especially without direct access to the store.

Related

How do you use in practice findAll and peekAll in Ember?

From EmberJS documentation i get the following two ways to retrieve all records of a given type, one that makes a request and one that doesn't.
var posts = this.store.findAll('post'); // => GET /posts
var posts = this.store.peekAll('post'); // => no network request
It seems to me that i always need to do first a findAll but isn't clear for my understanding when should i do a peekAll.
For example, the user enters my blog and then i get all the posts using findAll, then at some point in the same flow i need all those post, so i should use a peekAll to save bandwidth. So how should i know that i have requested all posts previously ? Should i save some global state to handle that ?
I would assume that the first time the client request a peekAll if there isn't any record it will automatically do a findAll or maybe i should that manually but it probably introduce some boilerplate.
How do you use in practice findAll and peekAll or they equivalents for single record ? Any recommendation ?
.findAll is cached:
First time store.find is called, fetch new data
Next time return cached data
Fetch new data in the background and update
This is the behavior of the new findRecord and findAll methods.
As you can read in Ember Data v1.13 blog post.
So, taking your example:
var posts = this.store.findAll('post'); // => GET /posts
// /\ or load from cache and update data in background /\
var posts = this.store.peekAll('post'); // => no network request
And:
It seems to me that i always need to do first a findAll but isn't
clear for my understanding when should i do a peekAll.
Yes, you need to do first .findAll, but you are encouraged to use .findAll in all places, as it is cached and suited for multiple requests for data (from many places across application without wasting bandwidth).
For example, the user enters my blog and then i get all the posts
using findAll, then at some point in the same flow i need all those
post, so i should use a peekAll to save bandwidth. So how should i
know that i have requested all posts previously ? Should i save some
global state to handle that ? I would assume that the first time the
client request a peekAll if there isn't any record it will
automatically do a findAll or maybe i should that manually but it
probably introduce some boilerplate.
I think user needs to have always up to date data in your application. What if you add blog post while he is browsing page? If you would use .peekAll() then user would need to refresh page to get latest data.
If you would like to save bandwidth then I would recommend you to implement maybe some kind of additional logic in Ember Adapter, but you have to find way to balance user requests with need to always serve latest data. You can do this by overriding Adapter's methods:
shouldReloadAll: function(store, snapshotRecordArray)
shouldBackgroundReloadAll: function(store, snapshotRecordArray)
See more info about these methods in Ember API docs.
How do you use in practice findAll and peekAll or they equivalents for
single record ? Any recommendation ?
If you are completely sure that you always have up to date data after first request then use .peekAll. There is data can be always up to date, because, for example it almost never changes in your database. It depends however what are your needs and how did you design your data models. It's hard to find good example, but maybe imagine if you would have some models which contain only constants. Like PI value etc. Maybe you have imported it from somewhere and it is complete, closed set of something that will never change. Then, after first .findAll, (for example if it's core function to your application it could be defined in Application route beforeModel hook) you would be sure that no more requests are needed and you have all data.
You could also use .peekAll if your application would have something like Offline Mode and can rely only on data you already have.

How to generate custom unique ID

We are using Sitecore 7.2 with multi-site implementation. The actual data is shared between multisite, hence it's been stored in common Global Item folder.
We are facing a problem generating aunique ID on URL. I had a good search but could not find any solution except to use Sitecore Item ID.
This is what we want:
domain/players/player_id
e.g. domain/players/1234
where 1234 is uniquely generated ID.
Could someone please suggest if this is possible?
Every page that is managed in Sitecore is a Sitecore Item. As such, you should be able to just navigate to the name of the player item. If you were trying to say in your post that player items are stored in globals and not as pages, then you are left with the following options:
Query String: domain/players/player?playerId={ID}
If this is the route that you choose to take then I would suggest using the player item's Sitecore ID for the value of the query string parameter.
If you have other IDs then put the specified ID there, however it would be easiest with Sitecore IDs
What you would then do is get the item with the ID specified in the query string parameter (or get the item with the player ID specified in the query string parameter, depending on which route you take) and display the data for that player on the page
Sitecore.Context.Database.GetItem(Request.QueryString["playerId"])
playerItems.FirstOrDefault(playerItem => playerItem["Player ID"] == Request.QueryString["playerId"])
Note that this assumes that the Player ID is a field, not the Sitecore ID
If it is the Sitecore ID then change the lambda to use playerItem.ID == new ID(Request.QueryString["playerId"]
Regardless of which one you use, I suggest adding null checks to the QueryString getter
Sublayout Parameters
If you use this method, the query string will not change and people will not be able to get to the page from the direct URL
The process is the same as for query strings, except that you are using Sublayout parameters instead
Note that you must set these in a parent sublayout or in Sitecore (which means that you have a separate page for each player - i.e. this would be a bad solution)
Virtual Items
This is really what I think you are looking for
This can be a lot of work if you do it from scratch, or you can use the Wildcard Module
If you do it from scratch, you will need a custom pipeline and/or processor for handling the requests
Good suggestions from Zachary. I will add a couple more:
1) IIS Rewrite Module. If what you are really after is having external URLs look like /domain/players/1234, you could easily accomplish this by forwarding these requests to something like Zachary's option #1. The client sees /domain/players/1234, but it's really handled by a single Sitecore item at /domain/player/player.aspx?playerid=1234. Client doesn't have to know that.
2) Custom ItemResolver pipeline handler. Custom Pipelines may be a bit intimidating at first, but they are actually pretty easy to implement and highly useful. Would be pretty straightforward to add a new one which checked for "players/1234" and set the ContextItem to your player handling page and drop the ID into a session variable or some context variable.

Ember-Data: Adding Server Queries to AJAX Requests

I am having trouble with a specific case using Ember-Data.
Typically Ember expects a model class, the route, the ajax request, and the returned JSON, to all follow a similar pattern.
The RESTAdapter tries to automatically build a URL to send to the server, which is ok for some situations, but I need full control over some of my request URLs particularly when it comes to appending additional parameters, or matching an API to a route that has a completely different URL structure.
Ember sadly, has no guides for this, though I did find something about the buildURL method
I am not comfortable enough rooting through the source code to find out what happens under the hood though I do not want to break ember data just to fix a few use cases.
I have set my RESTAdapter's namespace to api/rest
The model and resource I want to populate is view-debtors
The specific service I want to reach is at debtor/list
I also need to pass extra parameters for pagination ?page_size=10&page_number=1, for example.
I am completely lost how to do this. I cannot change the API structure... there are too many services depending on them.
Some Small Progress
I went ahead and used my current knowledge to get a little closer to the solution.
I created a model and called it "list"
I extended RESTAdapter for "list" to change the namespace to "api/rest/debtor"
I changed the model hook for "view-debtors" route to store.find('list')
The result now is that the AJAX call is almost correct... I just need to add those extra parameters to the server queries.
This is where I stand now... can I add those server queries via the model hook? or better yet can I also control server queries via ember actions to get new AJAX requests?
Stepping back a bit. Is my method so far a good practice? Because I am using a route's model hook, to set the model to list, will this only work if the routes URL is typed in directly?
So many questions :p
You can find by query which will append a query string onto the end of your request using the object provided.
// this would produce /api/rest/debtor/lists?page_size=1&page_number=10
this.store.find('list', {page_size:1, page_number:10});
Personally I think it's a bit hacky to go fudging the model names and namespace to make it supposedly fit your backend's url structure. It really depends on what you're attempting to do. If you want all the full features of CRUD using Ember-Data for this particular list of data, you're going to be hacking the end-point left and right. Whether or not Ember Data really helps you is questionable. If you are just reading data, I'd totally just fetch the data using jquery and sideload it into Ember Data.
var store = this.store;
$.getJSON('/api/rest/debtor/lists?page_size=1&page_number=10').then(function(json){
//fix payload up if necessary http://emberjs.com/api/data/classes/DS.Store.html#method_pushPayload
store.pushPayload('type', json);
}).then(function(){
return store.all('type'); // or store.filter('type') if you want to filter what is returned to the model hook
});
pushPayload docs

Where to save detailed user session information for EmberJS app?

I am building my first EmberJS app, and am still trying to wrap my head around the best practices & conventions. I'm using ember-data to talk to a RESTful API, and have ember-auth working well enough to log in and save a user's ID & OAuth2 access token. However, I'd now like to maintain additional user information (e.g. name, email, etc) for use in the navbar and in various other areas of the app.
To do this, I am thinking it would be helpful to have a User object (model) that is read from a separate endpoint (e.g. /users/<id>). Since this info would be needed throughout the app, I'm inclined to store it on the ApplicationController, somewhat like this example from Ember's docs:
App.ApplicationController = Ember.Controller.extend({
// the initial value of the `search` property
search: '',
query: function() {
// the current value of the text field
var query = this.get('search');
this.transitionToRoute('search', { query: query });
}
});
However, my user object wouldn't quite be an action like query or a property like search, so I'm not sure this example applies.
I think I'll eventually want to call something like:
this.get('store').find('user', App.Auth.get('userId'));
but I'm just not sure where in the app that would go.
Main question: is the ApplicationController the right place for this information per Ember conventions, and if so, what might the code look like to retrieve it from the REST API?
Appreciate any thoughts to put me on the right track.
The general approach that I've taken before is to store the currently logged in user as App.CurrentUser. Then you can use it in any template. Once I've pulled the User object I call Ember.set('App.CurrentUser',user) to store it, and then Ember.get('App.CurrentUser') to retrieve it in other routes or controllers.
Here's a short jsbin with the general idea : http://jsbin.com/ucanam/994/edit

Playframework 2 include a updatable combobox in a list (not a form)

I am using play framework 2.0 .I a page where I list all the elements that the user can edit/delete. one of the listed elements in a look up from another table. I have coded a select in the forms and that works fine.
I would like to include the combo box in the displayed list, so the user can update it right there without having to drill down into each element to update the field. Is there a way to do this? I want to listen to the change in the combobox and update the underlying model.
I tried a few iterations, but the select box seems to want a play.api.data.Field , and not the value I provide.
the parameters to the page is a pageable list like this
#(currentPage: Page[Deal], currentSortBy: String, currentOrder: String, currentFilter: String)
I don't know if I understand the issue, but I think the problem you are stating would be better solved at the client, with some ajax in it...
otherwise, you would be issuing a whole page refresh every time the user updates the items
I would expose the pageable list like a rest-json web service, and I wuld call it from javascript, binding the on-change event...
Here you have an example using select2 to do the lookup and consumign a rest web service: http://bb-jugar.rhcloud.com/assets/js/tmp/select2/demo.html