user2873816
user2873816

Reputation: 179

How to use modelEvents in Marionette.js

I have 2 textfields with id's source,destination. If any field value changes that corresponding model attribute will be change. I did this one using Backbone.Model and events object in Marionette.CompositeView. It's working fine.

Once any model Attribute change corresponding function will call. For this I written the following code. It's not working the problem was even one attribute changes both functions are evaluating.

model Code:

var mapModel = Backbone.Model.extend({
  defaults: {
    startPlace: "",
    endPlace: ""
  }
});

Marionette.CompositeView code:

var mapView = Marionette.CompositeView.extend({
  events: {
    "blur #source": "sAttributeSetting",
    "blur #destination": "dAttributeSetting"
  },

  dAttributeSetting: function() {
    this.model.set({"endPlace": document.getElementById(this.ui.destinationPlace).value});
  },

  sAttributeSetting: function() {
    this.model.set({"startPlace": document.getElementById(this.ui.sourcePlace).value});
  },

  modelEvents: {
    "change startPlace": "startMarkerDisplay",
    "change endPlace": "endingMarkerDisplay"
  },

  startMarkerDisplay: function() {
    alert("start");
  },

  endingMarkerDisplay: function() {
    alert("end");
  }
});

html code:

<input type="text" id="source">
<input type="text" id="destination">

creating instance for both model and view

mapModelObj = new mapModel();
var mapViewObj = new mapView({el:$('#mapDiv'), model:mapModelObj});

problems:

  1. Initially If I enter any value in first field(source) getting 2 alert boxes("start", "end").

  2. Initially If you enter any value in second field(destination) getting 4 alert boxes("start", "end", "start", "end")

I tried alot but I didn't understand where I am getting the problem

Can anyone help me.

Thanks

Upvotes: 0

Views: 4074

Answers (2)

Boti
Boti

Reputation: 3435

My observations are the following for your solution (however I propose a second solution at the bottom):

  • The binding of entity event has colon syntax. It should be a hash of { "event:name": "eventHandler" } configuration. Multiple handlers can be separated by a space. A function can be supplied instead of a string handler name.

  • You can use advantage of the el property of the backbone view. Instead of using document.getElementById(this.ui.sourcePlace), you can use this.$('#source'). This latest searches only in the context of el rather than searching the whole dom. This way the evaluation will be way faster... That way you should use this expression: this.$('.destination').val()

Please check my jsfiddle about your issue: http://jsfiddle.net/orbanbotond/VEcK6/

The code is the following:

var mapModel = Backbone.Model.extend({
  defaults: {
    startPlace: "",
    endPlace: ""
  }
});

var mapView = Marionette.CompositeView.extend({
  events: {
    "blur .source": "sAttributeSetting",
    "blur .destination": "dAttributeSetting"
  },
  dAttributeSetting: function(){
    console.log('end blured');
    console.log('input value:' + this.$('.destination').val());
    this.model.set({
      "endPlace": this.$('.destination').val()
    });
    console.log('endplace set to: ' + this.model.get('endPlace'));
  },
  sAttributeSetting: function() {
    console.log('start blured');
    console.log('input value:' + this.$('.source').val());
    this.model.set({
      "startPlace": this.$('.source').val()
    });
    console.log('startPlace set to: ' + this.model.get('startPlace'));
  },
  modelEvents: {
    "change:startPlace": "startMarkerDisplay",
    "change:endPlace": "endingMarkerDisplay"
  },
  startMarkerDisplay: function () {
    alert("start");
  },
  endingMarkerDisplay: function () {
    alert("end");
  }
});

$(document).ready(function(){
  var mapModelObj = new mapModel();
  var mapViewObj = new mapView({
    el: $('#mapDiv'),
    model: mapModelObj
  });
});

My proposed second solution:

Use the stickit library which does all you are doing. You only need to define the mapping between the dom selector and the observed model attribute.

Here is the jsfiddle for it: http://jsfiddle.net/orbanbotond/fm64P/

Here is the code:

var mapModel = Backbone.Model.extend({
  defaults: {
    startPlace: "initialStartPlace",
    endPlace: "initialEndplace"
  },
});

var mapView = Marionette.CompositeView.extend({
  template: "#mapDiv",
  events: {
    "blur .source": "sAttributeSetting",
    "blur .destination": "dAttributeSetting"
  },
  bindings: {
    '.source': {
      observe: 'startPlace'
    },
    '.destination': {
      observe: 'endPlace'
    }
  },
  onRender: function() {
    this.stickit();
    console.debug("Sticked to it already");
  },
});

$(document).ready(function(){
  var mapModelObj = new mapModel();
  var mapViewObj = new mapView({
    el: $('#mapDiv'),
    model: mapModelObj
  });
  mapViewObj.render();
    mapModelObj.bind('change:startPlace', function(obj){alert("New value: " + obj.get('startPlace'));});
    mapModelObj.bind('change:endPlace', function(){alert("New value: " + obj.get('endPlace'));});
});

For every code sample I used this template (I used class selectors instead of id selectors):

<div id="mapDiv">
    <input type="text" class="source">
    <input type="text" class="destination">
</div>

Upvotes: 0

Billy Chan
Billy Chan

Reputation: 24815

modelEvents should be connected by :. Say, event of changing startPlace should be

'change:startPlace'

If you use space you'll end with two events, not one event specific to this attribute.

Your code 'change startPlace' represents two events, one is 'change', the other is 'startPlace'. So you'll see "start","end","start","end"

Upvotes: 3

Related Questions