Mustache templating - presenting JSON collection - javascript

I am attempting to present a JSON collection, which is retrieved asynchronously and using FireBug I can see this ultimately looks like:
[{"Id":"00000010"},{"Id":"00000002"},{"Id":"00000003"}]
This does not work, but if I declare a collection as:
[{ "Id": "00000004" }, { "Id": "00000005" }, { "Id": "00000006"}]
This works, and then using FireBug I can see this is slightly different:
[Object { Id="00000004"}, Object { Id="00000005"}, Object { Id="00000006"}]
Why does it make a difference when retrieving the data synchronously and declaring a collection? What are my options for getting this to work.
Thanks.
UPDATE
I am also using sammy.js, here is the JavaScript:
var app = $.sammy('div[role="main"]', function () {
this.use('Mustache', 'html');
this.get('#/', function (context) {
this.load('/data')
.then(function (response) {
context.blah = 'blah';
context.data = response;
var data2 = [{ "Id": "00000004" }, { "Id": "00000005" }, { "Id": "00000006"}];
context.data2 = data2;
var templateUrl = '#Url.Content("~/Templates/template.html")';
context.partial(templateUrl);
});
});
});
$(function () {
app.run('#/');
});
Here is the template:
<h1>{{blah}}</h1>
<ul>
{{#data}}
<li>{{Id}}</li>
{{/data}}
</ul>
<ul>
{{#data2}}
<li>{{Id}}</li>
{{/data2}}
</ul>

Okay, I figured this one out!
context.data = response;
becomes
context.data = JSON.parse(response);

Related

How to create complex javascript object for JSON API

Below is the structure of JSON which I use to query an API
"order_items": [
{
"menu_item_id": "VD1PIEBIIG",
"menu_item_name": "Create Your Own",
"modifiers": [
{
"modifier_id": "6HEK9TXSBQ",
"modifier_name": "Shrimp"
}
],
"quantity": "1",
"total": 15.99,
"variant_id": "TXDOR7S83E",
"variant_name": "X-Lg 18\""
}
]
Now I want to call this API from an HTML page using Javascript(Using HTML elements like forms and drop down menus etc). I want to create a Javascript object with proper structure and then convert it to JSON using "stringify" function. But I am not able to create the Javascript object. Can anyone help with this?
Like i want to have the following structure
obj.order_items[0].menu_item_id="VD1PIEBIIG";
obj.order_items[0].menu_item_name="Create Your Own";
obj.order_items[0].modifiers[0].modifier_id="6HEK9TXSBQ";
and so on.
var jsonToSend = { "order_items": [ ] };
// then for each order item
var orderItem = { "menu_item_id": <whatever>,
"menu_item_name": <whatever>,
"quantity": <whatever>,
"total": <whatever>,
"variant_id": <whatever>,
"variant_name": <whatever>,
"modifiers": []
};
// then for each modifier
var modifier = { "modifier_id": <whatever>, "modifier_name": <whatever> };
orderItem.modifiers.push(modifier);
jsonToSend.order_items.push(orderItem);
JSON.stringify(jsonToSend);
Well there are a couple of ways to do this.
Manually create the Json object to send from the HTML elements:
$.ajax({
type: "POST",
url: "some.php",
data: new {"order_items": [
{
"total": $('total').Val(),
"variant_id": $('variant_id').Val(),
"variant_name": $('variant_name').Val()
}
]})
.done(function( msg ) {
alert( "Data Saved: " + msg );
});
You could use a great framework like KnockoutJs, this will keep your JSON object up to date with your form, so that you don't have to do it manually. When you are ready you just submit your original json back to the server.
See this basic example on JsFiddle
var ClickCounterViewModel = function() {
this.numberOfClicks = ko.observable(0);
this.registerClick = function() {
this.numberOfClicks(this.numberOfClicks() + 1);
};
this.resetClicks = function() {
this.numberOfClicks(0);
};
this.hasClickedTooManyTimes = ko.computed(function() {
return this.numberOfClicks() >= 3;
}, this);
};
ko.applyBindings(new ClickCounterViewModel());
You can use any number of plugins to Serialize the form, but the problem is getting the JSON structure just right.
See SerializeArray
$( "form" ).submit(function( event ) {
console.log( $( this ).serializeArray() );
event.preventDefault();
});

Update nested JSON with knockout

I'm attempting to alter a JSON in memory by using the knockout.js UI. The problem I'm running into is that when I alter a value in the UI, the JSON data doesn't seem to be changed whatsoever. I've implemented buttons with console.log(config) to test this. Any suggestions would be great, thanks!
http://jsfiddle.net/Hfwfs/1/
edit.js
var config = {
"departments": [
{
"name": "Step Down"
}, {
"name": "ER"
}]
};
var DepartmentViewModel = function (dep) {
var self = this;
self.name = ko.observable(dep.name);
}
function ConfigViewModel() {
var self = this;
self.departments = ko.observableArray([]);
ko.utils.arrayForEach(config.departments, function (dep) {
self.departments.push(new DepartmentViewModel(dep));
});
}
ko.applyBindings(new ConfigViewModel());
It is getting updated, you've to look in the model

Backbone.js collection fetch, can't retrieve items

I'm new to Backbone.js, I'm following a tutorial trying to adapt it to my needs.
I'm calling the fetch method from the main app view in order to retrieve multiple objects to be inserted in the collection.
I can see in chrome that the json data are returned, the fetch functions returns success but the collection is not populated.
I'm using IcanHaz for rendering. It prints out only the default model as I defined it in the Job model.
var Job = Backbone.Model.extend({
defaults: {
title: 'Not specified',
status: 0,
created_at: 'Not specified'
}
});
var JobView = Backbone.View.extend({
render: function () {
// template with ICanHaz.js (ich)
this.el = ich.jobRowTpl(this.model.toJSON());
return this;
}
});
// define the collection of jobs
var JobCollection = Backbone.Collection.extend({
model: Job,
url: '/api/1.0/jobs/'
});
// main app, the collection view
var AppView = Backbone.View.extend({
tagName: 'tbody',
initialize: function() {
this.jobs = new JobCollection();
this.jobs.on('all', this.render, this);
this.jobs.fetch({
error: function () {
console.log("error!!");
},
success: function () {
console.log("no error");
}
}).complete(function () {
console.log('done');
console.log('length1:' + this.jobs.length);
});
console.log('length2: '+ this.jobs.length);
},
render: function () {
this.jobs.each(function (job) {
var tmpjob = new JobView({model: job}).render().el;
$(this.el).append(tmpjob);
console.log('job': + this.tmpjob);
}, this);
return this;
}
});
var app = new AppView();
$('#app').append(app.render().el);
In the Chrome console I get this:
length2:0
job:undefined
no error
done
Uncaught TypeError: Cannot read property 'length' of undefined //referring to the lenght1 logging
These are the data that I fetch, from the chrome inspector under network/xhr/response:
{"count": 2, "next": null, "previous": null, "results": [{"id": 1, "title": "testAlbum", "status": 0, "created_at": "2012-12-31"}, {"id": 2, "title": "testAlbum2", "status": 0, "created_at": "2012-12-31"}]}
I don't understand why the 'jobs' collection exists after calling the fetch method but it is undefined inside the fetch block when the 'success' helper has been called.
And why the collection is not being populated despite it returns success and the json data are returned from the server?
I'm quite lost.
Add a parse method to your collection that just returns the results arrays. A collection needs to be an array of models, not your whole JSON response.
The Backbone docs explain how to use parse.

backbone fetch complicate structure

I have 3 models on backbone:
var Level1Model = Backbone.Model.extend({
defaults: {
level2Collection: null
}
});
var Level2Model = Backbone.Model.extend({
defaults: {
level3Collection: null,
text: null
}
});
var Level3Model = Backbone.Model.extend({
defaults: {
text: null
}
});
I have two REST services (urls):
1. One that gets Level1Model id and returns Level1Model with Level2Model and id's of Level3.
For example:
{
Level2Collection: [
{
text: "aaa",
Level3Collection: [ {id:1}, {id:2}, {id:3} ]
},
{
text: "bbb",
Level3Collection: [ {id:4}, {id:5} ]
}
]
}
2. One that gets Level3Model id and returns Level3Model data.
I am looking a way to fetch all the data structure by doing:
var level1Ins = new Level1Model({id:123});
level1Ins.fetch({
success: function() {
doSomething();
}
});
I am really confused of how to do it. For example, I don't know how can I fill the Level3Collection and also call doSomething() when success loading all elements.
How can I load the entire level1 instance?
You should try Backbone Relational. It makes this kind of thing very easy to work with.

Setting my model with Backbone.js

I'm attempting to use Backbone.js to simplify data (JSON) management and interaction with DOM.
Firstly, I'm not sure if Backbone.js can indeed simplify and improve the current process, but I'd like to assume it can.
Previously I'm retrieving the data with jQuery AJAX function. Now, I'm retrieving the data(still with AJAX) Backbone style into the Backbone model.
For update, previously I was parsing through the JSON object itself to update data. I would then send back the updated json to the back-end (just as I've received it).
Now, is it possible to use the set function in Backbone to simplify something like the below and ideally where should the set attribute behaviour (and all other UI bindings like change events) be constructed? Would it be on the fetch() success handler, which is in the View initializer?
function setBucketOffer(bucketName, newId) {
var segments = json.segments;
for (var i = 0; i < segments.length; i++) {
if (segments[i].market.toLowerCase() === g_market) {
var genders = segments[i].gender;
for (var i = 0; i < genders.length; i++) {
if (genders[i].name.toLowerCase() === g_segment) {
var buckets = genders[i].buckets;
for (var i = 0; i < buckets.length; i++) {
if (buckets[i].name === bucketName) {
buckets[i].confirm = newId;
return;
}
}
}
}
}
}
}
Example JSON
{
"segments": [
{
"market": "Market1",
"gender": [
{
"name": "male",
"buckets": [
{
"name": "Market1_M_CBD",
"subscribers": "50,000",
"postcode": "20000-2010",
"lastsend": "13/03/12 4:30PM",
"suggest": "10054",
"confirm": ""
},
{
"name": "Market1_M_North",
"subscribers": "50,000",
"postcode": "20000-2010",
"lastsend": "13/03/12 4:30PM",
"suggest": "10054",
"confirm": ""
}
]
},
{
"name": "female",
"buckets": [
{
"name": "Market1_F_CBD",
"subscribers": "50,000",
"postcode": "20000-2010",
"lastsend": "13/03/12 4:30PM",
"suggest": "10054",
"confirm": "10054"
}
]
}
]
},
{
"market": "Market2",
"gender": [
{
"name": "male",
"buckets": [
{
"name": "Market2_M_CBD",
"subscribers": "50,000",
"postcode": "20000-2010",
"lastsend": "13/03/12 4:30PM",
"suggest": "10054",
"confirm": "10054"
},
{
"name": "Market2_M_North",
"subscribers": "50,000",
"postcode": "20000-2010",
"lastsend": "13/03/12 4:30PM",
"suggest": "10054",
"confirm": "10054"
},
{
"name": "Market2_M_South",
"subscribers": "50,000",
"postcode": "20000-2010",
"lastsend": "13/03/12 4:30PM",
"suggest": "10054",
"confirm": "10054"
}
]
}
]
}
]
}
Edit 1
From here, I'm trying to make good use of Parse and to get just segments from my JSON:
var Offers = Backbone.Collection.extend({
url: 'URL',
parse: function (response) {
return response.segments;
}
});
Here, I'm getting more than just response.segments. Also not sure if it's right for me to use the render function or fetch success function to populate the DOM. Suppose I have my html template in the DOM... I want to clone it using jQuery clone() and populate the clone using a forEach on segments, and push back all the clones into the html body. Is this workable in backbone, how would you do it? (I'm able to do this without backbone.js, but would like to see how I can improve with backbone.js, and bind all the data on the clones to model changes)
var OfferView = Backbone.View.extend({
initialize: function () {
this.model = new Offers();
this.model.fetch({
success: function (collection, response) {
console.log(response);
}
});
this.model.on('change', this.modelChange);
this.model.on('change', this.render);
this.modelChange = function () {
alert('model changed');
};
},
render: function () {
}
});
Edit 2
I'm up to creating individual views through a forEach but am having trouble inserting these back into the DOM. What am I doing wrong? (Not sure around the return this part)
// DEFINE VIEW
var OfferView = Backbone.View.extend({
initialize: function () {
this.model = new Offers();
this.model.fetch();
this.model.on('change', this.modelChange);
this.model.on('change', this.render);
this.modelChange = function () {
alert('model changed');
};
this.render();
},
render: function () {
var self = this;
this.model.forEach(function (s) {
var view = new OfferMarketView({
id: "container" + s.get('name').toLowerCase().replace(/\s*/g, '')
});
$('#leftCol').append(view.el);
});
return this;
}
});
var OfferMarketView = Backbone.View.extend({
tagName: "div",
className: "marketContainer",
events: {},
render: function() {
}
});
Whenever you call fetch on a model the response is passed through a parse method that can be defined in your model. parse takes one parameter, the ajax response:
parse: function(response) {
}
In that function you can do whatever you want with the data that comes back from your ajax request and eventually return that object. The object returned by the parse method will be set on your model.
For event binding, you'll want to do that in your view. In the initialize method of your view you can do something like:
this.collection.on("change", this.someFunction);
Now, any time something causes that model to trigger its change event someFunction ( also defined in your view ) will run.
EDIT
The sample json you added to the question looks to be pretty normalized. With that data, I'd be fetching it into a collection. If that's the structure you want your models to look like then you don't need to do much parsing.
in you collection file if you create a parse method that does the following:
parse: function(response) {
return response.segments;
}
When you call your fetch, this.collection.fetch() on a successful request, your collection will be filled with models that contain attributes in a structure that matches your response.
EDIT 2
Your binding looks ok.
in this section of code:
this.collection.fetch({
success: function (model, attributes) {
initAll(attributes);
// populate ui with attributes from model
}
})
The parameters that are passed back on a success in a collection fetch are (collection, response) collection is the result of collection call and what this.collection will end up being. response is the response of your ajax request.
I'm not sure what initAll(attributes) is supposed to be doing. If you add a parse method like I posted above, your collection will contain a set of models with the attributes of each segment.
Also, rather than calling this.render() at the end, you could do bind render to the change event:
this.collection.on('change', this.render);
That way any time your collection changes, that view will automatically render again so your changes will show up.

Categories

Resources