Binding of a Collection nested inside a Model - backbone.js

I have this model structure in my mind:
var app = app || {};
// Caratteristica
app.Attribute = Backbone.Model.extend({
defaults: {
name: '',
selected: false
}
});
app.Attributes = Backbone.Collection.extend({
model: app.Attribute
});
// Tipo Caratteristica
app.AttributeCategory = Backbone.Model.extend({
defaults: {
name: '',
attributes: new app.Attributes()
}
});
app.AttributeCategories = Backbone.Collection.extend({
model: app.AttributeCategory,
url: '/ajax/attributes.cfm'
});
My API in '/ajax/attributes.cfm' will give me a response like that:
[
{
"id": "1",
"name": "Type1",
"attributes": [
{
"id": "1",
"name": "Attribute1"
},
{
"id": "2",
"name": "Attribute2"
},
{
"id": "3",
"name": "Attribute3"
}
]
},
{
"id": "2",
"name": "Type2",
"attributes": [
{
"id": "1234",
"name": "Attribute1234"
},
{
"id": "2567",
"name": "Attribute2567"
}
]
}
]
My question is: will this json data be parsed correctly into my nested data structure?
I mean I want to end up having two app.AttributeCategory items in my app.AttributeCategories collection. Each of these two items must then have its attributes property filled with the corresponding app.Attributes collection.
If the answer was NO, how would I override the parse() function for achieving that result?

I did it like this:
// Tipo Caratteristica
app.AttributeCategory = Backbone.Model.extend({
defaults: {
name: ''
},
initialize: function(options) {
this.set('attributes', new app.Attributes(options.attributes));
Backbone.Model.prototype.apply(this, arguments);
}
});
But better use RationalModel for set up relations betweens models

You can create the collection inside an initialize method in your AttributeCategory model, like this:
app.AttributeCategory = Backbone.Model.extend({
...
initialize: function () {
this.set('attributes', new app.Attributes(this.get('attributes')));
}
});

Related

How to create nested array in realm without key(React Native)

{
"a": [
[
{
"_id": "57e55b64016c3551c025abc1",
"title": "Main Campus"
},
{
"_id": "5810e2e27064497f74ad4874",
"title": "Ahm Campus"
},
{
"_id": "5d5d2633a1d0680620ac3cce",
"title": "Baroda"
},
{
"_id": "5d5d3af3a1d0680620ac3ef8",
"title": "India"
}
],
[
{
"_id": "57e55b64016c3551c025abc1",
"title": "Main Campus"
},
{
"_id": "5810e2e27064497f74ad4874",
"title": "Ahm Campus"
},
{
"_id": "5d5d2633a1d0680620ac3cce",
"title": "Baroda"
},
{
"_id": "5d5d3af3a1d0680620ac3ef8",
"title": "India"
}
]
]
}
How to create the schema in the realm(React native) for this type of JSON object. I tried all possible ways but did not found any specific solution. Basically, it is a nested array where the second array does not have any specific key(I tried with key it works fine but I want to do it without adding key).
You can use something like:
const ParentSchema = {
name: "parent",
properties: {
key: "string",
values: "Value[]"
}
};
const ValueSchema = {
name: "Value",
embedded: true,
properties: {
_id: "string",
title: "string"
}
};
You can insert objects like:
realm.write(() => {
realm.create("Parent", { key: "a", values: [
{ _id: "57e55b64016c3551c025abc1", title: "Main Campus" },
{ _id: "5810e2e27064497f74ad4874", title: "Ahm Campus" }
]
});
});
Documentation: https://docs.mongodb.com/realm/node/data-model
As of now there is no way to insert direct value in Realm database without key so for now we need to modify data and then we can store in following schema.
const ParentSchema = {
name: "parent",
properties: {
a: "level[]"
}
};
const level = {
name: 'level',
properties: {
level: 'sites[]'
}
}
const sites = {
name: 'sites',
properties: {
sites: 'site[]'
}
}
const site = {
name: 'site',
properties: {
title: 'string?',
_id: 'string?',
version: 'int?',
}
}
Data modification need to done like following.
var a = {
level: []
}
data.a.map((Site, index) => {
const sites = []
Site.map((s) => { sites.push(s)})
a.level.push({sites})
})

Error in routing with id parameter, link works but displays no data

I am having an issue with retrieving the stored data (within MongoDB) by way of an :id parameter. The link works and takes me to the specified url (./contests/1), but the data doesn't show up. When querying within the mongo CMD with (db.contests.find( {id:1} )) the correct object's data is displayed correctly.
route/contest.js
router.route("/contests/:id")
.get(function(req, res, next) {
Contest.findOne({id: req.params.id}, function(err, contest) {
if(err) {
res.send(err);
}
res.json(contest);
});
service/contestService.js
app.factory("contestService", ["$http", "$resource",
function($http, $resource)
{
var o = {
contests: []
};
function getAll() {
return $http.get("/contests").then(function(res) {
angular.copy(res.data, o.contests);
});
}
function get(id) {
return $resource('/contests/:id');
}
o.getAll = getAll;
o.get = get;
return o;
}]);
})();
controller/contestController.js
var app = angular.module("sportsApp.controllers.contest,["ui.router"]);
app.config(["$stateProvider", function($stateProvider) {
$stateProvider.state("contest", {
parent: "root",
url: "/contests/:id",
views: {
"container#": {
templateUrl: "partials/contests",
controller: "ContestController"
}
}
});
}
]);
app.controller("ContestController", ["$scope","contestService", "$stateParams", function($scope, contestService, $stateParams) {
var contest_id = $stateParams.id;
$scope.contest = contestService.get({id: contest_id});
}]);
})();
Contest Schema
var mongoose = require("mongoose");
var ContestSchema = new mongoose.Schema(
{
id: Number,
tags: String,
matchups: [{
type: mongoose.Schema.Types.ObjectId,
ref: "Matchup"
}],
usersWhoJoined: [{
type: mongoose.Schema.Types.ObjectId,
ref: "User"
}]
});
mongoose.model("Contest", ContestSchema);
Any assistance or advice would be much appreciated due to the fact that I am learning as I go with the MEAN stack and have little to no experience with it.
I am looking to display the specific contest's matchups in which displays two teams and other variables. This is my json file that I mongoimported in order to create the object of the contests collection within MongoDB:
{
"id": 1,
"tags": "NBA",
"matchups": [{
"matchupId": 1,
"selectedTeam": "",
"matchupWinner": "Atlanta",
"nbaTeams": [{
"team": "Portland",
"logo": "stylesheets/nbalogos/Portland-Trail-Blazers-Logo.png"
}, {
"team": "Atlanta",
"logo": "stylesheets/nbalogos/atl-hawks.png"
}]
}, {
"matchupId": 2,
"selectedTeam": "",
"matchupWinner": "Dallas",
"nbaTeams": [{
"team": "Dallas",
"logo": "stylesheets/nbalogos/Dallas-Mavericks.png"
}, {
"team": "Detroit",
"logo": "stylesheets/nbalogos/DET.png"
}]
}, {
"matchupId": 3,
"selectedTeam": "",
"matchupWinner": "Golden State",
"nbaTeams": [{
"team": "Golden State",
"logo": "stylesheets/nbalogos/GSW.png"
}, {
"team": "Memphis",
"logo": "stylesheets/nbalogos/Memphis-Grizzlies.png"
}]
}, {
"matchupId": 4,
"selectedTeam": "",
"matchupWinner": "Oklahoma City",
"nbaTeams": [{
"team": "Oklahoma City",
"logo": "stylesheets/nbalogos/OKC-Thunder.png"
}, {
"team": "Pheonix",
"logo": "stylesheets/nbalogos/Pheonix-Suns.jpg"
}]
}, {
"matchupId": 5,
"selectedTeam": "",
"matchupWinner": "Utah",
"nbaTeams": [{
"team": "Sacremento",
"logo": "stylesheets/nbalogos/Sacremento-Kings.jpg"
}, {
"team": "Utah",
"logo": "stylesheets/nbalogos/Utah-Jazz.jpg"
}]
}]
}
I want to create each contest in this format.
I have no idea what relevance the actual data has to this issue, so let's start with $scope.contest, since there seems to be a problem with the way you're accessing data.
// ContestController
$scope.contest = contestService.get({id: contest_id});
OK, so you're calling the contestService.get method with an object, let's say it's {id: 2}. Let's look at that method and call it with that object.
// contestService
function get(id) {
return $resource('/contests/' + id);
}
If using our dummy data, if you call get({id: 2}), you now have an Angular resource at the URL /contests/[object Object] because your object gets converted into a string. Your method would work if called using the value at the id property of that object, like:
// ContestController
$scope.contest = contestService.get(contest_id);

Creating a Backbone.js Model with complex JSON

I have JSON response as follows
{
"results": [
{
"name": "FOO",
"containerName": "Foo",
"accounts": [
{
"id": "10445570_7601",
"shareeAccountInfo": "",
"siteAccountId": "271555",
"siteId": "271555",
"refreshMode": "NORMAL",
"isNetIncl": "true",
"propertyId": null,
"amount": [
"0.0",
"USD"
]
},
{
"id": "1070_20537601",
"shareeAccountInfo": "",
"siteAccountId": "271555",
"siteId": "271555",
"refreshMode": "NORMAL",
"isNetIncl": "true",
"propertyId": null,
"amount": [
"0.0",
"USD"
]
}
]
},
{
"name": "FOO123",
"containerName": "Foo123",
"accounts": [
{
"id": "10445570_20601",
"shareeAccountInfo": "",
"siteAccountId": "271555",
"siteId": "271555",
"refreshMode": "NORMAL",
"isNetIncl": "true",
"propertyId": null,
"amount": [
"0.0",
"USD"
]
},
{
"id": "10445570_37601",
"shareeAccountInfo": "",
"siteAccountId": "271555",
"siteId": "271555",
"refreshMode": "NORMAL",
"isNetIncl": "true",
"propertyId": null,
"amount": [
"0.0",
"USD"
]
}
]
},
{
"name": "FOO83838",
"containerName": "Foo3232",
"accounts": [
{
"id": "1601",
"shareeAccountInfo": "",
"siteAccountId": "271555",
"siteId": "271555",
"refreshMode": "NORMAL",
"isNetIncl": "true",
"propertyId": null,
"amount": [
"0.0",
"USD"
]
}
]
}
]
}
I am having issues creating a Backbone Model from this JSON response.
Should I be using a nested Model? and how should I be creating a collection based of my Model? Instead will it be a good idea to flatten this JSON structure? any ideas?
Your data structure naturally fits a Collection of Models (I'll call the model Group), where each Group contains a collection of Account models. This collection (and optionally its models) should have a reference to the parent Group.
var Account = Backbone.Model.extend({
})
var Accounts = Backbone.Collection.extend({
model: Account,
initialize: function(models, options) {
this.parent = options.parent;
}
});
var Group = Backbone.Model.extend({
initialize: function() {
this.accounts = new Accounts([], { parent: this });
}
});
var Groups = Backbone.Collection.extend({
model: Group,
// Assuming you make requests to `/group` to produce your result JSON
url: 'group',
// Construct models from the `results` attribute of the response
parse: function(response) {
return response.results;
}
});
There are two main implementation choices to make:
Persistence
If individual Accounts can be persisted seperately from the parent container, perhaps using an endpoint like /group/FOO83838/account/1601, the Acccount model can use the default Backbone.Model.save. The Accounts collection should override url to reference the parent URL:
Accounts = Backbone.Collection.extend({
// code from earlier
url: function() {
return this.parent.url() + '/account';
}
});
If accounts can only be saved as part of the overall Group model, you need to do two things:
First, override Account.save to delegate to the parent's save method:
Account = Backbone.Model.extend({
// code from earlier
save: function() {
this.collection.parent.save();
}
});
Second, override the Group.toJSON to include child accounts:
Group = Backbone.Model.extend({
// code from earlier
toJSON: function() {
var json = Backbone.Model.prototype.toJSON.call(this);
json.accounts = this.accounts.toJSON();
return json;
}
});
(In this example I have used the collection's parent reference. If you prefer you could also save a reference to the parent on this model).
Events
You could allow app code to directly listen to Group.accounts events, in which case no code changes are required:
// Example view code
this.listenTo(group.accounts, 'change', this.onAccountChange, this);
Or, if you prefer the extra encapsulation, you can forward child model changes:
Group = Backbone.Model.extend({
// code from earlier
initialize: function() {
this.accounts = new Accounts([], { parent: this });
this.listenTo(this.accounts, 'all', this.onChildEvent, this);
}
onChildEvent: function(eventName, model, options) {
// write logic to whitelist the events and parameters you are interested in
this.trigger('child:' + eventName, model, options);
}
});
// Example view code
this.listenTo(group, 'child:change', this.onAccountChange, this);
You could also look into Backbone extensions like DeepModel (no longer maintained) or Relational. I usually prefer the finer control of a custom implementation.

Backbone (Marionette) fetch in a collection returns an empty array (nested models)

I'm working with nested models and collections in Backbone (Marionette).
// Basic unit
Models.User = Backbone.Model.extend({});
Models.Users = Backbone.Collection.extend({ model: Models.User });
// A Group has a collection of Users
Models.Group = Backbone.Model.extend({
initialize: function() {
var users = new Models.Users(this.get("users"));
this.set("users", users);
}
});
Models.Groups = Backbone.Collection.extend({ model: Models.Group });
// An Organization has a collection of Groups
Models.Organization = Backbone.Model.extend({
initialize: function() {
var groups = new Models.Groups(this.get("groups"));
this.set("groups", groups);
}
});
Models.Organizations = Backbone.Collection.extend({
model: Models.Organization,
url: "./data/data.json"
});
My understanding is that this.get will return an array of objects (as determined via the data.json file) and convert it to a Backbone Collection.
The data.json file has the following structure:
[{
"id": "org1",
"groups": [{
"id": "group1",
"users": [
{ "name": "Alice" },
{ "name": "Bob" }
]
},
{
"id": "group2",
"users": [{ "name": "Charlie" }]
}]
},
{
"id": "org2",
"groups": [{
"id": "groupA",
"users": [{ "name": "Eve" }]
},
{
"id": "groupB",
"users": [
{ "name": "Linda" },
{ "name": "Mallory" }
]
}]
}]
I'm trying to populate the top-most collection (an Organization) with the data from data.json.
In index.html, I have:
<script type="text/javascript">
$(document).ready(function() {
MyApp.OrgManager.addInitializer(function() {
var data = new MyApp.Models.Organizations();
data.fetch({
success: function(collection) {
console.log("Success", collection);
}
});
});
MyApp.start();
});
</script>
fetch returns successfully, but the output of my console for the collection is an empty array. What went wrong?
Solved it. Had to make sure that
I was running the page on a local webserver, since jQuery doesn't like null origin XMLHttpRequests, and
I had to _.bindAll a few things so that this had a proper context.

I am new to backbone.js. I want to create a collection object to retrieve the json object from server

Here is the data I'm getting from server. How do I store this JSON object in my backbone script and display it in a browser? Please help.
How can i built model or nested collection to retrive this data..
I am getting two kind of response from the server depend on query.
1st response:
[
{
"groups": [
{
"groupname": "Group_all",
"group": [
{
"displayname": "facebook",
"monitortype": "URL",
"responsetimereport": "value2",
"availabilityreport": "value4"
},
{
"displayname": "gmai",
"monitortype": "URL",
"responsetimereport": "value5",
"availabilityreport": "value6"
},
{
"displayname": "zoho",
"monitortype": "URL",
"responsetimereport": "value2",
"availabilityreport": "value1"
}
]
}
]
},
{
"monitor": []
}
]
2.Response
[
{
"groups": []
},
{
"monitor": [
{
"displayname": "facebook",
"monitortype": "URL",
"responsetimereport": "value2",
"availabilityreport": "value1"
}
]
}
]
what i have written to achieve this, i am pasting here
studentdb.Monitor = Backbone.Model.extend({
initialize : function(){
this.Displayname = this.get('displayname');
this.Monitortype = this.get('monitortype');
this.Responsetimereport = this.get('responsetimereport');
this.Availabilityreport= this.get('availabilityreport');
}
});
studentdb.Monitors = Backbone.Collection.extend({ model : studentdb.Monitor });
studentdb.Group1 = Backbone.Model.extend({
initialize : function(){
this.Displayname = this.get('displayname');
this.Monitortype = this.get('monitortype');
this.Responsetimereport = this.get('responsetimereport');
this.Availabilityreport= this.get('availabilityreport');
}
});
studentdb.Group1s = Backbone.Collection.extend({ model : studentdb.Group1 });
studentdb.Group_outer = Backbone.Model.extend({
defaults :{Groupname:""},
initialize : function(){
this.outer_group = new studentdb.Group1s(this.get('group'));
this.Groupname = this.get('groupname');
this.outer_group.parent = this;
}
});
studentdb.Group_outers = Backbone.Collection.extend({ model : studentdb.Group_outer });
studentdb.Overall = Backbone.Model.extend({
initialize : function(){
this.group_outer =new studentdb.Group_outers(this.get('groups'));
this.monitors = new studentdb.Monitors(this.get('monitor'));
}
});
studentdb.Final = Backbone.Collection.extend({
url:'https://data.json',
model : studentdb.Overall,
});
Basically, you must populate a collection with your data fetched from server, and then render your view based on a template.
Instead giving you a complete solution, i think you should first read some tutorials about backbone :
http://blog.joelberghoff.com/2012/07/22/backbone-js-tutorial-part-1/
http://backbonetutorials.com/what-is-a-collection/
could you post your collection code?
I'm afraid your json response probably can't be used directly in a backbone collection.
in that JSON, the array contains two members, the first one contains another array which has only one member (which contains groupName, and group( which really should be called groups))
if it is a 'Groups' collection, you will need to use parse.
docs here: http://backbonejs.org/#Collection-parse
it should process your response and return an array of Group model attributes like so:
[
{
"displayname": "facebook",
"monitortype": "URL",
"responsetimereport": "value2",
"availabilityreport": "value4"
},
{
"displayname": "gmai",
"monitortype": "URL",
"responsetimereport": "value5",
"availabilityreport": "value6"
},
{
"displayname": "zoho",
"monitortype": "URL",
"responsetimereport": "value2",
"availabilityreport": "value1"
}
]

Resources