Backbone.Marionette and Backbone.Paginator. CompositeView rerendering - marionette

I'm working on Infinite Pagination
(http://addyosmani.github.io/backbone.paginator/examples/infinite-paging/index.html)
I'm using CompositeView for pagination view.
And I've got the following problem. Each time after I get new portions of data Paginator's collection removes old data and adds new so it makes CompositeView to rerender and erase old results.
How can I resolve this problem? I'm thinking about disabling rerender functionality but how it should be done properly?
Thanks in Advance!
var BaseFeedChronoCompositeView = Backbone.Marionette.CompositeView.extend({
tagName: "div",
template: _.template(ChronoFeedComposite_html),
itemView: Article,
events: {
'click #loadmore-button-manual': function (e) {
e.preventDefault();
this.collection.requestNextPage();
},
appendHtml: function (collectionView, itemView, index) {
collectionView.$("#chronoFeed-content").append(itemView.$el);
}
});
Here is the basic code.
this.collection.requestNextPage() - sends request for data to server. After it gets data this.collection removes old models and adds new models.
Composite View is listening for these events and removes itemViews for old models and append itemViews for new models.
And I need CompositeView not to remove old itemViews.

Im not quite sure how this paginator works, as I've never used it. But I think the easiest way to fix this is to make sure that your Collection doesnt remove old models. I assume that when your data is being returned it is doing a set on the collection. If you look at the backbone docs you can see that you can disable this method from removing models http://backbonejs.org/#Collection-set
If you'd like to customize the behavior, you can disable it with
options: {add: false}, {remove: false}, or {merge: false}.
So when you are updating the collection, instead of just calling
myCollection.set([o1,o2,o3]);
you should be doing
myCollection.set([o1,o2,o3], {remove:false});

Related

Backbone routing and view relations

I'm preparing to build a medium sized website with Backbone for the first time. There are 7 menu items, and I cant figure out whats the best routing/view relationship when it comes to performance. When a route is triggered, do I create a new instance of the "active" view every time it's triggered or do I only create one view instance for each view, when the user loads the page?
... And whats the best way to handle views – adding and removing dom elements and events, without having trouble with performance. e.g.
$('selector').html(my-new-view);
You can create your menu only once, if it doesnt change. You can create some html template like this.
<div>
<nav>render-here-only-one</nav>
<section>render-here-when-page-changes/loads</section>
</div>
I prefer backbone's render method initialize and append itself.
var testView = Backbone.View.extend({
el: $("#section"),
template:_.template("<strong>hello.</strong>")
initialize: function () {
// any change on view will trigger render
_.bindAll(this, "render");
},
render: function (item) {
this.el.html(this.template());
}
});
var myView = new testView();
myView.render();

How can I change ItemView to CompositeView in Marionette application?

I'm trying to make in-row editing in Marionette application. What is the best approach to do this?
I have table which is Marionette.CompositeView and rows of this table are Marionettes ItemViews. Now I'm trying to change clicked table row (ItemView) to a CompositeView which will contain inputs and selects with ajax fetched data. Is this a good approach?
You can use CollectionView.getChildView to render different view for edited items, but this can cause performance problems if you need to render large collections.
I modified Derick Bailey's Tree View example to show how this can be done - http://jsfiddle.net/msamujlo/8g3abfg2/
// The recursive tree view
var TreeView = Backbone.Marionette.CompositeView.extend({
template: "#node-template",
tagName: "ul",
getChildView: function(item){
return item.get('isEditable')? EditorView : TreeView;
},
// ... more methods
};
var EditorView = TreeView.extend({
template: "#editor-template",
});
...

KendoUI : Confused about when bindings actually 'fire'

Using Kendo UI's MVVM framework, I am getting confused about how bindings that are wired in javascript actually work. Given a view model, I have tried the following;
var viewModel = new kendo.observable({
Items: [],
onUpdateItems: function(e){
console.log('updating items');
}
});
viewModel.Items.bind('change', function(e){
viewModel.onUpdateItems(e);
});
viewModel.trigger("change", { field: "Items" });
This does not cause the function to trigger. Though if I actually change items in the view, like interacting with it, it causes the function to fire. This doesn't make a lot of sense to me.
You're binding the change event for viewModel.Items, so you need to trigger the event there. If you change your call to
viewModel.Items.trigger("change");
it will call viewModel.onUpdateItems().
Change events will bubble upwards (from an inner ObservableArray to the outer ViewModel, for example), but not the other way. So if you trigger the change event for the view model, it will not fire the event for the nested ObservableArray Items.

Can I trigger an event on a specific model in a collection in backbone?

Say I have the following structure -
Model: Folder
Collection: Folders
From within my collection view, I want to trigger an event on a folder with a specific name -
So,
FolderCollectionView = Backbone.View.extend({
...
...
editFolder: function() {
this.collection.findWhere({ name: "abcd" }).trigger("editThisFolder");
}
});
FolderModelView = Backbone.View.extend({
...
...
editThisFolder: function() {
//This should get called
}
});
Is this possible? I'm using event aggregators, however, i haven't found a way wherein, I can trigger an event on a specific folder, I can make the folder view subscribe to a collection view event, but then all folder views respond to that event, I haven't found a way to make only a specific folder view respond to a collection event. Or somehow trigger an event on a specific folder view from the collection view.
I'm new to this, so let me know if i'm missing something important.
Event aggregator reference - http://lostechies.com/derickbailey/2011/07/19/references-routing-and-the-event-aggregator-coordinating-views-in-backbone-js/
Backbone has underscore.js as a dependency. One of the reasons for this is the fact that Backbone.js Collections implement a whole lot of underscore methods. So your solution should work
this.collection.findWhere({ name: "abcd" }).trigger("editThisFolder");
Then of course you should make your FolderView listen to that event and call the function
var FolderView = Backbone.View.extend({
initialize: function() {
// assuming a folder model assigned to each view
this.listenTo(this.model, 'editThisFolder', this.editThisFolder);
}
});
Did this answer your question?

does an onclick function go in model, view or controller?

I am using backbone.js and trying to stay strict to the model-view-controller structure as I learn it. I have an onclick function for a link in one of my views that I am not sure where to put. Is the best place to keep this in the render function of the view?
Thanks
More specifically, the onclick performs a facebook login and then adds the user to my database if they are not currently in it. Don't know if this changes anything.
Here is what I think I will go with:
var NewUserView = Backbone.View.extend({
el: $('#window'),
render: function(){
// Render
this.listeners();
},
listeners: function(){
// onclick and other listeners
}
});
From the Backbone documentation:
In Backbone, the View class can also be thought of as a kind of
controller, dispatching events that originate from the UI, with the
HTML template serving as the true view. We call it a View because it
represents a logical chunk of UI, responsible for the contents of a
single DOM element.
Here's the general way to handle events in Backbone:
var NewUserView = Backbone.View.extend({
el: $('#window'),
render: function() {
// Render
},
events: {
"click #facebookButton": "loginViaFacebook"
},
loginViaFacebook: {
// Perform facebook login and add user to database
}
});
Where do you want the link to appear? On View page right? So , you should keep it in the same view on which you want the link to appear.
But , if you are building an architecture rather than just a web application, then you should put the onclick function in some different file where you will keep all these function and then import them in the view as required or keeping them in separate files and bundling them for import on view page.
Please make a file and write all the functions in that file and include that file in the your view file and use the onClick in the anchor tag. Please let me know if this make sense.

Resources