Search code examples
javascriptbackbone.jsmarionettepublish-subscribeupdatemodel

Backbone Marionette - Updating view object based on incoming data


I have an application which updates based on live incoming iq packets to a pubsub node.

At the moment I am using backbone marionette to create the intial view when I receive a respnose from my request. This creates an object using the template, which I then need to feed the live data into.

I want to use backbone marionette to update this object with the live data but I'm unsure how it would be done.

Currently, when I receive the correct type of iq to the pubsub node I am getting out the info I want, then calling a function "updatewell" which updates the object created by backbone from the original response.

Is backbone able to update this object from the pubsub event? How would I call it?

Edit below shows approximately what I do in the updatewell function. Can backbone marionette handle all of this? It's not as simple as "replace the template with new data", I need to hide/show information based on what is returned.

The main issue I have using backbone marionette is that it constantly creates new objects. In the updatewell code you notice that I am defining divs with an ID that is unique, and updating based on that id (which is returned in the IQ to the pubsub). This means the correct object is always updated, something I can't find to define in backbone marionette.

In essence, I need to tell marionette: "These are a new set of values, does a model with this value as it's id exist? if not, create it, if it does, update it with the other values"

Please ask for more information.

My code is below (simplified as of 1st May 2014):

Backbone Marionette code:

InfoWell = Backbone.Model.extend({});

InfoWells = Backbone.Collection.extend({
    model : InfoWell
});

InfoWellView = Backbone.Marionette.ItemView.extend({
    template : "#template-infowell",
    tagName : 'div',
    className : 'alert alert-custom',

initialize: function () {
    this.$el.prop("id", this.model.get("datetime"));
},
});

InfoWellsView = Backbone.Marionette.CompositeView.extend({
    tagName : "div",
    id : "info-well-list",
    template : "#template-infowells",
    itemView : InfoWellView,

});

MainJs.addInitializer(function(options) {
    var aInfoWellsView = new InfoWellsView({
        collection : options.InfoWells
    });
    MainJs.InfoWellsContainer.show(aInfoWellsView);
});

var InfoWells = new InfoWells();

Response code to create well:

    InfoWells.add(new InfoWell({
        id : datetime,
        datetime : datetime,
        title : title,
        body : body,
        comments : comments
    }));

Pubsub code:

pubsubHandlerInfo = function(iq) {
    var date = $(iq).find('datetime').get()
    ...     
    MainJs.vent.trigger("updatewell", {
        datetime : datetime,
        title : title,
        body : body,
        comments : comments
    });
    return true;
}

EDIT Updatewell function:

MainJs.vent.bind("updatewell", function(data) {
        var datetime = data.datetime;

        if (datetime.length) {
            $("#hidden-state").trigger('testactions');
            $('#hidden-state').bind('testactions', updateWell(data))
        }

        function updateWell(data) {

        $("#body-" + data.datetime).html(data.body);
        $("#comments-" + data.datetime).html(data.comments);

        if (data.title === "something1") {
            $("#"+data.datetime+"-Something1").unbind('click').click(something1Action)
        } else if (data.title === "something2") {
            $("#"+data.datetime+"-Something2").unbind('click').click(something2Action)
        }

        function something1Action() {MainJs.function1();}
        function something2Action() {MainJs.function2();}
    });

So in words, what I'm trying to do is this: Replace MainJs.vent.trigger("updatewell", { with InfoWells.add(new InfoWell({ to send a new model to backbone. Backbone will see this model and check if there already exists a model with the ID of the datetime value.

As a first step, if there is a model with this ID, I need to update two divs in the model (the body and the comment) with the new values sent. If there is no model with this ID, I need to create one as normal (which works at the moment).

As a second step, I would need to check the value of the title and create a click function for the title div.

Big thank you for any help you can provide.

EDIT: As mentioned by Dmytro, I can use set and get, but I'm not sure how this applies here. Where do i tell it to get the existing ID and how do I set new values to it? Any link to documentation regarding this would be brilliant please.

SOLUTION: So, understand get and set and where to apply it is the main part of updating backbone models.

Below is the code I've added to my pubsub handler which does it correctly.

    var update = InfoWells.get(datetime);
    console.log(update);
    if (update !== undefined && update !== null){
        update.set({
title : title,
body : body,
comments : comments
        });
    };

So for those who want to know what I'm doing. I create a variable called update which gets it's value from looking at the collection (InfoWells) and getting the ID with value datetime, which from above you can see is the unique ID value I assigned every model.

I then check if this update value actually exists, and if it does I call the set command, which tells it to send these new values into the model for the attributes mentioned. Note that I left out id as I will never update that for a model.

Then, as Dmytro mentioned, I added the render to the ItemView when a model changes.

    modelEvents: {
        "change": "render"
    }

The next step for me, to replicate my update well, is use "change:ATTRIBUTE" : function().

Thanks for the help.


Solution

  • First of all Backbone.Model should represent current state of your data and than view should render it to HTML. Updating HTML directly it is not Marionette way.

    If you want to don't create new model but update exited when receive data about existed one you can just find existed model in collection(using, get or find or findWhere) and update it with new attributes using set.

    Than change events will be triggered in your model if some attributes changed. You can listen to this event and rerender your view using modelEvents:

    InfoWellView = Backbone.Marionette.ItemView.extend({
        template : "#template-infowell",
        tagName : 'div',
        className : 'alert alert-custom',
        modelEvents: {
          'change': 'render'
        }
    });