Ember sort data in router/ model - ember.js

When the route /facades get visited I want to redirect to the first facade. This generally works, but as the list from the server is not sorted, my code doesn't redirect to the "first" facade. I know how to sort in the controller, but how can I sort in the router/ model by any property?
App.FacadesRoute = Ember.Route.extend
model: ->
#get("store").find("facade")
redirect: ->
facade = #modelFor("facades").get("firstObject")
#transitionTo("facades.show", facade)

redirect is deprecated, the recommendation is afterModel, and findProperty is super easy for finding a model in a collection based on some property in the model or if you don't know exactly you can use sortBy.
App.FacadesRoute = Ember.Route.extend
model: ->
#get("store").find("facade")
afterModel: (model, transition) ->
facade = model.findProperty("someproperty", "value on some property");
// or
facade = model.sortBy("someproperty").get('firstObject');
#transitionTo("facades.show", facade)

Ok, I just found a way which works. Not sure if it's the best, but I think this could be useful to others too:
App.FacadesRoute = Ember.Route.extend
model: ->
#get("store").find("facade")
redirect: ->
sortedFacades = Ember.ArrayProxy.createWithMixins Ember.SortableMixin,
sortProperties: ["id"]
content: #modelFor("facades")
facade = sortedFacades.get("firstObject")
#transitionTo("facades.show", facade)

Related

How dynamically load route in EmberJS?

Need on change search field - load route with params
/search/WORD, path of route, example, /search/:q
How is best way?
In template {{input value=str}} and in controller this.transitionToRoute('search', this.store.find...) . It require loading model in controller and duplicate to route mode:function(){ return this.store.find...}.
In controller call route by url this.transitionToRoute('/search/' + str).
Else?
why not use queryParams?
ie.,
Ember.controller.extend({
queryParams: ['search'],
search: null,
doSomethingWhenSearchChanges: function() {
// do something here...
}.property('search')
});
I would second Christopher's notion of using query params for this case. For such a solution, your route would be /search?q=WORD. This solution is much more flexible and adaptable, especially if you think your search parameters will change over time. For example, you might begin to search on a handful of different attributes, such as name, type, etc. If this occurs, your route would become /search?name=NAME&type=TYPE&etc=ETC.
If you absolutely must use a route as you've defined above, you can forward the param through the route using the model and serialize hooks. In coffeescript...
App.Router.map( ->
#route('search', {path: '/search/:q'})
)
App.SearchRoute = Ember.Route.extend({
model: (params, transition) ->
return { q: params.q }
serialize: (model) ->
return { q: model.get('q') }
})
App.SearchController = Ember.Controller.extend({
strObserver: Ember.observer( ->
#transitionToRoute('search', {q: #get('str')})
).observes('str')
})
For full refresh model need use refreshModel: true http://guides.emberjs.com/v1.11.0/routing/query-params/#toc_opting-into-a-full-transition

Using transitionToRoute with a model with a custom slug

I've got an ember-data model that has an id as well as a server-generated custom slug attribute (which is prefixed with the id if that matters).
I'd like to use the slug instead of the id in all public routres. For that purpose, I have changed the router:
App.Router.map ->
#resource 'strategies', path: '/strategies', ->
#resource 'strategy', path: ':strategy_slug'
and overwrote the serialize method of the respective route:
App.StrategyRoute = Ember.Route.extend()
serialize: (model) ->
{
strategy_slug: model.get('slug')
}
Unfortunately, this does not seem to work when using transitionToRoute from a controller to transition to, e.g., /strategies/123-test:
App.ExampleController = Ember.ObjectController.extend()
[...]
actions:
showDetails: ->
#transitionToRoute("/strategies/#{#get('slug')}")
false
(where #get('slug') returns '123-test')
All output I get in the console after invoking the showDetails action is:
Transitioned into 'strategies.index'
Ember does seem to recognize the slug-based route.
Ember: 1.5.0-beta.2+pre.3ce8f9ac
Ember Data: 1.0.0-beta.6
Is there anything I may have missed?
Edit:
The following variant works and is feasible in this case, but I have another use-case where I have only access to the URL.
App.ExampleController = Ember.ObjectController.extend()
[...]
actions:
showDetails: ->
#transitionToRoute('strategy', #get('content'))
false
I eventually figured out how to solve this. The key is to add a model method to the router, which knows how to turn a slug into a model:
App.StrategyRoute = Ember.Route.extend()
model: (params, transition) ->
App.store.getById('strategy', parseInt(params.strategy_slug))
serialize: (model) ->
{
strategy_slug: model.get('slug')
}

binding controllers from other controllers not working in rc8

In Ember rc6 I was successfully binding a controller JobsTableColumnsController to an attribute columns inside of a controller JobsTableController. The JobsTableColumnsController would be created and bound to the columns attribute automatically.
Here is the code that works in rc6:
App.JobsTableRoute = Ember.Route.extend
model: -> App.Job.all()
setupController: (ctlr, model) -> ctlr.set('content', model)
App.JobsTableController = App.TableController.extend
needs: ['jobsTableColumns']
columnsBinding: 'controllers.jobsTableColumns'
App.JobsTableColumnsController = App.ColumnsController.extend
content: Em.A([
App.ColumnDefinition.create(name: 'Id')
App.ColumnDefinition.create(name: 'Description')
])
In rc8 I have to explicitly set the JobsTableColumnsController to the JobsTableController.columns attribute in the router like so:
App.JobsTableRoute = Ember.Route.extend
model: -> App.Job.all()
setupController: (ctlr, model) ->
columns = #controllerFor('jobsTableColumns')
ctlr.set('columns', columns)
ctlr.set('content', model)
Is this a bug, or do I need to change my strategy of binding controllers to attributes using the needs attribute.
Is this a bug, or do I need to change my strategy of binding controllers to attributes using the needs attribute.
No it's not a bug, the use of somePropertyBinding was quietly deprecated in favor of computed properties. For reference please see the comment by Peter Wagenet here: https://github.com/emberjs/ember.js/issues/1164#issuecomment-23200023
And as for the new strategy you should use Ember.computed.alias.
Example:
App.JobsTableController = App.TableController.extend
needs: ['jobsTableColumns']
columns: Ember.computed.alias('controllers.jobsTableColumns')
This way you don't need the extra work in the JobsTableRoute setupController hook.
Hope it helps.

Validating a transition using the new Async Ember router

Using the non-async router, we could expect redirect on a route to be called only after resolving promises on from the model function. That's no longer the case.
How can something like this be implemented today?
App.ClientRoute = Ember.Route.extend
model: (params) ->
App.Client.findById params.client_id
redirect: ->
unless #modelFor 'client'
#transitionTo 'clients'
As of RC6, you would implement this like so:
App.ClientRoute = Ember.Route.extend
model: (params) ->
App.Client.findById params.client_id
afterModel: (resolvedModel)->
unless resolvedModel
#transitionTo 'clients'
those are two Gists from the developer of the new async router of Ember.js which will explain the new behaviour and show you some examples:
https://gist.github.com/machty/5723945
https://gist.github.com/machty/5647589
Hope they'll help you - I'm reading and following through at the moment and I think everything is really well explained ;)

ember.js: combine search and filter

Having this controller:
App.ProductsController = Ember.ArrayController.extend Ember.PaginationMixin,
sortProperties: ["number"]
I would like to add the "search" functionality, in this (working) way
App.ProductsController = Ember.ArrayController.extend Ember.PaginationMixin,
sortProperties: ["number"]
search: ''
filteredContent: (->
search = #get("search")
#get("content").filter (item)->
name = item.get("name").toLowerCase()
name.match(search.toLowerCase())
).property("submittedSearch")
filterContent: ->
#set "submittedSearch", #get("search")
The problem is that when I apply my search i'm losing my sorting defined before. What could I do?
From the official documentation
Ember.SortableMixin provides a standard interface for
array proxies to specify a sort order and maintain this sorting when
objects are added, removed, or updated without changing the
implicit order of their underlying content array:
Ember.SortableMixin only cares about the content array while we do get, here you're trying to do get on filteredContent which the mixin doesn;t care !
So what I'd suggest you is make the content as computed property which depends on selected search as follows,
App.ProductsController = Ember.ArrayController.extend Ember.PaginationMixin,
sortProperties: ["number"]
search: ''
content: (->
search = #get("search")
#get('products').filter (item) ->
name = item.get("name").toLowerCase()
name.match(search.toLowerCase())
).property('submittedSearch')
Inside the route setupController set the main list to products property of controller instead of content
App.ProductsRoute = Ember.Route.extend
setupControllers: (controller, model) ->
controller.set('products'), App.Products.find()
Now, your content would be filtered courtesy ComputedProperty, sorted courtesy the "mixin"