Keeping track of old part of collection and new pa

2019-05-21 00:40发布

问题:

I'm using backbone.js, and I've got a collection with does fetch() sometimes. I don't want to pass the option {add: true} because of the way my subviews are created (the collection is looped over and each item is a new row appended to the current table). The one thing that I tried is just emptying the entire table and creating all new rows, but that is so slow since fetch() is run pretty often (when the scroll gets close to the end of the table). It begins to lag.

I'm hoping there's an alternative where I can keep track of the new collection for appending purposes, yet have the whole collection as an entity. One possibility is creating a second collection and then adding it into the first, but I'm not sure how / if I should do that.

回答1:

You could keep track of the current length of your collection, after new models are added to it use that as an offset to render the models from that point to the end of your collection.

UPDATE: just noticed this when I was looking through the underscore docs: http://documentcloud.github.com/underscore/#rest

To summarize it does this:

rest _.rest(array, [index]) Alias: tail
Returns the rest of the elements in an array. Pass an index to return the values of the array from that index onward.

with this you just need to keep track of what your length was before additional items were added to the collection and then pass that into rest as the index.



回答2:

I think creating a second collection of the new models is redundant. I'm trying to imagine your setup and here are some solution ideas.

Maybe one way you can do this is to change the way you do your subviews.

When you fetch() it resets your collection and it seems like you only need to work with the new models. In this case, using fetch with {add:true} sounds like a better solution. You mention that your subviews creation is looped, and I imagine how when you reset the collection, having to loop through and create all new subviews can be slow. Can you change the subview creation so that corresponds to each model? Thus for each new model that is added into the collection, a subview is appended.

I'm imagining something like the Todo.js example. But the context of your problem might be totally off from what I'm seeing.

EDIT: How to access the new models you're adding to a collection

As per our discussion, I found this thread that confirms what I was thinking about the fetch success option and parameters.

In Backbone.js, after I perform a collection.fetch({'add':true}), how do I get the latest elements retrieved?

EDIT2: Full Working Backbone Example

This is the OUTPUT (Something like this):

Pokemon Users

Audino  // These are in our initial collection
Bulbasaur
Charmander
Caterpie  // These are added to our collection using fetch()
Butterfree
Squirtle

Here is the HTML:

<body>
    <h1>Pokemon Users</h1>

    <div id="app">
        <div id="userList">     
    </div>
</body>

Here is the JS:

var User, UserCollection, UserView, AppView;

// Each User model has 1 attribute name
User = Backbone.Model.extend({
    defaults: {
        name: "changeMe"
    }
});

// Our collection of Users
UserCollection = Backbone.Collection.extend({
    model: User,
    url: 'user'
});

// Initialize our collection (nothing in it right now)
var myCollection = new UserCollection;

// Our UserView is each individual view, represented by the user model
UserView = Backbone.View.extend({
    tagName: 'div',
    className: 'user',
    render: function() {
        $(this.el).html(this.model.get("name"));
        return this;
    }
});

// AppView is the larger view that contains the sub-views
AppView = Backbone.View.extend({
    el: $('#app'),
    initialize: function() {
        // Binding the view to collection add events! <- This is the key
        myCollection.on('add', this.addOne, this);    // on/bind
    },
    addOne: function(user) {
        var view = new UserView({model:user});
        $('#userList').append(view.render().el);
    }
});

// Initialize the AppView -> Rock and Roll Time
var myApp = new AppView();

// I'm creating 3 new models
var userA, userB, userC;
userA = new User();
userA.set({name:"Audino"});
userB = new User({name:"Bulbasaur"});
userC = new User({name:"Charmander"});

var userAry = [userA,userB,userC];

// I'm adding these models into my collection
myCollection.add(userAry);

// When you take a look at the collection now, it only has 3 models
console.log(myCollection);

// Now we fetch the other 3 models from the server using {add:true}
// Try commenting this fetch call out to see the output minus new models
myCollection.fetch({
    add: true, success: function(collection, response) {
        // Just some extras to illustrate the success callback and args
        // console.log('collection: ');
        // console.log(collection);
        // console.log('response: ');
        // console.log(response);
    }
});

// The collection is updated rather than reset - necessary subview changes made
console.log(myCollection);

The following is the PHP server code - I use Slim PHP for my routing:

// Returns a JSON Collection
$app->get('/user', function() use ($app) {

    $userD = array("name"=>"Caterpie");
    $userE = array("name"=>"Butterfree");
    $userF = array("name"=>"Squirtle");

    $userAry = array();
    array_push($userAry, $userD, $userE, $userF);

    $json = json_encode($userAry);
    $response = $app->response();
    $response['Content-Type'] = 'application/json';
    $response->body($json);
});

This was fun to work through. I learned something myself. Hope it helps! :-)