Unable to output from JSON file - Backbone - javascript

Trying to fetch JSON data when the div is clicked, but not able to see the output. I am using Backbone Collection to pull json data. Tried to output json data to console and also within another div. The content from json file is also listed below.
<div class = "test">Click </div>
<div class = "new_test"> </div>
JS
var myModel = Backbone.Model.extend();
var myCollection = Backbone.Collection.extend({
model: myModel,
url : "myjson.json"
})
var jobs = new myCollection();
var myView = Backbone.View.extend({
el : 'div',
events : {
'click div.test' : 'render'
},
initialize : function(){
jobs.fetch();
},
render : function(){
jobs.each(function(myModel){
var _comp = myModel.get('company');
$('div.new_test').html(_comp);
console.log(_comp)
})
}
})
Json File :
[
{
"company": "Ford",
"Type": "Automobile"
},
{
"company": "Nike",
"Type": "Sports"
}
]

You have to call the render function of your view to see the results. You cannot instantiate a collection object and expect to see results.
Code hasn't been tested.
var myView = Backbone.View.extend({
el : 'div',
events : {
'click div.test' : 'render'
},
initialize : function(){
jobs.fetch();
this.render();
},
render : function(){
jobs.each(function(myModel){
var _comp = myModel.get('company');
$('div.new_test').html(_comp);
console.log(_comp)
})
}
})
var yourView = new myView();

I have the same problem a few weeks ago.
Check path for Your JSON.
For example when You have structure of directories like this:
-js
- collection
collection.js
- json
myjson.json
Backbone collection You set like this:
url: 'js/json/event.json',
Check in Firefox, in Chrome we have a Cross-browser thinking
and check this:
jobs.fetch({
reset: true,
success: function (model, attributes) {
//check here if json is loaded
}
});

Related

How do i pass a received array into underscore template

I am getting a long array from PHP containing various data objects.
[{"commid":"1","uid":"0","pid":"3","comment":"comm","parid":null,"date":"2016-10-27 15:03:10"},
{"commid":"2","uid":"0","pid":"10","comment":"Ana","parid":null,"date":"2016-10-27 15:03:51"},
{"commid":"3","uid":"0","pid":"5","comment":"asss!","parid":null,"date":"2016-10-27 15:05:50"},
{"commid":"4","uid":"0","pid":"10","comment":"Lawl?","parid":null,"date":"2016-10-27 17:03:59"},
{"commid":"5","uid":"0","pid":"14","comment":"sd","parid":null,"date":"2016-11-06 00:25:04"},
{"commid":"6","uid":"0","pid":"14","comment":"sds","parid":null,"date":"2016-11-06 00:25:50"},
{"commid":"7","uid":"0","pid":"14","comment":"WOW!","parid":null,"date":"2016-11-08 15:06:18"},
{"commid":"8","uid":"0","pid":"13","comment":"Hello!?","parid":null,"date":"2016-11-08 15:14:30"}]
My Backbone View which will be rendering the data is
var WorkPage = Backbone.View.extend({
el: $('#indexcontent'),
render: function() {
Backbone.history.navigate('work');
var _this = this;
this.$el.html(workHTML);
$.ajax({
type: "GET",
url: "includes/server_api.php/work",
data: '',
cache: false,
success: function(html) {
console.log(html);
var compiledTemplate = _.template($('#content-box').html(), html);
_this.$el.html(compiledTemplate);
},
error: function(e) {
console.log(e);
}
});
return false;
}
});
My workHTML which will be rendered by Underscore is
<script type="text/template" id="content-box">
<div class="workhead">
<h3 class="msg comment"><%= comment%></h3>
<p class="date"><%= date%></p>
</div>
</script>
<div id="content-box-output"></div>
How do I implement a underscore loop here?
You should take advantage of Backbone's features. And to do that, you need to understand how to use a REST API with Backbone.
Backbone's Model is made to manage a single object and handle the communication with the API (GET, POST, PATCH, PUT requests).
Backbone's Collection role is to handle an array of model, it handles fetching it (GET request that should return a JSON array of objects) and it also parse each object into a Backbone Model by default.
Instead of hard-coding a jQuery ajax call, use a Backbone collection.
var WorkCollection = Backbone.Collection.extend({
url: "includes/server_api.php/work",
});
Then, modularize your views. Make an item view for each object of the array you received.
var WorkItem = Backbone.View.extend({
// only compile the template once
template: _.template($('#content-box').html()),
render: function() {
// this is how you pass data to the template
this.$el.html(this.template(this.model.toJSON()));
return this; // always return this in the render function
}
});
Then your list view looks like this:
var WorkPage = Backbone.View.extend({
initialize: function(options) {
this.itemViews = [];
this.collection = new WorkCollection();
this.listenTo(this.collection, 'reset', this.render);
// this will make a GET request to
// includes/server_api.php/work
// expecting a JSON encoded array of objects
this.collection.fetch({ reset: true });
},
render: function() {
this.$el.empty();
this.removeItems();
this.collection.each(this.renderItem, this);
return this;
},
renderItem: function(model) {
var view = new WorkItem({
model: model
});
this.itemViews.push(view);
this.$el.append(view.render().el);
},
// cleanup to avoid memory leaks
removeItems: function() {
_.invoke(this.itemViews, 'remove');
this.itemViews = [];
}
});
It's unusual to set the url in the render function, you should keep the responsibilities scoped to the right place.
The router could be something like:
var Router = Backbone.Router.extend({
routes: {
'work': 'workPage'
},
workPage: function() {
var page = new WorkPage({
el: $('#indexcontent'),
});
}
});
Then, if you want to see the work page:
var myRouter = new Router();
Backbone.history.start();
myRouter.navigate('#work', { trigger: true });
Templates and RequireJS
My index.html page contains this
indexcontent div but the content-box which contains the template
format which we are compiling is stored in different work.html. So,
if i dont load this work.html in my main index.html i am unable to
access content-box.
I would recommend to use the text require.js plugin and load each template for the view like this:
The work-item.js file:
define([
'underscore', 'backbone',
'text!templates/work-item.html',
], function(_, Backbone, WorkItemTemplate) {
var WorkItem = Backbone.View.extend({
template: _.template(WorkItemTemplate),
/* ...snip... */
});
return WorkItem;
});
The work-page.js file:
define([
'underscore', 'backbone',
'text!templates/work-page.html',
], function(_, Backbone, WorkPageTemplate) {
var WorkPage = Backbone.View.extend({
template: _.template(WorkPageTemplate),
});
return WorkPage;
});
In your index.html file you need to have _.each() method to iterate throught each element
<% _.each(obj, function(elem){ %>
<div class="workhead">
<h3 class="msg comment"><%= elem.comment %></h3>
<p class="date"><%= elem.date%></p>
</div>
<% }) %>
I make variable of your response just to have data to work with. In your View you need to set point on template
template: _.template($("#content-box").html()), and in render method just send data as object.
Here is working code : jsFiddle
Here is one way to load the template for each value in the data array.
var WorkPage = Backbone.View.extend({
el: $('#indexcontent'),
render: function() {
Backbone.history.navigate('work');
var _this = this;
this.$el.html(workHTML);
$.ajax({
type: "GET",
url: "includes/server_api.php/work",
data: '',
cache: false,
success: function(data) {
console.log(data);
var $div = $('<div></div>');
_.each(data, function(val) {
$div.append(_.template($('#content-box').html(), val));
});
_this.$el.html($div.html());
},
error: function(e) {
console.log(e);
}
});
return false;
}
});

Unable to get the Backbone View working for a simple example

I am trying to write a simple example using Backbone.js for study. Some how nothing gets printed in the browser. Need a little help here. The code is given below.
Html:
<div id="container">
<ul id="person-list">
</ul>
</div>
Models
var Person = Backbone.Model.extend({
defaults: {
id: 0,
name: ''
}
});
var PersonStore = Backbone.Collection.extend({
model: Person,
url: 'api/person', //currently not using
initialize: function () {
console.log("Store initialize");
}
});
Views
var PersonView = Backbone.View.extend({
tagName: 'li',
initialize: function () {
_.bindAll(this, "render");
},
render: function () {
$(this.el).append(this.model.name) //model.name shows undefined here
return this;
}
});
var PersonListView = Backbone.View.extend({
el: $('#person-list'),
tagName:'ul',
initialize: function () {
_.bindAll(this, "render");
this.render();
},
render: function () {
self = this;
this.collection.each(function (person) { //name property undefined here on person
var personView = new PersonView({ model: person });
$(self.el).append(personView.render().el);
});
}
});
Sample Run
var persons = new PersonStore([
new Person({id:1, name: "Person 1"}),
new Person({ id: 2, name: "Person 2" }),
]);
new PersonListView({ collection: persons });
The above setup prints nothing(blank) on screen. I have struggled now for some time and need a little help here as to why the two Person's name does not get displayed in the browser.
To make your code work you have to replace
this.$el.append(this.model.name)
with
this.$el.append(this.model.get('name'))
Always use method .get() to access model properties.
Also i highly recommend you use templates for rendering views. This approach let you write .render() implementation once and will be no need to change it if you need visual changes, you can make in template

Using views in backbone.js

I'm currently learning backbone.js and have a little problem. I dont' quite get how the view works.
I have created a model, a collection, and another model that again contains the collection:
Sensor = Backbone.Model.extend({
defaults: {
channel: '',
name: '',
temperature: 0,
tempMin: 0,
tempMax: 0
}
});
SensorList = Backbone.Collection.extend({
model: Sensor
});
Now I created a view, so I am able to render the sensor collection with handlebar.js template:
TemperatureView = Backbone.View.extend({
initialize: function() {
this.render();
},
render: function(eventName) {
var source = $('#sensor-list-template').html();
var template = Handlebars.compile(source);
var html = template(this.collection.toJSON());
this.$el.html(html);
} 
});
Now I want to load some data and render the information. But I don't know how to get the data into my view...I tried this:
$(document).ready(function() {
var temps = new TemperatureRequest();
temps.fetch({
success: function() {
console.log(temps);
var test = temps.get("sensors");
console.log(test);
var tempView = new TemperatureView({
collection: test
});
}
});
});
The data is fetched correctly. I have a collection of sensors. And now I want to pass them to the view so it is getting rendered....but I don't understand how this is done..pls help!
Since you are passing the collection to the view while creating it, you can access the same using this.collection inside your view anywhere.
var tempView = new TemperatureView({
collection: test
});
More over you have added the render function inside your initialize , it automatically calls the render function.Inside the render it fetches the collection and since your template needs only json object you are converting your collection it to json array objects.Templates takes care of appending the values to html.
If you want to add automatic view render to happen whenever the collection removes a model or adds a model into it you can add a listener and callback function to it
initialize : function(){
console.log("initializing view");
this.collection.on('add', this.render, this);
this.collection.on('reset', this.render, this);
this.render();
}
I just got it. Took me a while and I have definitly some reading to do.
There were several problems. First of all I have to overwrite the parse function, so the collection is stored correctly in my model:
TemperatureRequest = Backbone.Model.extend({
urlRoot: '/temperatures',
defaults: {
timestamp: '',
logfile: '',
sensorList: new SensorList()
},
parse: function(response) {
response.sensorList = new SensorList(response.sensors);
return response;
},
success: function(response) {
console.log('success');
}
});
In my view I know add the listen to events as suggested and also fetch the data within the initialize function to get rid of the success callback:
TemperatureView = Backbone.View.extend({
el: '#temperatures',
initialize: function() {
this.listenTo(this.model, 'reset', this.render);
this.listenTo(this.model, 'change', this.render);
this.listenTo(this.model, 'add', this.render);
this.model.fetch();
},
render: function(eventName) {
var list = this.model.get('sensorList');
console.log(list.toJSON());
var source = $('#sensor-list-template').html();
var template = Handlebars.compile(source);
var html = template(list.toJSON());
this.$el.html(html);
this.renderTimestamp();
},
renderTimestamp: function() {
var tsText = $("<p></p>").addClass("text-right");
var timestamp = $("<div></div>").addClass("col-sm-4 col-sm-offset-8").append(tsText);
tsText.text(this.model.get('timestamp'));
$('#timestamp').append(timestamp);
}
});
now I can do this to render the data:
$(document).ready(function() {
var temps = new TemperatureRequest();
var tempsView = new TemperatureView({
model: temps
});
});
Instead of passing the collection to the view I pass the model to it and fetch the data inside of the initialize function.
What I still don't understand is when I have to use "this" and when I have to use _bindAll...

Uncaught ReferenceError: text is not defined

http://jsfiddle.net/3pSg7/
I wonder if someone can help to find what's wrong in this case.
I get "Uncaught ReferenceError: text is not defined" in line 6.
Using template and local .txt files for testing until APIs are available.
Backbone.js model script:
var Letter = Backbone.Model.extend( {
urlRoot: 'data/json/news',
initialize: function() {
},
defaults: {
_type: "",
text: "",
is_read: 0
}
});
var News = Backbone.Collection.extend({
model: Letter,
url: 'data/json/list_news.txt',
initialize: function() {
},
fetchMyNews: function() {
this.fetch({async:false});
}
});
var news = new News();
View script:
var NewsView = Backbone.View.extend({
initialize: function() {
this.isShown = false;
this.render();
this.listenTo(news, "all", this.doListen);
},
doListen: function(eventName){
if(eventName == "change"){
this.render();
}
},
isShown: false,
events: {
},
render: function() {
this.$el.attr("z-index", "1000");
news.fetchMyNews();
var sHtml = JST["news/row"](news.attributes);
$("#news_tbody").html(sHtml);
}
});
a few things in your code.
you are defining a global variable 'news' for your collection. that's not recommend, you can just pass a new collection to your view when you instantiate it :
var NewsView = new NewsView({
collection: new News()
});
and change all your 'news' reference in the view to 'this.collection'
and, I usually don't like async ajax calls. try to change them to callbacks, or just listen to events in your view. oh, and also, try not to fetch data in your render(). your function should only do what they are named for. :)
so in your view:
initialize: function() {
this.isShown = false;
this.listenTo(this.collection, "all", this.doListen);
this.collection.fetch();
},
doListen: function(eventName){
if(eventName == "change" || eventName == 'reset'){
this.render();
}
}
and in your render:
var sHtml = JST["news/row"](new.attributes);
$("#news_tbody").html(sHtml);
you are calling news.attributes, news is a collection here..."attributes" doesn't give you anything. I'm not sure what your template looks like, but you may be calling '.text' in your template, which is giving your this error here since news.attributes is undefined.

ember.js <select> populated and selected by two different objects

I'm new to ember, so maybe I'm doing this wrong.
I'm trying to create a select dropdown, populated with three values supplied from an external datasource. I'd also like to have the correct value in the list selected based on the value stored in a different model.
Most of the examples I've seen deal with a staticly defined dropdown. So far what I have is:
{{#view contentBinding="App.formValues.propertyType" valueBinding="App.property.content.propertyType" tagName="select"}}
{{#each content}}
<option {{bindAttr value="value"}}>{{label}}</option>
{{/each}}
{{/view}}
And in my module:
App.formValues = {};
App.formValues.propertyType = Ember.ArrayProxy.create({
content: [
Ember.Object.create({"label":"App","value":"app", "selected": true}),
Ember.Object.create({"label":"Website","value":"website", "selected": false}),
Ember.Object.create({"label":"Mobile","value":"mobile", "selected": false})
]
});
And finally my object:
App.Property = Ember.Object.extend({
propertyType: "app"
});
App.property = Ember.Object.create({
content: App.Property.create(),
load: function(id) {
...here be AJAX
}
});
The dropdown will populate, but it's selected state won't reflect value of the App.property. I know I'm missing some pieces, and I need someone to just tell me what direction I should go in.
The answer was in using .observes() on the formValues. For some reason .property() would toss an error but .observes() wouldn't.
I've posted the full AJAX solution here for reference and will update it with any further developments.
App.formValues = {};
App.formValues.propertyType = Ember.ArrayProxy.create({
content: [],
load: function() {
var that = this;
$.ajax({
url: "/api/form/propertytype",
dataType: "json",
success: function(data) {
that.set("content", []);
_.each(data, function(item) {
var optionValue = Ember.Object.create(item);
optionValue.set("selected", false);
that.pushObject(optionValue);
});
that.update();
}
});
},
update: function() {
var content = this.get("content");
content.forEach(function(item) {
item.set("selected", (item.get("value") == App.property.content.propertyType));
});
}.observes("App.property.content.propertyType")
});
App.formValues.propertyType.load();

Categories