Marionette async model fetching not working as expected
-
21-12-2019 - |
题
I'm running into a weird issue. I have a Marionette module responsible for fetching data, which is exposed through Backbone.Wreqr
Request/Response system. For my projects it looks like this (CoffeeScript):
@App.module 'Entities', (Entities, App, Backbone, Marionette, $, _) ->
class Entities.Project extends Backbone.Model
urlRoot: '/api/project'
class Entities.ProjectsCollection extends Backbone.Collection
model: Entities.Project
url: '/api/projects.json'
API =
getProjectEntities: ->
projects = new Entities.ProjectsCollection
projects.fetch()
projects
getProject: (project) ->
project = new Entities.Project({ id: project });
project.fetch()
project
App.reqres.setHandler 'project:entities', ->
API.getProjectEntities()
App.reqres.setHandler 'project:entity', (project) ->
API.getProject(project)
For the collection this works entirely as expected. Data is fetched, and when I pass it to a Marionette.CompositeView
the view is rendered just fine.
I'm fleshing out a detail-page for these projects now, and all is not well. When I request a specific model by instantiating a new model currentProject = App.request 'project:entity', project
, and then pass it on to a Marionette.ItemView
, the ItemView parses its template before the model is fetched, causing an Uncaught reference error
because the variables in my template haven't been declared yet... Any idea what's going on here?
My template is for now extremely simple:
<script id="project_detail_template" type="text/template">
<h1>Hello world!</h1>
<p><%= title %></p>
</script>
Edit: Ok, apparently I'm doing more things wrong here, because when I log out this model to the console, all it has attribute-wise is its id
. If someone could set me in the right direction that'd be great.
解决方案
You're calling fetch
and then immediately returning the project
object, without waiting for the async fetch
to complete.
Instead of returning the project
object, return project.fetch()
as this will return a promise. Then you can .then
the value, ensuring it is available:
@App.module 'Entities', (Entities, App, Backbone, Marionette, $, _) ->
class Entities.Project extends Backbone.Model
urlRoot: '/api/project'
class Entities.ProjectsCollection extends Backbone.Collection
model: Entities.Project
url: '/api/projects.json'
API =
getProjectEntities: ->
projects = new Entities.ProjectsCollection
projects.fetch()
getProject: (project) ->
project = new Entities.Project({ id: project });
project.fetch()
App.reqres.setHandler 'project:entities', ->
API.getProjectEntities()
App.reqres.setHandler 'project:entity', (project) ->
API.getProject(project)
When making the call through reqres, you'll get a promise back.
App.request("project:entity", someId, function (promise){
// wait for the project to finish loading
$.when(promise).then(function(project){
// do stuff with your project, here
});
});