BackboneJS How to add <comparator>-method to model - javascript

I have made a Model which I made to display the whole discography of a band which I get delivered by an API as JSON. So far so good, but I need to sort the albums by its releasedate, so I intent to use the comparator-method, which is not possible to use on Models. So I want to "transform" the Model into a Collection, or is there maybe a better way?
Here is my model I define on my discography.js:
ArtistDiscography.ArtistDiscographyModel = Backbone.Model.extend({
url: function() {
return App.APIO + '/i/artist/' + this.get('slug') + '/releases';
},
parse: function(response){
return response.data;
},
});
the slug value is the JSON value, which returns for example rihanna. The JSON file also contains a value called releaseDate.
In my maincontroller.js, I have this:
define(function (require, exports, module) {
var ArtistDiscographyModule = require('modules/discography');
)};
ArtistController.prototype.initDiscography = function(name) {
this.artistdiscographyModel = new ArtistDiscographyModule.ArtistDiscographyModel({slug: name});
this.artistdiscographyModel.fetch();
this.artistdiscographyModel.on('sync', function() {
this.artistDiscographyView = new ArtistDiscographyModule.View({model: this.artistdiscographyModel});
App.useLayout('artistDiscography', 'artistDiscography').setViews({
'.releasesDiv' : this.artistDiscographyView,
}).render();
}, this);
};
The JSON response is:
data: [{
"slug" : "rihanna",
"releases": {
"title" : "Music Of The Sun",
"releaseDate": "2005-08-29",
"tracks": [{ //array of tracks}]
}, {
"title" : "Pon de Replay",
"releaseDate": "2005-08-22"
"tracks" : [{ //array of tracks}]
}
}]
Can someone help me out? I would really appreciate it!

You can set collection as an attribute of model:
ArtistDiscography.ArtistDiscographyModel = Backbone.Model.extend({
defaults: {
slug: '',
releases: new Releases()
}
});
Releases = Backbone.Collection.extend({
model: Release
});
Release = Backbone.Model.extend({
defaults: {
title: '',
releaseDate: '',
tracks: []
}
});
Then you can add comparator into Releases collection.
Or you can go dirty and use the underscore's sort function for array:
_.sortBy([1, 2, 3, 4, 5, 6], function(num){ return Math.sin(num); });
=> [5, 4, 6, 3, 1, 2]

Have you tried something along these lines?....
ArtistDiscographyCollection = Backbone.Collection.extend({
model: ArtistDiscography.ArtistDiscographyModel,
comparator: function (model) {
return (model.get('releases').releaseDate);
}
});

Related

I've found a Json data using findById, how do I use it in my code?

I am creating an API that gets Patients data(id and name), Physicians data(id and name) and Appointments(id, phyId, patId, app_date) and displays the Patients appointed to a particular physician. I need to create a remote method in physician.js in such a way that I get related Appointment that has phyId and print the details of the Patients using the patId obtained from appointment.
I'm using loopback 3.
Refer this link for clear idea:
https://loopback.io/doc/en/lb3/HasManyThrough-relations.html
I have related models (Physicians, Patients) that are related by "hasMany" with each other "through" Appointment(another model) and Appointment is related to each of these by belongsTo, in my loopback application and i need to print the Patients of a particular Physician.
Patient data:
[
{
"id": 1,
"name": "Anna Mull"
},
{
"id": 2,
"name": "Paige Trner"
}
]
Physician data:
[
{
"id": 1,
"name": "Cardiologist"
}
]
Appointment data:
[
{
"id": 1,
"physicianId": 1,
"patientId": 1,
"appointmentDate": "2019-01-28T10:06:33.530Z"
},
{
"id": 2,
"physicianId": 1,
"patientId": 2,
"appointmentDate": "2019-01-28T10:06:33.530Z"
}
]
I know there is a method already available to query the Patients of a Physician, but I want to code it myself to learn and also print it in the following format.
My idea is to get all the Appointments having the specific phyId in it and find the patId in those appointment and store it in an array. I then use that array to get the patients from the Patient model. I managed to get the Patient details in a function, but I can only console.log(Patients) but I am not able to display it in the API response.
The following is the format i need it in. (EXPECTED OUTPUT in API response)
Physician:
{
"id": 1,
"name": "Cardiologist"
}
Patients:
[
{
"id": 1,
"name": "Anna Mull"
},
{
"id": 2,
"name": "Paige Trner"
}
]
or any similar format.
I've tried to the same and here is my code.
common/models/physician.js
'use strict';
var app = require('../../server/server');
module.exports = function (Physician) {
Physician.getDetails = function (phyid, cb) {
var Appointments = app.models.Appointment;
var Patient = app.models.Patient;
Physician.findById(phyid, function (err, Physician) {
Appointments.find({ where: { physicianId: phyid } }, function (err, Appointment) {
if (err) {
cb(null, "Errorrrrrrrr", "Errorrrrrr");
}
else {
var patients = [], i = 0;
var patobj= [];
for (i in Appointment) {
patients[i] = Appointment[i].patientId;
//console.log(patients);
Patient.findById(patients[i], function(err, Patients){
if(err){
cb("Error in patients", "--");
}
else{
patobj[i]=Patients;//doesnt have any effect
console.log(Patients);//prints in console
}
});
}
cb(null, Physician, patobj);//only Physician is printed, patobj is empty.
}
});
});
}
Physician.remoteMethod('getDetails', {
http: {
path:
'/:phyid/getDetails',
verb: 'get'
},
accepts: {
arg: 'phyid',
type: 'number'
},
returns: [{
arg: 'Physician',
type: 'Object'
}, {
arg: 'Patient',
type: 'Object'
}]
});
};
I am actually getting this in the API response:
{
"Physician": {
"id": 1,
"name": "Cardiologist"
},
"Patient": []
}
and this in the console:
D:\Project\Project1>node .
Web server listening at: http://localhost:3000
Browse your REST API at http://localhost:3000/explorer
{ name: 'Anna Mull', id: 1 }
{ name: 'Paige Trner', id: 2 }
How am I supposed to get the patient data to be printed in the API response?
You patients are empty because, finding Patients by Id is an asynchronous operation. But the for loop is synchronous. The loop finishes and calls the following line before any of the Patients are found.
cb(null, Physician, patobj);//only Physician is printed, patobj is empty.
You need to wait for all the patients to be found by using either Promise.all or async.each.

Backbone - Updating models in collection with data polled from another API

I have a Backbone collection that I'm populating from an API endpoint. This return data such as:
[
{
"gameId": 1234,
"gameName": "Fun Game 1"
},
{
"gameId": 1235,
"gameName": "Fun Game 2"
},
{
"gameId": 1236,
"gameName": "Fun Game 3"
},
etc,
etc,
etc
]
The collection is very simple and is initialised in the router so it's accessible to the entire app:
var GamesCollection = Backbone.Collection.extend({
model: GameModel,
url: '/path/to/games/list',
parse:function(response){
return response;
}
});
I have another endpoint that returns a collection of data related to the original data. This data looks like:
[
{
"gameId": 1234,
"numberOfPlayers": "1,000"
},
{
"gameId": 1235,
"numberOfPlayers": "Fun Game 2"
},
{
"gameId": 9999,
"numberOfPlayers": "Some other game that's not in the original list"
}
]
Note that the number of players response may or may not contain data for every game in the original response and may or may not contain data for games that do not exist in the original games response.
I need to be poll the number of players endpoint every X minutes and update the models in the GamesCollection with the data from the response so I can show this in the view.
What is the best way to handle this?
Query your numberOfPlayers endpoint and then set the fetched data on your collection. You can customize how set works with add and remove options.
For example,
var GamesCollection = Backbone.Collection.extend({
model: GameModel,
url: '/path/to/games/list',
parse: function(response){
return response;
},
pollNumberOfPlayers: function() {
var self = this;
return Backbone.ajax('/numberOfPlayers/endpoint').then(function(resp) {
self.set(resp, {add: false, remove: false, merge: true});
});
},
startPolling: function() {
var self = this,
timer = 10000; //10 seconds
self.pollNumberOfPlayers().then(function() {
setTimeout(function() {
self.startPolling();
}, timer);
});
}
});
Note that I assumed your GameModel objects have gameId as their idAttribute.

Meteor publishing field issue

My application is publishing a 'memberPrice' field when it is not supposed to. In my publish.js file, I specified the memberPrice to not be published. Here is my server/publish.js:
Meteor.publish('cars', function() {
return Products.find({category: 'vehicle'}, {limit: 10}, {fields: {memberPrice: 0}});
});
My controller:
carsController = RouteController.extend({
waitOn: function () {
var sessionId = Session.get('sessionId');
console.log("Session: ", sessionId);
Meteor.subscribe('cars');
Meteor.subscribe('cartItems', sessionId);
},
action: function() {
this.render('Cars');
}
});
Here's my table using the aldeed:tabular package:
TabularTables = {};
Meteor.isClient && Template.registerHelper('TabularTables', TabularTables);
TabularTables.Cars = new Tabular.Table({
name: "Cars",
collection: Products,
columns: [
{data: "productCode", title: "Product Code"},
{data: "brand", title: "Brand"},
{data: "productLineName", title: "Product Name"},
{data: "description", title: "Description"},
{data: "memberPrice", title: "Member Price"}
]
});
Does anyone know what's going on?
Thanks!
You're passing three arguments to Products.find, but it only expects two. {limit: 10}, {fields: {memberPrice: 0}} should be {limit: 10, fields: {memberPrice: 0}}.
In the past i do publish like the one you have, but since i read this post from David Weldon page.
I change my publish to something like this.
Meteor.publish('cars', function() {
var selector = {category: 'vehicle'};
var options = {limit: 10,fields: {memberPrice: false}};
return Products.find(selector,options);
});
Based on the Publish function you have, the memberPrice option should be exclude here, try with this, here we are following the correct syntaxis of the Collection.find wich is collection.find([selector], [options]) and you have something like collection.find([selector],[selector],[options]).

Specify id label for data loaded from array

Is it possible to load fully custom set of data into select2? I mean I can customize the option text property, can I also do it for id?
The code below works perfect
var dummy = [
{ id: 1, Name: "opt1" },
{ id: 2, Name: "opt2" }
];
$("#myselect").select2({
data: { results: dummy, text: "Name" },
formatSelection: function (item) { return item.Name; },
formatResult: function (item) { return item.Name }
});
However, my data incoming has the id property in caps. It surely would be possible for me to rename these objects' properties iterating through the received data set, yet the amount of data is pretty large and I certainly do not want to slow this simple load down. I'd also love to have these object properties stay.
Long story short, my data is like
var dummy = [
{ ID: 1, Name: "opt1" },
{ ID: 2, Name: "opt2" }
];
Is it possible to define an alternate id key?
yes, there is an option called id
Function used to get the id from the choice object or a string
representing the key under which the id is stored.
$("#myselect").select2({
id: 'ID',
data: { results: dummy, text: "Name" },
formatSelection: function (item) { return item.Name; },
formatResult: function (item) { return item.Name }
});

How to access second level JSON object via $.getJSON

Hi guys please take a look at this having trouble reaching second level inside a object that looks like this:
{
"results": [{
"title": "TEAM",
"subtitle": "athletes",
"offset": 0,
"icon": "info",
"relevance": 1,
"link": {
"title": "HOME",
"url": "http://www.test.com",
"id": "23458"
}]
}
and this is the code I have:
var theJson = {
init: function() {
this.url = 'http://test.com/js?jsonfeed=123123';
this.fetch();
},
fetch: function() {
$.getJSON(this.url, function( data ){
var obj = $.map(data.results, function( newObj ){
return {
title: newObj .title,
icon: newObj.icon,
topic: newObj.link.id, //??
topic: newObj["link"].id //??
topic: newObj[1].id //??
};
});
});
}
};
theJson.init();
My question is how do I reach the id var in link array inside results object? Thank guys you all rock!
You are doing it correct the first and second time:
newObj.link.id
newObj["link"].id
There are both correct ways to get the id under link.
You can easily access it by index, like that:
newObj["link"][0]

Categories