Handlebars.js doesn't like square brackets in the front - javascript

I am using PHP-backend, Backbone.js and Handlebars.js. My javascript requests for data, and JSON data is returned successfully (json_encode).
When I give this JSON data to the handlebars template, it is not displaying. I realised the square brackets in front and at the back of my JSON object are 'disliked' by Handlebars.js and not being displayed. Take a look at the code below.
var ArticleListView = Backbone.View.extend(
{
el: $('#main'),
render: function()
{
var template = Handlebars.compile($("#articles_hb").html());
$(this.el).html(template([{"articles":[{"title" : "1"}, {"title" : "2"}]}]));
return this;
}
});
Now, if I take the brackets out, it works fine. What's going on? Why are the square brackets there in the first place? How do I get rid of them?

It's perfectly reasonable to call Handlebars to loop through the output of a collection.
Also an array is not a bad design decision for data handling in views.
Handlebars has a special syntax for dealing with numeric or symbol identifiers, as described here. So, the more correct answer is that Handlebars can access arrays in templates like this:
{{people.attributes.[0]}} // akin to people.attributes[0]
{{people.attributes.[1]}} // akin to people.attributes[1]
Input: mails:[{headers: {subject: ["Hello Darling", "...another"]}}, ...more ]
<ul>
{{#each mails}}
<li>.
{{headers.subject.[0]}}
</li>
{{/each}}
</ul>

Handlebars wants an object for the context as it uses the context as a simple lookup table for template values. So you need to pass an object ({ ... }) to template(), not an array ([ ... ]).
Someone is give you a one element array that contains the context object you need. Either fix the PHP that is producing the JSON to send a JSONified object (associative array in PHP terms) without the array wrapper or strip off the array in the client code with something like this:
$(this.el).html(template(context[0]));
If you have this literal code:
$(this.el).html(template([{"articles":[{"title" : "1"}, {"title" : "2"}]}]));
in your JavaScript file then you have to what is generating that code and fix it. If you do have literal data like that embedded in your Backbone view then you're probably not using Backbone correctly, the data for your template should probably be coming from a Backbone model.
If you're getting that JSON from a Backbone model then I'd guess that you're calling toJSON on a collection (which returns an array) rather than a single model where toJSON should give you a JavaScript object.

Related

Issue formatting a list of dictionaries to be used by javascript

I'm fairly new to Django, and I'm looking for the ideal way to handle data queried from GraphQL and creating HTML elements from the data to display on my website.
I've been generating a list of dictionaries from product information, all of which have "id", "name", "price", etc. and passing them onto my template as is.
On the template I can traverse the list with a for loop and the items correctly display within a p element as {'id': '...', 'title': '...' } However on js what I see is a string containing [{'id':... What's the ideal way to generate a list of dictionaries usable by JS from this string?
Also, declaring a variable with the filter |safe as such:
var products = "{{data|safe}}";
generates an Unexpected Identifier error for some reason.
You can look into using the json_script template tag:
{{ value|json_script:"json-data" }}
This will render into a tag like so:
<script id="json-data" type="application/json">{"key": "value"}</script>
You can use it in javascript by writing:
const value = JSON.parse(document.getElementById('json-data').textContent);
Reference: Django docs- json_script
Another option would be to return a JsonResponse for an ajax request made using javascript.

ICanHaz.js - Possible to use an array of strings in section instead of key/value pairs?

My situation is as follows:
I receive an object from an AJAX call which contains an array of strings (not key/value pairs). It would be amazing if I could just take that array and toss it into the template's data object like the below, and then recursively show each value in the array via the ICanHaz mustache section template syntax. Unfortunately I can not get it to work without key/value pairs to reference inside the section template.
This is a major pain because I have to go into the array returned from AJAX and add key value pairs.
I could not find anything on the mustache or ICanHaz.js documentation dealing with this matter.
Javascript:
var listOfStuff = {
name: 'This is not important',
stuff: data.ajaxreturnedarray || [1, 2, 3, 4] // Just for example.
};
$("#new").append(ich.test(listOfStuff));
HTML
<div id="new">Test</div>
<script type="text/html" id="test">
<div class="panel">
{{#stuff}}<p>{{stuff}}</p>{{/stuff}}
{{^stuff}}<p>No items :(</p>{{/stuff}}
</div>
</script>
Does anyone know a way to make this work?
Update
This is covered in this answer, but it does not mention ICanHaz.js so I cross-reference for anyone googling this problem with ICanHaz.js without mustache.
AFAIK, ICanHaz embeds Mustache, and if it's Mustache you can simply do
{{#stuff}}<p>{{.}}</p>{{/stuff}}

Pass a list of string from Django to Javascript

My Django objects have an attribute "City". I'm trying to get a list of cities and catch it in the template with Jquery (to use in a chart on the X axis).
My problem is that I can't get rid of the unicode and quote for a list.
(I manage to do it for one single value). Instead I'm stucked with this:
["[[u'Paris'], [u'Lyon']]"]
I've tried tons of things, included JSON. No success.
My view:
(actually, one of many try..)
def barchart1(request):
city_array =[]
for i in [1,MyObject.objects.count()]:
objet = get_object_or_404(MyObject, pk=i)
cities = [objet.city.city_name]
city_array.append(cities)
return render (request, 'plot3/plot_page.html', {"city_array" : city_array})
My JS:
<script type="text/javascript">
var cities = ["{{ city_array }}"];
</script>
Here is how JS read the context sent by the view
["[[u'Paris'], [u'Lyon']]"]
Here is what I would like to get
['Paris', 'Lyon']
It MUST be something simple but I just couldn't figure out how to do it.
Others posts don't deal with a list of string.
Any idea of what should I do?
When you do {{ city_array }} in your template, your list is converted to a string. This is done by calling repr() on the list, which recursively calls repr() on its contents. Because your strings are unicode, you see those unicode literals, u'Paris'.
The "correct" way to do this is to encode your data to json, for example in your view:
import json
# ...
json_cities = json.dumps(city_array)
# ...
return render (request, 'plot3/plot_page.html', {"city_array" : json_cities})
and then do
var cities = {{ city_array|safe }};
in the template.
Please note: don't use this for user-controller data! See the XSS Cheat Sheet by OSWASP and the discussion on Django ticket 17419 for further information. To prevent XSS, you could use something like the SafeJSONEncoder from the django-cms project.

What does template.data._id do in Meteor?

Beginner Meteor/JS question:
When associating objects in Meteor I see small line of code that I'm not understanding. For example, post with associated comments.
var $body = $(e.target).find('[name=body]');
var comment = {
body: $body.val(),
postId: template.data._id
};
So get the content of the comment, put it in the variable "comment", and also create a postId to go into this comment so you know what post the comment belongs to. This postId is being called in with *'template.data._id'*
My questions are:
So you call template, then wouldn't you want to call the template name? Not data? Where is data coming from?
That aside, so you call data...and then ._id, are there other options to 'data'? IE
template.data.(option)
This isn't working for me, haha, *console.log(template.data._id);* is coming back undefined. So it's not grabbing the object ID as advertised. I'm sure I messed something up.
Here's the surrounding code if you need more context:
https://github.com/DiscoverMeteor/Microscope/blob/master/client/views/comments/comment_submit.js
Beginning with the easiest first, under your point 3 it should read:
console.log(template.data._id);
As to points 1 and 2, the key idea to note is that your code is being called inside of Template.commentSubmit.events({}). Inside of this object (the "{}"), you are working with an instance of the template in the document, including whatever data is being passed to that instance. In a different template, you will receive different data and hence template.data will consist of different keys and values. You can check out more in the documentation here, http://docs.meteor.com/#template_inst.
So in answer to your question, the reason you can invoke "data" rather than the template name is that the template name has already been provided by Template.commentSubmit. Note that inside of events({}), "this" will generally be equivalent to "template.data." So
console.log(template.data._id);
will generally be equivalent to
console.log(this._id);
The properties you can access on the data will always vary based on the instance received by the template. For example, if template.data consists of {_id: 1, name: "x", location: "y"}, you can retrieve these values by calling the keys, e.g. "template.data.name" or "template.data._id" etc. In your example, you are correct that you are setting postID to template.data._id.
The data arriving to the template comes from your Meteor.subscriptions. Hope this helps.
The template has a data context. When you use an {{#each}} block you are iterating through data, in this case posts.
So using template.data retrieves the data context for the template. It would refer to a post from where the comment form is. So template.data._id is the equivalent of this post._id (where post is the post you're commenting on).
The thing is I think this was removed from meteor. It was there a couple of versions back. I'm not sure about this but that's what I thought. I would have thought the correct code should be this._id. Where this ends up being the data context of the form (which would again be the post).
Could you check if that gives you undefined if you changed it out?
The .events method of a template takes in an event map:
http://docs.meteor.com/#eventmaps
The callbacks for each of the events (in this case 'submit form') can take two arguments. The first one 'e' is the javascript event object and the second one 'template' is the instance of the template where the event occurred. That template instance has a bunch of utility methods/properties (see http://docs.meteor.com/#template_inst) one of which is .data (see http://docs.meteor.com/#template_data). That .data property returns the data that the template was bound to (in your Microscope example it looks like it's bound to a comment object) and that object (in this case) has an _id property.
Note that the 'template' (little T) is not the same as Template (big T).

binding nested json object value to a form field

I am building a dynamic form to edit data in a json object. First, if something like this exists let me know. I would rather not build it but I have searched many times for a tool and have found only tree like structures that require entering quotes. I would be happy to treat all values as strings. This edit functionality is for end users so it needs to be easy an not intimidating.
So far I have code that generates nested tables to represent a json object. For each value I display a form field. I would like to bind the form field to the associated nested json value. If I could store a reference to the json value I would build an array of references to each value in a json object tree. I have not found a way to do that with javascript.
My last resort approach will be to traverse the table after edits are made. I would rather have dynamic updates but a single submit would be better than nothing.
Any ideas?
// the json in files nests only a few levels. Here is the format of a simple case,
{
"researcherid_id":{
"id_key":"researcherid_id",
"description":"Use to retrieve bibliometric data",
"url_template" :[
{
"name": "Author Detail",
"url": "http://www.researcherid.com/rid/${key}"
}
]
}
}
$.get('file.json',make_json_form);
function make_json_form(response) {
dataset = $.secureEvalJSON(response);
// iterate through the object and generate form field for string values.
}
// Then after the form is edited I want to display the raw updated json (then I want to save it but that is for another thread)
// now I iterate through the form and construct the json object
// I would rather have the dataset object var updated on focus out after each edit.
function show_json(form_id){
var r = {};
var el = document.getElementById(form_id);
table_to_json(r,el,null);
$('body').html(formattedJSON(r));
}
A much simpler approach would be to accept a form submission and output the data in JSON format. That way, there is no need to bind variables.
The solution has arrived. JQuery now has plugins for data binding and templates.
http://www.borismoore.com/2010/09/introducing-jquery-templates-1-first.html
http://api.jquery.com/jQuery.template/
http://api.jquery.com/category/plugins/data-link/
There is another simple template engine that loads JSON data directly into the form. See http://plugins.jquery.com/project/loadJSON plugin. It works similar way as the one that Jack placed here but it uses plain HTML for template.
You can see instructions how to use it on the http://code.google.com/p/jquery-load-json/wiki/WorkingWithFormElements and live example on the http://jquery-load-json.googlecode.com/svn/trunk/edit.html?ID=17.

Categories

Resources