Backbone - parsing JSON ID - json

I'm trying to parse JSON data using Backbone from a remote API. Here's what I've got so far:
// --------------------------------------------------
// MODELS
// --------------------------------------------------
var VideoModel = Backbone.Model.extend({
idAttribute: '_id',
parse: function(){
this.id = response._id;
}
});
var videoModel = new VideoModel({ parse:true });
// --------------------------------------------------
// COLLECTIONS
// --------------------------------------------------
var VideosCollection = Backbone.Collection.extend({
model: VideoModel,
url: 'redacted',
parse: function(response){
this.videos = response.data;
this.cid = response.cid;
return response.data;
},
render: function(){
this.collection.forEach(this.addone, this);
}
});
var videosCollection = new VideosCollection();
videosCollection.fetch({
success: function(videos){
console.log('success!');
},
error: function(){
console.log('failed.');
}
});
// --------------------------------------------------
// VIEWS
// --------------------------------------------------
var VideoView = Backbone.View.extend({
template: _.template('<%= videoModel.id %>'),
render: function(){
this$el.html(this.template(this.model.attributes));
return this;
}
});
var videoView = new VideoView({});
var VideosCollectionView = Backbone.View.extend({});
var videosCollectionView = new VideosCollectionView({
collection: videosCollection,
render: function(){
this.collection.forEach(this.addOne, this);
},
addOne: function(videoModel){
this.$el.append(videoView.el);
}
});
What I'm having trouble with is that console.log(videoModel.id) is still undefined.
The data is a playlist of videos, which is valid JSON:
{
"total":24,
"per_page":24,
"current_page":1,
"last_page":1,
"from":1,
"to":24,
"data":[
{
"_id":"55d1bb50140ba04c1d8b4583",
Be glad for some prompts in the right direction - especially since I had it working this morning and then ... reverted to a previous version without saving.
Thanks

From documentstion of parse method:
The function is passed the raw response object, and should return the
attributes hash to be set on the model. The default implementation is
a no-op, simply passing through the JSON response.
So by default it works like this:
parse: function(data) {
return data;
}
Your code now returns nothing and model takes no data.
As I see you want to set id attribute but you already have setted idAttribute property with _id and there is _id in your data so it should work fine without parse at all. Try to remove it.

The answer is that I was trying to parse via a Collection instead of a Model. So I would never have got the id I was looking for. For some reason.
I needed to move the URL into the Model and parse from there:
var VideoModel = Backbone.Model.extend({
idAttribute: '_id',
url: 'redacted',
parse: function(response){
var id = response._id;
var cid = response.cid;
return response.data;
},
}),
Now when I do videoModel.get(1) in the console, it returns the value of the first item in my array.

Related

How to fetch 4 JSON (API) Responses to one view in backbone.js using Model/Collection

I'm learning how to use backbone.js. I got 4 JSON APIs, and I need to collect all the responses and fetch the total response to single view
How can I achieve this? Do I need to use collection/model to achieve this?
I implemented a 2 call main view with sub views. It gets a lot more complex then that. But that should get you started.
These are the main 2 collections that get the data. If you want to break it down further (depends on needs) you can create a Model and then assign it to the collection using model: CityModel (in this case).
var Cities = Backbone.Collection.extend({
url: 'http://api.geonames.org/citiesJSON?north=44.1&south=-9.9&east=-22.4&west=55.2&lang=de&username=me',
parse: function(response) {
return response.geonames;
}
});
var Earthquakes = Backbone.Collection.extend({
url: 'http://api.geonames.org/earthquakesJSON?north=44.1&south=-9.9&east=-22.4&west=55.2&username=me',
parse: function(response) {
return response.earthquakes;
}
});
then the sub views, standard: here you can create events for each.
var EarthquakeView = Backbone.View.extend({
tagName: 'li',
template: _.template('<strong><%=eqid%></strong> <%=lng%> <%=lat%> magnitude: <%=magnitude%>'),
render: function() {
this.$el.html(this.template(this.model.toJSON()))
return this;
}
});
Notice here you can extend a view so you dont have to repeat yourself.
var CityView = EarthquakeView.extend({
template: _.template('<strong><%=toponymName%></strong> <%=lng%> <%=lat%>')
});
The main view..
var View = Backbone.View.extend({
initialize: function(opt) {
// attach to the main body
$(opt['main']).append(this.el)
this.earthquakesEl = $('<ol>');
this.earthquakes = new Earthquakes()
this.earthquakes.on('sync', _.partial(this.renderList, EarthquakeView, this.earthquakesEl), this);
this.earthquakes.fetch()
this.citiesEl = $('<ol>');
this.cities = new Cities()
this.cities.on('sync', _.partial(this.renderList, CityView, this.citiesEl), this);
this.cities.fetch()
// initialize the element
this.render();
},
renderList: function(view, el, collection) {
collection.forEach(function(model) {
el.append(new view({model: model}).render().el)
});
},
render: function() {
this.$el.append(this.earthquakesEl);
this.$el.append(this.citiesEl);
return this;
}
});
new View({ main: $('body') });
http://jsfiddle.net/u9y574y8/2/
There are 2 collection calls that are made independently, and there are 2 listeners that wait for them to finish and then place it on the main view. If you have any issue let me know. I think its pretty straight forward.

Create a collection from inside a collection

I have a collection, which when fetched gets a json and puts into collection:
The JSON format is:
[
{
name: 'Hello',
age: '22',
bio: [{
interest: 'soccer',
music: 'r&B'
}]
}
]
I want to make another collection from bio (without fetching again).
The reason is I want to access both name, age and bio and a parse function can have only one return?
var user = new Backbone.Collection.extend({
url: '/user',
parse: function (response) {
//I want both of this?
//return response;
return response.bio;
}
});
I am passing this collection on success function of fetch into two different views.
//Controller File....
.............
mycollection.fetch({
success: function() {
//Details View wants response
PrimaryLayout.main.show(new detailsView{collection: mycoll});
//Bio View wants response.bio
PrimaryLayout.body.show(new bioView{collection: mycoll});
}
})
What would be the best way to tackle this? Can I clone a collection and just have bio in it?
I've generally solved this by instantiating the sub-collection in parse:
var User = Backbone.Model.extend({
parse: function(json) {
// instantiate the collection
json.bio = new Backbone.Collection(json.bio);
// now person.get('bio') will return a Collection object
return json;
}
});
var Users = Backbone.Collection.extend({
model: User,
// ...
});
I think this is what you are looking for : Backbone Associations. Have a look at the tutorials and examples there.

Backbone insert data inside Model from another

I have a simple app in backbone where the logic isn't clear for me, It's my second app and I don't know if is good the logic and how I have construct it.
The goal is when I load a page I want to retrieve all folders and files of a specific directory and print it.
I have create an app general where I include another app called Folder.
When I load the page I create the general app, search inside a folder and retireve folders and files into a json with an ajax function.
I have succesfull do that but my problem is how now populate my FolderView, FolderModel and Folder Collection?
Is necessary to do that I think but I don't know how to pass this json to FolderCollection/FOlderModel.
This is my appView
define(['jquery' , 'backbone', 'views/folder', 'models/folder', 'collections/folder', 'models/app'],
function($, Backbone, FolderView, FolderModel, FolderCollection, AppModel){
var AppView = Backbone.View.extend({
model: AppModel,
el:$('#folder'),
initialize: function(){
console.log('initialize AppView');
this.retrievFolderFile('uploads');
//prendo le cartelle e le metto nel json
this.folders = new FolderCollection();
this.render();
//this.todos.bind('sync', this.render, this);
//this.todos.fetch();
},
render: function(){
var element = this.$el;
element.html('');
this.folders.each(function(model){
var folderView = new FolderView({model:model});
element.append(folderView.el);
});
},
retrievFolderFile: function(dir){
var here = this;
console.log('retrieveFolderFile');
$.ajax({
type: "POST",
dataType: "json",
data: {"dir": dir},
url: 'function/retrieve_folder.php',
success: function(data) {
console.log(data);
// ------------------ HERE I HAVE RESULT HOW TO PASS TO FOLDER VIEW/ COLLECTION?------
}
});
}
})
return AppView;
});
This is my folderModel
define(['backbone'],function(Backbone){
var FolderModel = Backbone.Model.extend({
defaults:{
name:'Folder',
path:''
},
initialize:function(){
console.log('Initialized Folder model');
}
});
return FolderModel;
});
This is my FolderCollection
define(['backbone', 'models/folder'], function(Backbone, FolderModel){
var folderCollection = Backbone.Collection.extend({
model: FolderModel,
});
return folderCollection;
});
This is my FolderView
define(['jquery', 'underscore', 'backbone', 'text!templates/folder.html'], function($, _, Backbone, FolderTemplate){
var FolderView = Backbone.View.extend({
el:$('#folder'),
template: _.template(FolderTemplate),
initialize: function(){
console.log('FolderView initialized');
this.render();
},
render: function(){
console.log('FolderView render');
//$(this.el).html(this.template({model: this.options.model}));
}
});
return FolderView;
});
To retrieve folder and files I use this file PHP that return me a valid json to backbone
<?php
$dir = $_POST['dir'];
$data = fillArrayWithFileNodes( new DirectoryIterator( '../'.$dir ) );
function fillArrayWithFileNodes( DirectoryIterator $dir )
{
$data = array();
foreach ( $dir as $node )
{
if ( $node->isDir() && !$node->isDot() )
{
//$data[$node->getFilename()] = fillArrayWithFileNodes( new DirectoryIterator( $node->getPathname() ) );
$arr_to_insert = array();
$arr_to_insert['name'] = $node->getFilename();
$arr_to_insert['type'] = 'folder';
array_push($data, $arr_to_insert);
}
else if ( $node->isFile() )
{
//$data[] = $node->getFilename();
$arr_to_insert = array();
$arr_to_insert['name'] = $node->getFilename();
$arr_to_insert['type'] = 'file';
array_push($data, $arr_to_insert);
}
}
return $data;
}
echo json_encode($data);
?>
How to pass from appview the json that return me?
Is correct to do the folderand filde search inside appview or I have to do it inside folderModel?
Because after when I click on a folder I want to retrieve its file and folders again.
Help me to understand the logic and how to pass it.
I thought to call a function inside FolderCollection like parseFolderFile and insert it into a model but how?
Thanks
AJAX is asynchronous.. So you are making an ajax call and then calling the render method which is iterating over the collection and renders them.
But your data is not ready until and after the sucess callback, where I guess your collection will be populated. So you are supposed to populate the collection inside the success call back and then call render.
So something in these lines
initialize: function () {
console.log('initialize AppView');
this.folders = new FolderCollection();
this.retrievFolderFile('uploads');
},
render: function () {
var element = this.$el;
element.html('');
this.folders.each(function (model) {
var folderView = new FolderView({
model: model
});
element.append(folderView.el);
});
},
retrievFolderFile: function (dir) {
var here = this;
console.log('retrieveFolderFile');
$.ajax({
type: "POST",
dataType: "json",
data: {
"dir": dir
},
url: 'function/retrieve_folder.php',
success: function (data) {
console.log(data);
here.folders.set(data);
here.render();
}
});
}
Also why do you want to handle an ajax request , where there is already a native one provided by backbone.
You can declare the url in the collection do this.folders.fetch() , and then listen to the sync or the resent event which will be lot more cleaner in my view.
Using native Fetch
define(['jquery', 'backbone', 'views/folder', 'models/folder',
'collections/folder', 'models/app'],
function ($, Backbone, FolderView, FolderModel,
FolderCollection, AppModel) {
var AppView = Backbone.View.extend({
model: AppModel,
el: $('#folder'),
initialize: function () {
this.folders = new FolderCollection();
// This will automatically call the render once the
// collection is reset
this.listenTo(this.folders, 'reset', this.render);
this.folders.data = 'uploads';
this.folders.fetch();
},
render: function () {
var element = this.$el;
element.html('');
this.folders.each(function (model) {
var folderView = new FolderView({
model: model
});
element.append(folderView.el);
});
}
})
return AppView;
});
define(['backbone', 'models/folder'], function(Backbone, FolderModel){
var folderCollection = Backbone.Collection.extend({
model: FolderModel,
url : 'function/retrieve_folder.php' + this.data;
});
return folderCollection;
});

Getting static data from a json file into backbone model

I have the following code and was wondering why my data isn't getting pulled into my model? I'm using a static json file and I'm guessing this might be my problem but can't seem to find any documentation about it.
var DataModel = Backbone.Model.extend({
initialize: function () {
console.log('initiliazed model')
},
url: "data/data.json"
});
var StructureView = Backbone.View.extend ({
initialize: function () {
console.log('initiliazed view')
_.bindAll(this);
this.model.fetch();
this.render();
this.model.on('change',this.render);
},
el : '#ev-wrapper',
render: function () {
$('#ev-wrapper').empty().append(Handlebars.compile($('#ev-template').html())(this.model.toJSON()));
$('.ev-asset-loader').fadeOut('slow');
}
});
var structureView = new StructureView({model: new DataModel()});
You need to call fetch. This will issue an AJAX request using url
var model = new DataModel();
model.fetch();
Open Firebug or your favorite browser's network console to see AJAX requests and check if it's OK

How to get json with backbone.js

I am trying to use backbones.js fetch to get json from a twitter search
and my code below can someone tell me where I am going wrong?
(function($){
var Item = Backbone.Model.extend();
var List = Backbone.Collection.extend({
model: Item,
url:"http://search.twitter.com/search.json?q=blue%20angels&rpp=5&include_entities=true&result_type=mixed"
});
var ListView = Backbone.View.extend({
el: $('#test'),
events: {
'click button#add': 'getPost'
},
initialize: function(){
_.bindAll(this, 'render', 'getPost');
this.collection = new List();
this.render();
},
render: function(){
var self = this;
$(this.el).append("<button id='add'>get</button>");
},
getPost: function(){
console.log(this.collection.fetch());
}
});
// **listView instance**: Instantiate main app view.
var listView = new ListView();
})(jQuery);​
I am just getting started with backbone and I just want to console.log the json
you can see my example here. jsfiddle.net/YnJ9q/2/
There are two issues above:
Firstly, you need to add a success/fail callback to the fetch method in order for you to have the fetched JSON logged to the console.
getPost: function(){
var that = this;
this.collection.fetch(
{
success: function () {
console.log(that.collection.toJSON());
},
error: function() {
console.log('Failed to fetch!');
}
});
}
Another problem is the issue of "same-origin-policy'. You can find out how to resolve that by taking a look at this link.
Update:
I modified your code and included the updated sync method. It now works! Take a look here!
Basically, update your collection to include the parse and sync methods as below:
var List = Backbone.Collection.extend({
model: Item,
url: "http://search.twitter.com/search.json?q=blue%20angels&rpp=5&include_entities=true&result_type=mixed",
parse: function(response) {
return response.results;
},
sync: function(method, model, options) {
var that = this;
var params = _.extend({
type: 'GET',
dataType: 'jsonp',
url: that.url,
processData: false
}, options);
return $.ajax(params);
}
});