问题
I'm building an office reception app in Ember. When a person arrives at the office, they pop open the app and are taken through a three step wizard:
- Choose a reason for visiting
- Choose the person you've come to see
- Confirm
The app also allows an administrator to view all of the visits and to view an individual visit.
I have Visit
and Person
models I've hooked up to a server using Ember Data. Here's what my routes look like:
App.Router.map () ->
@resource 'visits', ->
@resource 'visit', { path: '/:visit_id' }
@resource 'new', ->
@route 'welcome'
@route 'directory'
@route 'thanks'
This allows me to create a new Visit
model in the VisitsNewRoute
and use it in the welcome
, directory
and thanks
views.
This works. However, it feels wrong to have a new
resource, especially since it's conceivable I'll want at least one more new
route in my application.
Is there a better way to do this?
回答1:
I think that you can change the new
resource to newVisit
like this:
App.Router.map () ->
@resource 'visits', ->
@resource 'visit', { path: '/:visit_id' }
@resource 'newVisit', ->
@route 'welcome'
@route 'directory'
@route 'thanks'
Now you will have a NewVisitRoute
where you can create a new Visit
model to use in each of the child routes.
And you will be able to make a transition to this routes with the route names: newVisit.welcome
, newVisit.directory
and newVisit.thanks
. You can use this route names in a link-to
helper link this:
{{link-to "Welcome", "newVisit.welcome"}}
回答2:
The recommended practice is to use a create
/new
route under the resource type, so new
under visits
, then `transitionTo('visit.welcome', newRecord). (I'm saying all of this with the assumption that welcome, directory, and thanks aren't part of the new record creation).
App.Router.map () ->
@resource 'visits', ->
@route 'new'
@resource 'visit', { path: '/:visit_id' }
@route 'welcome'
@route 'directory'
@route 'thanks'
回答3:
Ember doesn't always name routes the way you want when dealing with routes nested more than one level. I would name your 'new' route as follows:
@resource 'visits.new', path: 'new', ->
There are a number of approaches you can use to structuring your routes depending on how you assign model ids and whether or not you are using localStorage
to preserve user edits until they are persisted to the server.
I have my route pattern as follows:
App.Router.map () ->
@resource 'visits', ->
@route 'new'
@route 'crud', path: ':visit_id'
My 'new' routes create a new resource in the routes model
callback which in my models auto-generates a v4 UUID. The new route then performs a transitionTo
the crud route in the afterModel
callback. In effect the 'visits.new' route acts as a trampoline and allows you to easily use {{link-to 'visits.new'}}
from templates/menus etc.
The above approach allows you to to have a single crud route and crud controller that can handle all the show/create/update/delete actions for the model. The models isNew
property can be used within your templates to handle any differences between create and update.
I also use localStorage
so that newly created (but not yet persisted) models survive a browser refresh, the UUIDs really come in handy for both this and for persisting complex model graphs.
The above router pattern occurs quite a lot in my app so I have defined some base Route classes and a route class builder but the general pattern is as follows:
If using UUIDs:
App.VisitsNewRoute = Em.Route.extend
model: (params, transition)->
App.Visit.create(params)
afterModel: (model,transition) ->
@transitionTo 'visits.crud', model
App.VisitsCrudRoute = Em.Route.extend
model: (params,transition) ->
App.Visit.find(params['visit_id'])
If not using UUID's then the routes are different. I did something like this before I moved to UUIDs, it treats model id 'new' as a special case:
App.Router.map () ->
@resource 'visits', ->
@route 'crud', path: ':visit_id'
App.VisitsCrudRoute = App.Route.extend
model: (params, transition) ->
visit_id = params['visit_id']
if visit_id == 'new' then App.Visit.create() else App.Visit.find(visit_id)
serialize: (model, params) ->
return if params.length < 1 or !model
segment = {}
segment[params[0]] = if model.isNew() then 'new' else model.get('id')
segment
For your specific case of managing the wizard step state I would consider using Ember Query Params, which allow you specify the current step in a parameter at the controller level
Query params example:
App.VisitsCrudController = Em.ObjectController.extend
queryParams: ['step'],
step: 'welcome'
Link to next step in the view:
{{#link-to 'visits.crud' (query-params step="directory")}}Next{{/link-to}}
You may also want to define some computed properties for the next and previous steps, and some boolean properties such as isWelcome
, isDirectory
for your view logic.
来源:https://stackoverflow.com/questions/23947532/creating-a-new-resource-in-ember