Fragmenting Backbone collection view based on some criteria - backbone.js

I'm a bit new to BackboneJS and Marionette, and I'm a bit stuck on how to implement some tricky behaviour with a CollectionView. Suppose I have a list of appointments, each with an appointment date/time (stored as a unix timestamp, but that's not important).
When I display these, I'd like to display them as follows:
Today
Meeting A (10:00 AM)
Meeting B (11:00 AM)
Meeting C (1:00 PM)
... and 4 more
Next 7 days
Meeting D (Monday at 3 PM)
Meeting E (Tuesday at 2 PM)
... and 7 more
The approach I'm considering is to pull one collection from the server for the next 7 days (including today) and then do 2 views over the collection (one for today, and one for the week). Here's what I'm struggling with:
AFAIK, the Marionette.CollectionView renders all the elements in a collection. Is there an easy way to override this behaviour to only render, say, 3 or 4 items?
How do I deal with the ... and n more line? It's not really a model, but its data is computed from the underlying collection.
If it makes a difference, I'm using #SlexAxton's requirejs-handlebars project for templating.

You might use a CompositeView instead of a CollectionView. So you define yourself the collection attribute to use a subset you want, and then you can display the "X moreā€¦" link.
It could be something like:
EventView = Backbone.Marionette.ItemView.extend
template: 'event'
EventsView = Backbone.Marionette.CompositeView.extend
itemView: EventView
template: 'events'
initialize: (attributes)->
#extractSubset(attributes.collection)
extractSubset: (collection)->
#collection = new EventsCollection(collection.filterByWhatYouWant())
#othersCount = collection.length - #collection.length
appendHtml: (collectionView, itemView)->
collectionView.$('.events').append(itemView.el)
serializeData: ->
othersCount: #othersCount
andAnyOtherThing: 'you need in the template'

Related

Creating "Empty" Rows in ui-grid / ng-grid

Is there a way to conditionally add "empty" rows to a ui-grid model? The requirements for my project stipulate that we display items by date (very easy), but also display empty rows for days that don't have items on them so that users can see those gaps at a glance (much more difficult).
Somewhat in line with what was being asked in this question, perhaps some sort of grouping by date and inserting an empty group for dates that don't have associated items could work...?
I could create a whole new collection model that combines dates and my actual data and have the ui-grid use that, but that seems extremely inelegant, as it would likely entail a lot of manual reloading of everything when changes are made to the data. Ideally I'd like to just feed my collection of data rows to the grid, but still have it show an extra row with just the date field for dates that don't currently have items.
I actually have this working in a setup using tables and ng-repeat now, but I'm looking to switch to ui-grid or similar to gain benefits of virtual scrolling, etc since I have a lot of editable (and hence, fully-bound) data.
Thanks in advance...
Would something like this meet your needs?
function fillInEmptyDates(startDate, endDate, data) {
var dateToCheck = moment(startDate);
var end = moment(endDate);
var finished = false;
while (!finished) {
if (!Enumerable.from(data).any(function (x) { return dateToCheck.diff(x.YourEntityDateField, 'days') === 0; })) {
var newEntity = { "YourEntityDateField": dateToCheck.clone().toDate() };
data.unshift(newEntity);
};
dateToCheck.add(1, 'days');
if (dateToCheck.diff(end, 'days') === 0) {
finished = true;
}
}
}
To be called like...
fillInEmptyDates(new Date(2014, 6, 30), new Date(2014, 10, 25), $scope.gridOptions.data);
You could perhaps have the first date as the minimum of your current data, and the end date as the max, or adjust according to your needs.
Note that I have used MomentJS for date manipulation and LinqJS for looking through the dates for the data. I'm sure there would be an easy way to loop through the data without using LinqJS if you preferred. (I'm new to JavaScript and find myself hooked on the LINQ stuff I was previously doing in C#.)
The sorting that you specify in the grid options should apply to the newly created rows.
(Sidenote: you might have to play with timezones to get exactly the values you want. If you're seeing duplicates of the dates that do have data, then it may be due to this.)

Backbone.js collection getting multiple models

You can get a model from the collection by using collection.get(id);
but i want to get mulitple models. The get only gets 1 models.
I now use this piece of code, but it doesn't look pretty or feels good for performance. Anyone knows a better way to select an array of models from the collection?
var models = this.collection.filter(function(model){
return _.indexOf([1,2,3,4], model.get('id')) > -1;
});
Since you just need 4 items, your code iterate whole collection.
Following code is better performance by iterating only size 4 array.
var models = _.map([1,2,3,4], function(id) {
return collection.get(id);
});

Backbone: pluck models with an array of IDs, and save them

So I have an array of IDs:
var myIDs = [1,5,9];
I have a collection that I want to search through, and pluck from. I thought I could do something like the following:
var searchResults = myCollection.where({"uID" : myIDs});
Of course that won't work, but there must be a way to achieve something similar.
Once I have the selected models, the plan is to edit the contents of, then save. Am I correct in assuming I can save the whole batch by doing the following?
myCollection.reset(searchResults);
I'm a total n00b to Backbone, obviously.
You can use Collection.filter to compare each item against the array:
var searchResults = myCollection.filter(function(model) {
return myIDs.indexOf(model.id) != -1;
});
("Where" is like a special case of "filter", with a specific iterator -- it compares the properties of each model with the hash set you provide.)
As far as saving, if you mean replacing the items in the collection, then yes, you can use reset for that. (Note that "save" in Backbone parlance normally means syncing model updates back to the server.)

Change the kendo calendar month names from shortform to fullform

In the kendo calendar control, the months names in the months view(where all the months of a specific year are listed) are shown in the short form instead of the full name. How can i change the names to full form only in this view. Ex: Mar instead of March.
I tried changing the date format using 'calendar.options.format' property, but it dosen't make any difference. Need help.
The calendar widget is programmed to always use the month abbreviation names. However, you can edit these names in the Kendo culture settings. Just be aware that they will change anywhere in Kendo that uses month abbreviations.
The abbreviations are stored in:
kendo.cultures.current.calendars.standard.months.namesAbbr
which is an array, indexed by the month. So you could set:
kendo.cultures.current.calendars.standard.months.namesAbbr[0] = "January";
kendo.cultures.current.calendars.standard.months.namesAbbr[1] = "February";
// ...etc...
Or, to make things easier, you can just copy the entire un-abbreviated months array to the abbreviated array, instead of setting each individual month:
kendo.cultures.current.calendars.standard.months.namesAbbr = kendo.cultures.current.calendars.standard.months.names;
However, that is still going to affect any other Kendo widgets that rely on the month abbreviations. A cleaner approach would be to make a custom culture for the Calendars to use. So in the initialization script for your page, after you include kendo.min.js, you can do this:
// just do this once on page load. copy current culture to a new one, and replace abbreviated months.
kendo.cultures.currentWithoutMonthAbbreviations = $.extend(true, {}, kendo.cultures.current);
kendo.cultures.currentWithoutMonthAbbreviations.name = "currentWithoutMonthAbbreviations";
kendo.cultures.currentWithoutMonthAbbreviations.calendars.standard.months.namesAbbr = kendo.cultures.currentWithoutMonthAbbreviations.calendars.standard.months.names;
Then the calendar widgets that you want to use full month names in, you can tell it to use your custom culture.
$("#datePicker").kendoDatePicker({
culture: "currentWithoutMonthAbbreviations"
});
You can do it with this script for days. I imagine the same would work for months:
var dayInfo = kendo.culture().calendar.days;
for (var i = 0; i < dayInfo.namesAbbr.length; i++) {
dayInfo.namesShort[i] = dayInfo.namesAbbr[i];
}

How can I access to some model in Backbone collection

I have a collection of models:
city = new M.City
App.citiesList = new C.CitiesList model: city
App.citiesList.fetch()
How can I access to the model with id=15 for example?
I need something like App.citiesList.find(15).name(), where name() is model function
When I try to add function find to the collection it is incorrect.
When I try to iterate over App.citiesList.models - I see only one model or what it is.. I actually don't know.
Thanks a lot!
If App.citiesList is a Backbone collection then you'd want to use get:
get collection.get(id)
Get a model from a collection, specified by id.
So this would get you your model from the collection:
fifteen = App.citiesList.get 15
And if you wanted to call a method on it:
App.citiesList.get(15).name()
You'd probably want to make sure you got something back from App.citiesList.get 15 first though (unless you knew it was there of course). Since you're working in CoffeeScript you could use the existence operator like this:
name = App.citiesList.get(15)?.name()
#----------------------------^
to get 15's name or undefined in the name variable.
The find method on App.citiesList would be Underscore's find and that doesn't find an object with a particular ID.

Resources