Knockback: Remove item from an observable collection - backbone.js

Given an observable collection in Knockback, how do I remove an item from the underlying collection in response to a knockout.js click event?

If I'm right, a would say you want delete some item from the collection by clicking a button.
So we have the kb view:
var viewModel = kb.ViewModel.extend({
constructor: function(model, options) {
var self = this
this.delete= function(){
self.coll.delete(self)
}
this.coll = options.coll
this.name = kb.Observable(model, {key: 'name'})
}
});
var yourCollection = new Backbone.Collection();
var yourModel = new Backbone.Model({name: 'Stefan'});
var yourKBView = new viewModel (yourModel, {coll: yourCollection});
This is a simple way to store some nested information.
When you will do this automatic when a model is add in the collection you can override the create function of the view like this.
var collectionViewModel = kb.ViewModel.extend({
constructor: function(collection, options) {
var self = this
this.coll= kb.collectionObservable(collection, {
/**
* Calls by adding a model to the collcetion
* #param model -
* #param options -
*
*/
create: function(model, options){
var options = options || {}
options.coll = self
return new viewModel(model,options)
}
});
}
});

Related

BackboneJS How to merge collections

I asked this before BackboneJS Display multiple collections in one <ul>-Element but I can't get it to work and I'm starting getting really desperate so
how can I merge these 3 collections and display them in the same <ul>?
define(['app','backbone','modules/artistInstagram', 'modules/artistTwitter',
'modules/artistFacebook'
], function (App, Backbone, ArtistInstagram, ArtistTwitter, ArtistFacebook) {
var ArtistSocialMedia = App.module();
ArtistSocialMedia.View = Backbone.View.extend({
tagName: 'ul',
id: 'suptiles',
beforeRender: function(){
var artistinstagramCollection = new ArtistInstagram.ArtistInstagramCollection();
artistinstagramCollection.artist_id = this.artist_id;
this.insertView('.socialMedia', new ArtistInstagram.View({collection: artistinstagramCollection}));
artistinstagramCollection.fetch();
var artisttwitterCollection = new ArtistTwitter.ArtistTwitterCollection();
artisttwitterCollection.artist_id = this.artist_id;
this.insertView('.socialMedia', new ArtistTwitter.View({collection: artisttwitterCollection}));
artisttwitterCollection.fetch();
var artistfacebookCollection = new ArtistFacebook.ArtistFacebookCollection();
artistfacebookCollection.artist_id = this.artist_id;
this.insertView('.socialMedia', new ArtistFacebook.View({collection: artistfacebookCollection}));
artistfacebookCollection.fetch();
}
});
return ArtistSocialMedia;
});
Right now, it clearly creates 3 views but I want to merge them into one collection. Please help!
Thanks in advance...
Don't overthink it - since you're defining an element with dynamic content, it should be its own View. It's an unordered list, so the tag name must be <ul>. All you're doing is filling in the <li>'s, so the template isn't very complicated.
var collection1 = new WhateverCollection();
var collection2 = new WhateverCollection();
var collection3 = new WhateverCollection();
var ListView = Backbone.View.extend({
tagName: 'ul',
render: function(){
// define template
var templateStr = '<% _.each(collection,function(model){ %>\
<li><%- model.name %></li>\
<% }); %>';
// convert to function
var template = _.template(templateStr);
// for learning purposes, render each one individually
var htmlFromFirst = template({ collection: collection1.toJSON() });
var htmlFromSecond = template({ collection: collection2.toJSON() });
var htmlFromThird = template({ collection: collection3.toJSON() });
// set the html
this.$el.html( htmlFromFirst + htmlFromSecond + htmlFromThird );
return this;
}
});

Get properties of a Backbone model starting with certain text using Underscore.js

I have a Backbone Model in which there are certain properties like
test_id
test_name
test_desc
test_score
Now I want to retrieve properties which are starting with "test_".
I tried with code below and its working fine.
var MyModel = Backbone.Model.extend({
getTestProperties: function(str){
// get clone of attributes to iterate over
var testProperties = {};
var attrs = _.clone(this.attributes);
_.each(attrs, function(val, key){
if(key.indexOf(str) == 0){
testProperties[key]= val;
}
}, this);
}
});
But
Is there any other way I can get these properties using underscore methods ?
Thanks
Backbone proxies some methods from Underscore on models that can help you create a more readable _.filter: _.keys and _.pick
You can then simplify your function like this :
var MyModel = Backbone.Model.extend({
getTestProperties: function (str) {
// get the keys you want
var keys = _.filter(this.keys(), function (key) {
return key.indexOf(str) === 0;
});
// and build an object
return this.pick(keys);
}
});
And a demo http://jsfiddle.net/nikoshr/5a63c/
Try something like
var attrs = _.filter(_.keys(_.clone(this.attributes)), function(attr){
return attr.indexOf("text_") === 0;
});

How to make selected item to change class(How to make property observable in backbone)

i want to build simple screen, where list of items in one side and selected item details -on another. when user click on one of the items - its details displayed in 'details' section.
also the selected item in the 'list' section must be decorated with 'active' class.
here is my router code:
var AppRouter = Backbone.Router.extend({
routes:{
"":"list",
"users/:id":"userDetails"
},
list:function () {
this.usersList = new UsersCollection(usersList);/* new UsersCollection()*/
var self = this;
//this.userList.fetch({
// success: function () {
this.UsersListView = new UsersListView({ model: this.usersList });
$('#sidebar').html(this.UsersListView.render().el);
// }
//})//end of fetch
},
userDetails:function (id) {
if(this.usersList){
//unselect prevously selected
if(this.user )this.user.set({'selected':false});
this.user = this.usersList.get(id);
//select current
this.user.set({'selected':true});
//empty refill the items section
this.UsersListView = new UsersListView({ model: this.usersList });
$('#sidebar').empty().html(this.UsersListView.render().el);
if (this.UserDetailsView) this.UserDetailsView.close();
this.UserDetailsView = new UserDetailsView({model:this.user});
$('#content').html(this.UserDetailsView.render().el);
}
else{
}
}
});
So far i managed to set the 'active' item class by emptying and refill the items section html.
Is there any way to observe (like in knockoutjs) the 'selected' property, so once it changes -the change will be visible in html?
code of view:
window.UserListItemView = Backbone.View.extend({
tagName:"li",
template:_.template($('#tpl-user-list-item').html()),
render:function (eventName) {
if(this.model.get('selected')){$(this.el).addClass('active');}
$(this.el).html(this.template(this.model.toJSON()));
return this;
}
});
Thanks forwards
This is what you're looking for (especially the Events#listenTo method).
So; in your view:
initialize: function() {
// listen to your model
this.listenTo(this.model, 'change:selected', this.updateClass);
},
updateClass: function() {
// something like...
this.$el.toggleClass('active');
}

createItem for qx.ui.mobile.list.List

qx.ui.mobile.list.List seems not to support the qx.data.controller.List.
Is there another way to add a delegate for createItem? I tried to add the create delegation on both classes, but createItem was not invoked.
Here is an example, how to use databinding with lists:
/**
* Creates a list and returns it.
*/
__createListDataBindings : function() {
var self = this;
var list = new qx.ui.mobile.list.List({
configureItem : function(item, data, row)
{
var stopCount = self.getListData().getLength()-row;
item.setTitle("Stop #"+stopCount);
item.setSubtitle(data);
}
});
this.bind("listData", list, "model");
return list;
},
ListData is a class property:
properties :
{
// overridden
listData :
{
init : new qx.data.Array(),
nullable : true,
event : "updateListData"
}
},

Filter backbone collection by attribute value

I have a defined model and a collection:
var Box = Backbone.Model.extend({
defaults: {
x: 0,
y: 0,
w: 1,
h: 1,
color: "black"
}
});
var Boxes = Backbone.Collection.extend({
model: Box
});
When the collection is populated with the models, I need a new Boxes collection made out of Box models that have a specific color attribute contained in the complete collection, I do it this way:
var sorted = boxes.groupBy(function(box) {
return box.get("color");
});
var red_boxes = _.first(_.values(_.pick(sorted, "red")));
var red_collection = new Boxes;
red_boxes.each(function(box){
red_collection.add(box);
});
console.log(red_collection);
This works, but I find it a bit complicated and unefficient. Is there a way of doing this same thing in a more simple way?
Here is the code I described: http://jsfiddle.net/HB88W/1/
I like returning a new instance of the collection. This makes these filtering methods chainable (boxes.byColor("red").bySize("L"), for example).
var Boxes = Backbone.Collection.extend({
model: Box,
byColor: function (color) {
filtered = this.filter(function (box) {
return box.get("color") === color;
});
return new Boxes(filtered);
}
});
var red_boxes = boxes.byColor("red")
See http://backbonejs.org/#Collection-where
var red_boxes = boxes.where({color: "red"});
var red_collection = new Boxes(red_boxes);

Resources