Pulling JSON subarray items into a template in Backbone - json

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>
<% }); %>

Related

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() }));
}
});

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;
});

Fetching directory contents to json in backbone

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)

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)

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);
}
});