0
votes

I'm new to Backbone so hopefully I'm just missing something simple. I'm working on building a simple survey creation/survey taking app to work through nested models, etc. I'm running a restful Rails server for the back-end.

I'm struggling with getting the survey models to save to the server though. It doesn't seem like a post request is actually happening and thus it's not actually getting updated. Any ideas what I'm missing?

Survey model:

class SurveyMe.Models.Survey extends Backbone.Model

Survey Edit View:

 class SurveyMe.Views.SurveyEdit extends Backbone.View

      template: JST['templates/surveys/survey_edit']

      initialize: ->
        @model.on('all', @render, this)

      events: {
        'click #back': 'back'
        'submit #survey': 'update'
      }

      render: ->
        $(@el).html(@template(survey: @model))
        this

      back: ->
        Backbone.history.navigate("surveys",true)

      update: ->
        @model.set("title", $('#title').val())
        @model.set("survey_limit", $('#survey_limit').val())
        @model.save()
        Backbone.history.navigate("surveys",true)

Survey Edit Template:

<h1>Edit Survey</h1>
<form id="survey">
<div class="input-group">
    <span class="input-group-addon">Title:</span>
    <input id="title" type="text" class="form-control" value="<%= @survey.get('title') %>">
    <br>
</div>
<br>
<div class="input-group">
    <span class="input-group-addon">Desired Responses:</span>
    <input id="survey_limit" type="text" class="form-control" value="<%= @survey.get('survey_limit') %>">
    <br>
</div>
<hr>
<button class="btn" id="back">Back</button>
<input type="submit" class="btn" id="update" value="Update">
</form>

EDIT: Adding Index/Router/Collection

Index:

class SurveyMe.Views.SurveysIndex extends Backbone.View

  template: JST['templates/surveys/index']

  events:
    'submit #survey':'createSurvey'

  initialize: ->
    @collection.on('reset', @render, this)
    @collection.on('add', @addSurvey, this)

  render: ->
    $(@el).html(@template())
    @collection.each(@addSurvey)
    console.log(@collection.length)
    this  

  addSurvey: (survey) ->
    view = new SurveyMe.Views.Survey(model: survey)
    @$('#surveys').append(view.render().el)

  createSurvey: ->
    console.log("Survey created")

Router:

class SurveyMe.Routers.Surveys extends Backbone.Router
  routes: 
    'surveys/:id': 'edit',
    'surveys': "index"

  initialize: ->
    @collection = new SurveyMe.Collections.Surveys()
    @collection.fetch(reset: true)

  index: ->
    view = new SurveyMe.Views.SurveysIndex(collection: @collection)
    $("#container").html(view.render().el)

  edit: (id) ->
    survey = @collection.get(id)
    view = new SurveyMe.Views.SurveyEdit(model: survey)
    $("#container").html(view.render().el)

Collection:

class SurveyMe.Collections.Surveys extends Backbone.Collection

  model: SurveyMe.Models.Survey

  url: '/surveys/'
3
can you do some debugging in your Edit Route and see if the following 2 things are true: @ is defined and survey is found correctly. - jurassix
@ comes back as an object and survey appears to be found correctly as survey.get('title') pulls back the title - Tom Hammond
in your createSurvey method can you put a debugger statement there. It seems like you need to grab the event and stop propagation; a debugger will reconfirm you statement that this method is not being called when you submit your form. - jurassix

3 Answers

1
votes

Wild guess here but it may be because you are using a simple arrow instead of a fat arrow in coffeescript:

update: ->
  @title = $('#title').val()
  @survey_limit = $('#survey_limit').val()
  this.save()

You are getting into this method from an even, which means that this is scoped to the event trigger rather than the model. Use the fat arrow:

update: =>

And it should be fine...

0
votes

Your problem may be within the update function of your model. I don't see a fetch() call to initially populate the model, so I'm guessing the data is populated on the client side only, and sent to the server side. If this is the case, you'll need to set this data within the model. You can do this prior to the save call:

this.model.set("title", $('#title').val());
this.model.set("survey_limit", $('#survey_limit').val());

Or you could do it within the save call directly:

this.model.save({
   title: $('#title').val(),
   survey_limit: $('#survey_limit').val()
});

You can do this within the model, but as you can see from the code above I'd recommend putting that logic in the view instead. This way the model doesn't have to understand what's on the view itself.

0
votes

Your model should also be having something like this,

model.collection

If you pass a {collection: ...} as the options, the model gains a collection property that will be used to indicate which collection the model belongs to, and is used to help compute the model's url. The model.collection property is normally created automatically when you first add a model to a collection. Note that the reverse is not true, as passing this option to the constructor will not automatically add the model to the collection. Useful, sometimes.

One more thought, are you sure your REST url should be "/surveys"? In our application, we have separate url for models specified in the urlRoot.

For eg, if Collection c has models m1, m2,

c1 -> url (/surveys) - where surveys will accept a collection of objects

m1 , m2 -> (/survey) - where survey will accept a model (single object)

Hope this helps.