Collection - Model usage for JSON response? - json

Regarding the pattern Backbone uses for Collections and Models , I am not sure if what I am trying to achieve is possible.
I am wanting the Collection to act as a constructor by making a AJAX POST request to fetch JSON. Using that JSON response it will instantiate multiple models and add them to an array.
Each object has the attributes which will be stored in my model e.g.
define([
'underscore',
'backbone'
], function (_, Backbone)
{
'use strict';
var Employee= Backbone.Model.extend({
defaults: {
name: '',
skill: '',
latitude : 0,
longitude : 0
},
});
return Employee;
});
JSON Response
[
{
"name" : "bob",
"skill" : "project manager",
"latitude" : 12512.25,
"longitude" : 95952.26
},
{
"name" : "sarah",
"skill" : "software dev",
"latitude" : 89432.25,
"longitude" : 1205.26
},
{
"name" : "tom",
"skill" : "evil sys admin",
"latitude" : 1215,
"longitude" : 92325
}
]
Collection
define([
'underscore',
'backbone',
'models/employee'
], function (_, Backbone, Store, Employee) {
'use strict';
var Employees = Backbone.Collection.extend({
// Reference to this collection's model.
model: Employee,
});
return new Employees();
});
Code
emps = new Employees();
emps.url("/testURL"); //
emps.sync();
emps.model[0]; //undefined !!!
So from that I can conclude that the Collection is not smart enough to instantiate an array of Employee models from the JSON response.
How can I do this?

The function you're looking for is fetch. Fetch uses sync to fetch data, and then instantiates models accordingly.
If your API doesn't respond to a GET /someurl then what you need to override is the sync method. Read the source to see how it works.
Also, you're not using url properly. It should be a string, or a function that returns a string.
var employees = new Employees();
employees.url = '/my/testurl';
// note that fetch is async
employees.fetch().done(function () {
console.log(employees.length);
});

Right now your collection constructor code is getting undefined as its input array, and thus remains empty.
You want to pass your collection into your Employees constructor, like
var emps = new Employees(arrayOfEmployees, {model: Employee});
Also, that last part (re-specifying the model) is likely not necessary.

Related

Read and transmit JSON file from Express to Jade

I'm new to Express and Jade, can't find why Jade tells me the object is undefined.
I've a big JSON file about a collectionable card game, which structure is:
{
"LEA" : { /* set data */ },
"LEB" : { /* set data */ },
"2ED" : { /* set data */ },
...
}
and, for each set
"name" : "Nemesis",
"code" : "NMS",
"gathererCode" : "NE",
"oldCode" : "NEM",
"magicCardsInfoCode" : "ne",
"releaseDate" : "2000-02-14"
"border" : "black",
"type" : "expansion",
"block" : "Masques",
"onlineOnly" : false,
"booster" : [ "rare", ... ],
"cards" : [ {}, {}, {}, ... ]
I want to loop through the array of cards for a GETed set and display some informations about. This is my cards.js file
'use strict';
var express = require('express');
var router = express.Router();
var mtgjson = require('mtgjson');
router.get('/:set?', function(req, res){
var set = req.params.set;
if (set === undefined) {
res.send('respond with a resource');
} else {
mtgjson(function(err, data) {
if (err) return console.log(err);
res.render('cards', { selectedSet : data.set });
});
}
});
module.exports = router;
and this the jade template
extends layout
block content
h1 #{selectedSet.name}
ul
each card in selectedSet.cards
li #{card.rarity}
I'm getting
Cannot read property 'name' of undefined
Any suggestion will be much appreciated, I'm probably making some stupid error.
EDIT: New informations ------------------
When I console.log(data) I get the following, it seems right:
TOR:
{ name: 'Torment',
code: 'TOR',
magicCardsInfoCode: 'tr',
releaseDate: '2002-02-04',
border: 'black',
type: 'expansion',
block: 'Odyssey',
booster:
[ 'rare',
'uncommon',
...
'common' ],
cards:
[ [Object],
[Object],
[Object],
...
[Object],
[Object],
[Object] ] },
And if I console set It gives me the right string ( TOR in this example ).
Edit 2 -------------------------
If I pass the entire data object and the set variable to the jade template, I can achieve the final result but in a very sub-optimal way.
I've made something like this
block content
ul
each val, key in data
if key == set
li #{val.name}
each card in val.cards
p #{card.name}
SOLUTION ----
Just a stupid error: I just messed up with property accessors. I should use data[set] instead of data.set beacause var set is a literal.
See reference http://www.ecma-international.org/ecma-262/5.1/#sec-11.2.1
You need to use selectedSet.cards.rarity instead of cards.rarity. The only object you are passing to the template is your selectedSet object, and cards is nested within that.
I was using the wrong notation to access properties. I should use square brackets notation beacause the var set is a string literal, in this case the dot notation won't work.
See reference

Reformat API data to Ember friendly array of objects | Ember data with unconventional endpoint

This is a question about molding some API data to fit some needs. I've heard it called "munging." I guess the heart of if is really re-formatting some JSON, but It would be ideal to do it the Ember data way...
I'm getting this data in an Emberjs setting - but it shouldn't really matter - ajax, ic-ajax, fetch, etc... I'm getting some data:
...
model: function() {
var libraryData = ajax({
url: endPoint,
type: 'GET',
dataType: 'jsonp'
});
// or most likely the ember-data way
// this.store.findAll(...
console.log(libraryData);
return libraryData;
}
...
The URL is getting me something like this:
var widgetResults = {
"settings": {
"amazonchoice":null,
"show":{
"showCovers":null,
"showAuthors":null
},
"style":null,
"domain":"www.librarything.com",
"textsnippets":{
"by":"by",
"Tagged":"Tagged","readreview":"read review","stars":"stars"
}
},
"books":{
"116429012":{
"book_id":"116429012",
"title":"The Book of Three (The Chronicles of Prydain Book 1)",
"author_lf":"Alexander, Lloyd",
"author_fl":"Lloyd Alexander",
// ...
The promise that is actually returned is slightly different.
My goal is to get to those books and iterate over them - but in my case it wants an array. that #each loops over must be an Array. You passed {settings: [object Object], books: [object Object]} - which makes sense.
In and ideal API the endpoint would be / http:/site.com/api/v2/books
and retrieve the data in this format:
{
"book_id":"116428944",
"title":"The Phantom Tollbooth",
"author_lf":"Juster, Norton",
"author_fl":"Norton Juster",
...
},
{
"book_id":"116428944",
"title":"The Phantom Tollbooth",
"author_lf":"Juster, Norton",
"author_fl":"Norton Juster",
...
},
{
... etc.
I would expect to just drill down with dot notation, or to use some findAll() but I'm just shooting in the dark. Librarything in specific is almost done with their new API - but suggest that I should be able to loop through this data and reformat it in an ember friendly way. I have just looped through and returned an array in this codepen - but haven't had luck porting it... something about the returned promise is mysterious to me.
How should I go about this? am I pointed in the wrong direction?
I've tried using the RESTAdapter - but didn't have much luck dealing with more unconventional endpoints.
Custom Adapters / Serializers ?
this article just appeared: "Fit any backend into ember with custom adapters and serializers
Full url with endpoint in question
model (just title to test)
import DS from 'ember-data';
export default DS.Model.extend({
title: DS.attr('string')
});
route ( per #Artych )
export default Ember.Route.extend({
model() {
$.ajax({
url: endPoint,
type: 'GET',
dataType: 'jsonp'
}).then((widgetResults) => {
// modify payload to RESTAdapter
var booksObj = widgetResults.books;
var booksArray = Object.keys(booksObj).map((element) => {
var book = booksObj[element];
book.id = book.book_id;
delete book.book_id;
return book;
});
console.log(booksArray);
this.store.pushPayload({books: booksArray});
});
return this.store.peekAll('book');
}
});
template
{{#each model as |book|}}
<article>
<h1>{{book.title}}</h1>
</article>
{{/each}}
There is straightforward solution to process your payload in model():
Define book model.
Process your payload in model() hook:
model() {
$.ajax({
url: endPoint,
type: 'GET',
dataType: 'jsonp'
}).then((widgetResults) => {
// modify payload to RESTAdapter
var booksObj = widgetResults.books;
var booksArray = Object.keys(booksObj).map((element) => {
var book = booksObj[element];
book.id = book.book_id;
delete book.book_id;
return book;
});
this.store.pushPayload({books: booksArray});
});
return this.store.peekAll('book');
}
Iterate model in controller or template as usual.
Working jsbin:
ember 1.13
ember 2.0
You want a custom serializer to translate the data from that format into JSON-API. JSON-API is an extremely well thought-out structure, so well in fact that ember-data has adopted it as the default format used internally. Some of the benefits are that it defines a structure for objects themselves, separating attributes from relationships; a means for embedding or including associated resources; defines a place for errors and other metadata.
In short, for whatever you're trying to do, JSON-API probably has already done a lot of the decision-making for you. And, by subclassing from DS.JSONSerializer, you'll be mapping right into the format that ember-data needs.
To do this, you create a custom adapter using ember generate serializer books:
// app/serializers/book.js
import DS from 'ember-data';
export default DS.JSONSerializer.extend({
normalizeResponse(store, primaryModelClass, payload, id, requestType) {
// payload will contain your example object
// You should return a JSON-API document
const doc = {};
// ...
return doc;
}
});
For your example data, the output of the normalization should look something like this:
{
"data": [
{
"type": "books",
"id": 116429012,
"attributes": {
"title": "The Book of Three (The Chronicles of Prydain Book 1)",
"author_lf": "Alexander, Lloyd",
"author_fl": "Lloyd Alexander"
}
},
{
"type": "books",
"id": 1234,
"attributes": {
}
}
],
"meta": {
"settings": {
"amazonchoice":null,
"show":{
"showCovers":null,
"showAuthors":null
},
"style":null,
"domain":"www.librarything.com",
"textsnippets":{
"by":"by",
"Tagged":"Tagged","readreview":"read review","stars":"stars"
}
}
}
};
Then do
this.get('store').findAll('books').then((books) => {
const meta = books.get('meta');
console.log(meta.settings.domain);
books.forEach((book) => {
console.log(book.get('title'));
});
});
Code is not tested, but hopefully it gets you started.
Define settings and book models. Arrange for the API to respond to the endpoint /books returning data in the format:
{
settings: { ... },
books: [
{
id: xxx,
...
}
]
}
Retrieve the data in the model hook with this.store.findAll('book').
Iterate over the books in your template with {{#each model as |book|}}.

extjs error on filling store

I have a java map. I converted it to json string and I obtain something like this :
{"NEW ZEALAND":"111111111111111","CHAD":"1","MOROCCO":"111","LATVIA":"11"}
Now I want to use it in a store and then a chart like the following code but it's not working. I have no error just no display.
var obj = Ext.Ajax.request({
url: App.rootPath + '/controller/home/dashboard/test.json',
method:'GET',
success: function(response) {
return Ext.JSON.decode(response.responseText);
}
});
var store2 = Ext.create('Ext.data.Store', {
model: 'PopulationPoint',
data: obj
});
Ext.create('Ext.chart.Chart', {
renderTo: 'infos2',
width: 500,
height: 300,
store: store2,
series: [
{
type: 'pie',
field: 'population',
label: {
field: 'state',
display: 'rotate',
font: '12px Arial'
}
}
]
});
The AJAX request is asynchronous. As such, the obj variable used to initialize your data won't contain your data yet.
One option is to create the store2 variable and create the chart directly in the success callback of the AJAX request.
A cleaner option would be to configure the store with a proxy to load the url, and in the callback create the chart.
EDIT
The JSON response does not contain the fields that are declared in your model (sent in the comments). Update the JSON to return a properly formatted model and the chart should work as seen in this fiddle. The JSON should look something like
[
{
"state" : "New Zealand",
"population" : 111111111
},
{
"state" : "Chad",
"population" : 1
}
]

loading data from json in sencha

I am creating an application where i have created a list and populated the data in the list using a data store.
data.js
Ext.regModel('Contact', {
fields: ['firstName', 'lastName', 'DOB', 'group']
});
iPolis.ListStore = new Ext.data.Store({
model: 'Contact',
sorters: 'lastName',
getGroupString : function(record) {
return record.get('group');
},
data: [
{ firstName: "Domino", lastName: "Derval" , DOB: "28May2008", group:"Personalize"},
]
});
This part of the code runs fine where i get the data and display it. Now what i require is a connection to the database and retriving the data in the data.js using a json file.
Any suggestions on how thats possible?
iPolis.ListStore = new Ext.data.Store({
model : 'Contact',
proxy : {
type : 'ajax',
url : 'js/person_list.json',
reader : {
type : 'json',
//root : 'results',
// totalCount : 'total'
}
},
autoLoad : true
});
used this for getting the data but it gives me an error sayin XMLHttprequest cannot load data in file.json
Go through the Ext.data.Proxy in Sencha API and also check the examples of store in API docs.
Just replace the url property of reader to the php file.
return proper JSON

How to create multiple rooted JSON for ExtJS store?

I want to create a JSON string on server side with 2 root. I am using ExtJS 3.2. I want to use first root for load data to grid and the second one is to fill a form with different data.
I am creating JSON string on server side like this;
{
metaData: {
"idProperty": "reportID",
"root": "data",
"successProperty": "success"
},
"success": true,
"data": [
{
"ID": 1,
"name": "Jon",
"surname": "Doe"
}]
}
Let's assume second root name is summary and second idProperty is summaryID. How can I implement this and where can I add summary data?
Thx all.
There is no automagic for you are willing to do.i had the same issue on this project and i figured out how to create multiple stores automatically from a JSON response.put the following code before your grids are loaded.in extjs4,i put the following code in app.js so the stores will be created when the app is initialized.The stores will be created automatically,dependent on what the JSON returns:
Ext.Ajax
.request({
url : './account/getadminstores',
callback : function(options, success, response) {
var json = Ext.decode(response.responseText);
var adminStores = new Array();
// setup and intitialize on the fly stores
for ( var key1 in json) {
var storeFields = new Array();
for ( var key2 in json[key1]) {// if
// (i==1){break;}
// console.log(key2);
for ( var key3 in json[key1][key2]) {
storeFields.push(key3);
}
break;
}
;
Ext.define('MA.store.' + key1, {
extend : 'Ext.data.Store',
fields : storeFields,
storeId : key1,
id : 'MA.store.' + key1,
data : json[key1],
proxy: {
type: 'ajax',
url : './account/getadminstores',
reader: {
type: 'json',
root: key1
}
},
autoLoad: true
});
Ext.create('MA.store.' + key1);
}
;
Created stores for your case would be MA.store.root1and MA.store.root2which MA is your apps namespace(and you should change it to whatever your app namespace is).This code is for extjs4 and you might need some modifications to make it work in older versions.Hope it helps.