2
votes

Here's the fiddle:

http://jsfiddle.net/QhQ8D/10/

Code is down below. Making a chat app and need a sorted, connected user list. Figured Collection with a comparator on name hooked to a CompositeView should do it. Am I doing something wrong in the implementation here?

HTML:

    <div>Enter user name and hit add user to build your list</div>
    <div id="divadduser">
        <input id="inputusername"/>
        <input id="buttonadduser" type="button" value="add user"/>
    </div>

    <div id="divusers"></div>

JAVASCRIPT:

    var nextAvailableUserId = 0;

    //Define a region to show a list of users 
    var userListRegion = new Backbone.Marionette.Region({ el: '#divusers'});

    var ConnectedUserModel = Backbone.Model.extend();

    //Make a user item view
    var UserView = Backbone.Marionette.ItemView.extend({
        template: Handlebars.compile(
            '<a id="{{id}}">{{name}}</a>'        
        ),
        tagName: "li",   
    });

    //Define a user collection
    var UserCollection = Backbone.Collection.extend({
        model: ConnectedUserModel,
        comparator: "name"
    });

    //Make a user collection instance
    var collConUsers = new UserCollection();                   

    //Define a composite user list view 
    var UserListView = Backbone.Marionette.CompositeView.extend({
        template: Handlebars.compile(
           '<ul id="ulusers"></ul>'
        ),

        itemView: UserView,
        itemViewContainer: 'ul',

        collectionEvents: {
            "add": "doSort"
        },

        doSort: function () {
            this.collection.trigger('reset');
        }
    });

    //Make a composite user list view instance
    var view = new UserListView({
        collection: collConUsers                        
    });

    //Show the view
    userListRegion.show(view);

    //Handle add user button click
    $('#buttonadduser').click(function () {    
        var uName = $("#inputusername").val();
        if (uName.length > 0) {
            nextAvailableUserId += 1;
            collConUsers.add([{ id: nextAvailableUserId, name: uName }]);        
            $("#inputusername").val('');
        }
    });

UPDATE:

I'm leaving this marked answered but the solution below is not optimal. In essence it overrides how CollectionView or CompositeView appendHtml. Technically this helps the issue described in this thread but it seems to create other problems. In my case I also have a JQuery filter on my user list (like this - http://kilianvalkhof.com/uploads/listfilter/). This override breaks that filter. Not sure why just yet. If I discover why I'll update this post.

After a few days on this I've found no reliable BB marionette way to sort on add AND filter on each keystroke a user list without rendering duplicate models. If I do I'll update. But I just think the benefit of the collection/view bond here is not fully realized without this piece. I did this with minimal difficulty in AS3.

I think the real answer is that views should accurately represent the state of a model. If a model has had an addition and been sorted, a view should reflect that. Duplicate model rendering feels like a bug.

UPDATE:

Learning as I go here. You have to specify in the override precisely where you want your content to go. As such, my 'ul' itemViewContainer is no longer relevant. So the final answer for me was:

  1. Ditch itemViewContainer
  2. Override appendHtml to tell my CompositeView explicitly where my users ul was and also to insert users by index according to sort order
  3. Ditch my "add" collectionEvent and handler

http://jsfiddle.net/QhQ8D/29/

Whew...

1

1 Answers

3
votes

Your doSort() function, triggering reset is what does the trick. If you comment that out, it only produces one copy of the view.

Use a comparator() function to sort the model, don't reset the list every time it is added.

UPDATE

More ideas on sorting as models are added are explained here:

The best way to sort a collection in a CompositeView

I used the appendHTML extension example in this post successfully in my own app (the first response to the question).