Fetching directory contents to json in backbone - html

I have folder that contains images; I call fetch on the folder uploads/ and my GET returns with the following response in HTML (no json etc)
<h1>Index of /backbone_images/uploads</h1>
<ul><li> Parent Directory</li>
<li> 2012-12-11 15.30.221.jpg</li>
<li> in1.jpg</li>
<li> imagedummy.png</li>
I try to render / my fetched data into models etc with the following code:
window.Person = Backbone.Model.extend({});
window.AddressBook = Backbone.Collection.extend({
url: 'uploads/',// declare url in collection
model: Person
});
window.Addresses = new AddressBook();
window.AppView = Backbone.View.extend({
el: $('#left_col'),
initialize: function() {
Addresses.bind('reset', this.render); // bind rendering to Addresses.fetch()
},
render: function(){
console.log(Addresses.toJSON());
}
});
window.appview = new AppView();
Addresses.fetch();
but nothing is being rendered or appended to my left column: so --> can I fetch from a directory containing images like this? Also what can I do with the HTML response and how can I load it into models, make it render etc (if there is any way) ?

You should change the HTML response into a JSON format so Backbone can render it properly (although there's a way to display the HTML you have above, this isn't a recommended approach as it's better to render raw data).
You can do something like this:
HTML:
<div id="container">
</div>
<script id="template" type="text/html">
<li><img src=<%- dir %><%- image %> /></li>
</script>
JavaScript:
$(function(){
/** Your response object would look something like this. */
var json = {'parent_directory':
{'dir_desc': 'Index of /backbone_images/uploads',
'images': [
{'dir': '/images/', 'image': 'image1.jpg'},
{'dir': '/images/', 'image': 'image2.jpg'},
{'dir': '/images/', 'image': 'image3.jpg'}
]
}};
/** Create a simple Backbone app. */
var Model = Backbone.Model.extend({});
var Collection = Backbone.Collection.extend({
model: Model
});
var View = Backbone.View.extend({
tagName: 'ul',
initialize: function() {
this.render();
},
template: _.template($('#template').html()),
render: function() {
_.each(this.collection.toJSON(), function(val){
this.$el.append(this.template({
image: val.image,
dir: val.dir}));
}, this);
return this;
}
});
/** Create a new collection and view instance. */
var newColl = new Collection(json.parent_directory.images);
var newView = new View({collection: newColl});
$('#container').html(newView.el);
});

You should bind it to the sync event
Also I prefer to use listenTo
this.listenTo(Addresses, 'sync', this.render)

Related

Populating a BackboneJS model with response from an API endpoint

I'm new to BackboneJS but I'm doing my best to learn it. I'm more familiar with AngularJS so I have some confusion in BackboneJS but would definitely want to become an expert BackboneJS developer too.
Back at my previous job, I was the frontend dev and I would work with the Java dev guy. We would have a meeting about how the JSON response would look like. Basically, I'll make a REST call(either with Restangular or $http) to one of their endpoints and I'll get a response. The JSON response will be assigned to a scope variable such as $scope.bookCollection. In my template, I'll just use ng-repeat to display it.
Now with BackboneJS, I'd like to do it properly. I read today that a BackboneJS Model is a container. What I'd like to happen is that after making a fetch(), I want the JSON response to be put in the Model that I defined. How is that done?
I found an example jsfiddle but I think it's a very bad example. I can't find something that is helpful right now, something with a good fetched data.
require.config({
paths: {
jquery: 'http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min',
underscore: 'http://underscorejs.org/underscore',
backbone: 'http://backbonejs.org/backbone-min'
},
shim: {
backbone: {
deps: ["underscore", "jquery"],
exports: "Backbone"
},
underscore: {
exports: "_"
}
}
});
require([
'jquery',
'underscore',
'backbone'], function ($, _, Backbone) {
var UserModel = Backbone.Model.extend({
urlRoot: '/echo/json/',
defaults: {
name: '',
email: ''
}
});
var userDetails = {
name: 'Nelio',
email: 'nelio#angelfire.com'
};
var user = new UserModel(userDetails);
user.fetch({
success: function (user) {
console.log(user.toJSON());
}
});
});
Here is the jsfiddle:
http://jsfiddle.net/20qbco46/
I want the JSON response to be put in the Model that I defined. How is
that done?
If you are trying to render the data from you model, you will use a view for this:
First, create a view to render your data:
// Create a new view class which will render you model
var BookView = Backbone.View.extend({
// Use underscores templating
template: _.template('<strong><%= title %></strong> - <%= author %>'),
initialize: function() {
// Render the view on initialization
this.render();
// Update the view when the model is changed
this.listenTo(this.model, "change", this.render);
},
render: function() {
// Render your model data using your template
this.$el.html(this.template(this.model.toJSON()));
return this;
}
});
See also: template and toJSON as well as $el
Next, create a Model:
// Create a model class
var Book = Backbone.Model.extend({
urlRoot: '/echo/json/',
defaults: {
title : '',
author: ''
},
});
Your model will hold the data fetched from the url / urlRoot
You can use set if you are trying to add new attributes to your model.
You can use get to grab attributes from your model.
See also - save and destroy.
Then, instantiate your model:
// Some dummy data
var instance = {
title: 'learn Backbone JS',
author: 'Bobby Longsocks',
};
// Instansite your model
var model = new Book(instance);
And finally, fetch your model data and create a new instance of you view:
// Fetch your model
model.fetch({
success: function(book) {
// Instansite your view, passing in your model
var view = new BookView({model: book, el: $('body')});
}
});
Here is an Example you can fiddle with.
And some further reading: Annotated Source

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.

Backbone - json data not displayed in browser but rendering in console

I am able to see the json data in console, but not displayed in the html. I am not sure what change must be done to make it render in the browser.
Here is my code.
Model.js
var agent = Backbone.Model.extend({
});
var agentList = Backbone.Collection.extend({
model: agent,
url: 'data/agents.json',
});
View.js
var agentListView = Backbone.View.extend({
el: '.container',
initialize: function() {
this.template = _.template( tpl.get('agentList'));
},
render: function() {
var agents = new agentList();
agents.fetch({
success: function(agents) {
console.log(agents.toJSON());
}
});
this.$el.html(this.template({ AgentsList: agents.toJSON()}))
},
});
HTML
<% _.each(AgentsList, function(item) { %>
<tr>
<td>data</td>
<td><%= item.name%></td>
<td><%= item.gender%></td>
<td><%= item.birthYear%></td>
<td><%= item.skills%></td>
</tr>
<% }); %>
The problem is that you don't render the view in the callback, and therefore you won't have anything to show.
Besides, getting the list of agents inside the render function is definitely not something to do if you want to respect MVC principles. You should have something like:
var agentCol = new AgentList();
var agentView = new AgentListView({collection: agentCol});
agentCol.fetch({
success: function() {
agentView.render();
}
});
and your AgentListView should look like
var AgentListView = Backbone.View.extend({
el: '.container',
initialize: function() {
this.template = _.template(tpl.get('agentList'));
},
render: function() {
this.$el.html(this.template({ agents: this.collection.toJSON()}));
},
});
(I took the liberty to rename some variables to match naming conventions)
Its maybe because the time when the $el update code runs the agents collection is not loaded (fetched) yet.
May be you can update your render method with the code below, so that the $el shall be updated only when the collection fetch is returned from the server.
render: function() {
var $this = this;
var agents = new agentList();
agents.fetch({
success: function(agents) {
console.log(agents.toJSON());
$this.$el.html($this.template({ AgentsList: agents.toJSON() }));
}
});
}
Or an an alternative you can listen to the collection event (reset maybe) which fires whenever the data is fetched from the remote data source - json file in this case.
In that case the view code could be,
var agentListView = Backbone.View.extend({
el: '.container',
initialize: function() {
this.template = _.template( tpl.get('agentList'));
this.collection = new agentList();
this.listenTo(this.collection, "reset", this.addAgentsToDom);
},
render: function() {
this.collection.fetch({
success: function(agents) {
console.log(agents.toJSON());
}
});
},
addAgentsToDom: function(collection, options) { // please name the method whatever you want :)
this.$el.html(this.template({ AgentsList: this.collection.toJSON() }));
}
});

Accessing model data from a view with backbone.js

I have the following code but am struggling to get my view to render the template instead of my model. It all works fine if I render the handlebars template through my model but would like to separate my code into the view.
var DataModel = Backbone.Model.extend({
initialize: function () {
$.getJSON('js/data.json',function(data){
$('.one-wrapper').append(Handlebars.compile($('#one-template').html())(data));
$('.one-asset-loader').fadeOut('slow');
});
},
defaults : function () {
},
});
var StructureView = Backbone.View.extend ({
initialize: function () {
}
});
var structureView = new StructureView({model: new DataModel()});
You can access the model inside the view using this.model.
Your code should look something like:
var StructureView = Backbone.View.extend ({
initialize: function () {
_.bindAll(this);
this.render();
this.model.on('change',this.render);
},
render: function() {
$('.one-wrapper').empty().append(Handlebars.compile($('#one-template').html())( this.model.toJSON() ));
}
});
This will work assuming your model actually contains the data. To do this you need to use the model.url and model.fetch() (not $.getJSON)

Pulling JSON subarray items into a template in Backbone

a question fron a total Backbone newbie:
I want to pull items from a JSON subarray and place them in a specific spot on my template. I'm not sure how to target those specific items.
The subarray is represented in the code below: it's the two arrays named images:
(function () {
//JSON object containing gallery content
var galleries = [
{ name: 'Renovations', images: [
'../img/Galleries/01/pic01.jpg',
'../img/Galleries/01/pic02.jpg'
]
},
{ name: 'Kitchens', images: [
'../img/Galleries/01/pic03.jpg',
'../img/Galleries/01/pic04.jpg'
]
}
];
//Gallery Class...this is a Backbone Model
var Gallery = Backbone.Model.extend({
initialize: function(){
console.log('this gallery is up and running');
}
});
//A collection...also a class & the 'C' in MVC in this case
var SingleGallery = Backbone.Collection.extend({
model: Gallery,
parse: function(response){
return response.items;
console.log(response.items);
}
});
//A view...also a class
var GalleryGroup = Backbone.View.extend({
tagName: 'article',
className: 'contact-container',
template: $('#galleryTemplate').html(),
render: function () {
var tmpl = _.template(this.template);
this.$el.html(tmpl(this.model.toJSON()));
return this;
}
});
//Another view...also a class
var GalleryView = Backbone.View.extend({
el: document.getElementById('container'),
initialize: function () {
this.collection = new SingleGallery(galleries);
this.render();
},
render: function () {
var that = this;
_.each(this.collection.models, function (item) {
that.renderGallery(item);
}, this);
},
renderGallery: function (item) {
var galleryView = new GalleryGroup({
model: item
});
this.$el.append(galleryView.render().el);
}
});
var gal1 = new GalleryView();
} ());
My template looks like this so far:
<script id="galleryTemplate" type="text/template">
<p><h1><%= name %></h1>
<div><img src='<%= images %>' /></div></p>
</script>
If I only had one image to load into <%= images %> section, this would be easy, but I would like to construct a well-formatted JSON object and be able to find each individual item in the two 'images' arrays. I want to think that fetch() is the way to go but I'm not sure...any ideas?
Thanks in advance.
is
You could use underscore's each method to iterate over the images array along these lines:
<% _.each(images, function (image) { %>
<div><img src='<%= image %>' /></div>
<% }); %>