1

I'm currently busy with writing my first Backbone, RequireJS & jQuery mobile app, but I've got some problems with the events listener, they won't fire. I know this is a common problem, but I can not find the right solution.

Here's my code:

index.html body

<body>
    <div data-role="page" id="loading"></div>
</body>

Router

define([
  'jquery',
  'backbone',
  'views/projects/ProjectsView',
  'views/projects/AddProjectView'
], function($, Backbone, ProjectsView, AddProjectView) {

  return Backbone.Router.extend({

    initialize: function() {
      $(document).on('click', '[data-rel="back"]', function(event) {
          window.history.back();
          return false;
      });
    },

    routes: {
      'addProject': "addProject",
      '*actions': 'showProjects' // Default
    },

    addProject: function () {
      new AddProjectView().navigate();
    }

    showProjects: function() {
      new ProjectsView().navigate();      
    }

  });
});

AddProjectView (the problem page with event)

define([
  'jquery',
  'underscore',
  'backbone',
  'models/ProjectModel',
  'collections/ProjectsCollection',
  'text!/templates/projects/editProjectTemplate.html'
], function($, _, Backbone, ProjectModel, ProjectsCollection, editProjectTemplate){

  var EditProjectView = Backbone.View.extend({
    el: '#editProject',

    events: {
      "form submit": "addProject"
    },

    addProject: function(e){
      e.preventDefault();

      var form = $(this.el).find('form');

      var project = new ProjectModel({ title: form.find('input[name=title]').val(), description: form.find('input[name=description]').val() });

      var projectsCollection = new ProjectsCollection();
      projectsCollection.fetch();

      projectsCollection.add(project);
      project.save();

      window.location = '#project';

      return false;
    },

    render: function(){  
      this.template = _.template(editProjectTemplate, { type: 'toevoegen', action: 'toevoegen' });

      this.$el.html(this.template);    

      return this;
    },

    navigate: function() {
      var page = this.render();

      $('body').append(page.template);

      $.mobile.changePage( '#editProject' , { changeHash: false } ); 
    }
  });

  return EditProjectView;
});

EditProjectTemplate

<div data-role="page" id="editProject">
    <div data-role="header" data-position="fixed" data-tap-toggle="false">
        <a href="#projects" data-transition="slide" data-direction="reverse" class="ui-btn ui-btn-left ui-nodisc-icon ui-corner-all ui-btn-icon-notext ui-icon-carat-l">Back</a>
        <h1>Project <%= type %></h1>
    </div>  
    <div role="main" class="ui-content">
        <form id="addProjectForm">
            <ul data-role="listview" data-inset="true">
                <li data-role="fieldcontain">
                    <label for="title">Titel</label>
                    <input type="text" name="title" id="title" value="" />  
                </li>
                <li data-role="fieldcontain">                
                    <label for="description">Omschrijving</label>
                    <textarea cols="40" rows="10" name="description" id="description"></textarea>
                </li>
                <li data-role="fieldcontain"> 
                    <input type="submit" value="Project <%= action %>" />
                </li>
            </ul>
        </form>
    </div>
</div>

I've tried to set the el to 'body' and then works the event fine, but when I use it the second time the addProject event is fired twice. And when I submit the form for the third time, the addProject event is fired 3 times.

Thanks for the help!

Rido
  • 53
  • 9
  • This question shows research effort; it is useful and clear. Perhaps, a working example such as jsFiddle or jsBin would be appreciated, in order to study the console output. – Milche Patern Nov 22 '13 at 15:28

1 Answers1

0

Just use :

el: '#editProject', //Hope this is the id of your form
events: {
  "submit #addProjectForm": "addProject"
},

You can handle the double submission by capturing the event :

submit : function(e) {
    if(e.handled==false){ 
        e.handled = true;
        e.preventDefault();
        console.log("submit");
    }            
}

If you put a selector, Backbone will call

this.$el.on(event, selector, method);

instead of

this.$el.on(event, method);

And the on method of jQuery will indead apply the selector to the descendants of the element only, excluding the element itself.

Read more about events : http://backbonejs.org/#View-delegateEvents

Cheers

Alexandre Bourlier
  • 3,972
  • 4
  • 44
  • 76
Roy M J
  • 6,926
  • 7
  • 51
  • 78
  • This doesn't work completely for me. When I change the view I will add this dynamically to the body. After that I remove the previous view. But when I el: '#formId', the event will not fire. When I use el: 'body' and as event listener submit, it works fine. – Rido Dec 03 '13 at 14:12
  • Okay you are playing with the scope of events. You cannot change el mid-way and expect this to work. One solution is that you can declare another view like this : http://stackoverflow.com/questions/20193482/access-click-event-outside-the-el-in-backbone-view. I had same issue with the scope and i found solution. I am not still certain of its problems, but quite seemed to work for me. Check out my answer – Roy M J Dec 03 '13 at 14:37