handlebars - how to access first element of child array? - javascript

I have an data object, which contains an array within an array, I want to loop over the parent array and read out the first object of each child array.
In the example I want to read out: {"id":1}, {"id":9}, {"id":11}
var object =
{ parts: [ [{"id":1},{"id":2},{"id":3}], [{"id":9},...], [{"id":11},... ] ] }
so far I have a for each loop:
{{#each object.parts}} ... {{/each}}

In order to get the first element, you would need:
{{#each object.parts}}
{{this.[0]}}
{{/each}}
but this would just print [object object].
The second requirement - viewing it as JSON - requires a helper in your JS:
Handlebars.registerHelper('json', function(context) {
return JSON.stringify(context);
});
and then:
{{#each object.parts}}
{{json this.[0]}}
{{/each}}

Related

jQuery object from html table into two one-dimensional arrays for Chartist chart

This may be so simple that you may find it silly, but I'm stumped. I'm fiddling around with some jQuery code that should extract data from a 2-column HTML table and then spit out two one-dimensional arrays. E.g. ['sample 1','sample 2', 'sample 3'...] for the bar tags, and e.g [645, 872, 423...] for the bar values in a Chartist chart.
EDIT: I later discovered that the "series" array should be bi-dimensional to permit more datasets to be presented in the same chart. If using only one "series" dataset, put brackets around it to turn it into an array within an array.
I've managed to get the HTML table values into a jQuery object like this:
var tdata = [];
var headers = [];
$('#myTable th').each(function(index, item) {
headers[index] = $(item).html();
});
$('#myTable tr').has('td').each(function() {
var tdataItem = {};
$('td', $(this)).each(function(index, item) {
tdataItem[headers[index]] = $(item).html();
});
tdata.push(tdataItem);
});
...where myTable is a HTML table like:
<table id="myTable">
<tbody><tr>
<th>Oxide</th>
<th>Proportion</th>
</tr>
<tr>
<td>Ca0</td>
<td>0.73</td>
</tr>
<tr>
<td>Li2O</td>
<td>0</td>
</tr>
<tr>
<td>MgO</td>
<td>0.13</td>
</tr>
</tbody></table>
The problem is that I can't get the first column (under "Oxides") and the second column values (under "Proportion") into their own one-dimensional array to feed into Chartist, which basically needs this:
var data = {
labels: ['CaO', 'Li2O', 'MgO'],
series: [0.73, 0, 0.13]
]
};
I made a JSfiddle where you can see the output of the array through console.log(tdata);
[Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object]
0:
Object
Oxide:
"Ca0"
Proportion:
"0.73"
__proto__:
Object
It seems that somehow these objects are multidimensional or there's some jQuery funkiness going on, because I haven't managed to extract the one-dimensional "labels" and "series" arrays for Chartist. It should be dead simple, though?
It looks like you may have the data backwards. You are storing an array of objects, versus an object with 2 arrays.
I update the fiddle with an example that creates the "data" object you would use for Chartist.
https://jsfiddle.net/t539uuok/1/
var data = {
labels: [],
series: []
};
$("#myTable tr").has("td").each(function () {
data.labels.push($(this).find("td:first").html());
data.series.push($(this).find("td:last").html());
});
If you need it to be dynamic, there would need to be other changes. But, this would work if you are only looking to capture 1-dimensional label/series data.

How to generate the code in loop

I need to generate code from some array,the code should be generate according to the array value
for example,
alert("sofia")
alert("Miley")
alert("lindzy")
...
I've created for that array with the following structure
var customerList = {
cusomer: []
};
and in the customer array there is name:value like name:sofia,name:Miley ....
The template look like
{{#each customerList.customer}}
alert( {{name}} );
{{/each}}
And this is generate the Html with {object,objet},what am I missing here?
The array look like
Try this:
customerList['cusomer'].forEach(function(e){
alert(e.name)
});

Meteor and handlebars #each to iterate over object

I want to use handlebars #each with an object that's not an array.
How do I do that? I need it to still work with meteor's special features with #each.
My object is in the form of:
{
john: "hello",
bob: "hi there"
}
I'm trying to get an output like this:
<div>hello</div>
<div>hi there</div>
You need to use a helper in your js to help handlebars understand your object:
Add to your client js
Template.registerHelper('arrayify',function(obj){
var result = [];
for (var key in obj) result.push({name:key,value:obj[key]});
return result;
});
And use (you can also use the key with {{name}}) in your html:
{{#each arrayify myobject}}
<div title="hover here {{name}}">{{value}}</div>
{{/each}}
myobject comes from your template:
Template.templatename.helpers({
myobject : function() {
return { john:"hello", bob: "hi there" }
}
});
You can convert your object into array with underscore _.map
html:
<template name="test">
{{#each person}}
<div>{{greeting}}</div>
{{/each}}
</template>
js:
Template.test.helpers({
person : function () {
return _.map(object, function(val,key){return {name: key, greeting: val}});
}
});
It should be noted for people finding this now that the correct way to declare Handlebars helpers in Meteor as of this writing is with the UI.registerHelper method as opposed to Handlebars.registerHelper. So the above helper should look like this now:
UI.registerHelper("arrayify", function(obj){
result = [];
for (var key in obj){
result.push({name:key,value:obj[key]});
}
return result;
});

Access Array via Index

I tried figuring this out by reading both how the Tags are handled in the Todo-List Example and how the RSVPS are handled in the Parties example, but I could not figure out a general way to achieve my Goal.
I have a Plan Collection which has a name ownerid and excerciselist
Plans.insert({name: names[i], ownerId: 1, excerciselist: excercises});
Now in this Excerciselist, I want to add an undefined Amout of Excercises by ID.
I have an Excercisecollection with the following:
Excercises.insert({name: names[i], muscle: muscles[i], device: devices[i], description: descriptions[i]});
Now all these Excercises have a unique _id element by default.
Adding things to the excerciselist no Problem I can do that by Push.
But what I can not figure out is, how I can access only certain ID's in the excerciselist via it's Index.
I can only access the whole Stringarray and output in in HTML via
{{#each planarray}}
{{excerciselist}}
{{/each}}
But there is no possiblity to do smoething like
{{ excerciselist }}
I have also tried returning only excerciselist to the planarray, but the problem is that because it is only indexed and not mapped it can not be accessed by the LiveHTML.
Does anyone have an Idea how this problem could be solved?
Why don't you add a field for the unique id to the Excersies insert?
Excercises.insert({ uniqueID: [i], name: names[i], muscle: muscles[i], device: devices[i], description: descriptions[i]});
This way you can get just the excercise you want based on the uniqueID-field.
Oh and you should probably call "uniqueID" something that makes more sense.
I found a little Workaround which is not exactly what I had in mind but it gets the job done.
Template.editplan.excercises = function() {
var names = [];
var add = [];
var adder = null;
for(var i = 0; i < this.excerciselist.length; i++)
{
add[i] = [];
adder = Excercises.find({_id: this.excerciselist[i]});
add[i]['_id'] = this.excerciselist[i];
add[i]['location'] = i;
adder.forEach(function (obj) {
add[i]['name'] = obj.name;
});
names.push(add[i]);
}
return names;
};
Basically I made a new Array in which i put the Data I want to have so I can read it in the LiveHTML see example below
{{#each planarray}}
<h1>{{name}}</h1>
{{#each excercises}}
{{name}}
{{/each}}
<select name="selectedexcercise{{_id}}" id="selectedexcercise{{_id}}">
{{> excerciseoption}}
</select>
<input type="button" class="addtoplan" value="Eine Übung hinzfügen">
{{/each}}
But there must be a more efficient or nice way.... At least I hope so!

Need Handlebars.js to render object data instead of "[Object object]"

I'm using Handlebars templates and JSON data is already represented in [Object object], how do I parse this data outside of the Handlebars? For example, I'm trying to populate a JavaScript variable on the page through a handlebars tag, but this doesn't work.
Any suggestions? Thank you!
EDIT:
To clarify, I'm using ExpressJS w/ Handlebars for templating. In my route, I have this:
var user = {}
user = {'id' : 123, 'name' : 'First Name'}
res.render('index', {user : user});
Then in my index.hbs template, I now have a {{user}} object. I can use {{#each}} to iterate through the object just fine. However, I'm also using Backbonejs and I want to pass this data to a View, such as this:
myView = new myView({
user : {{user}}
});
The problem is that {{user}} simply shows [Object object] in the source. If I put it in console.log I get an error that says 'Unexpected Identifier'.
When outputting {{user}}, Handlebars will first retrieve the user's .toString() value. For plain Objects, the default result of this is the "[object Object]" you're seeing.
To get something more useful, you'll either want to display a specific property of the object:
{{user.id}}
{{user.name}}
Or, you can use/define a helper to format the object differently:
Handlebars.registerHelper('json', function(context) {
return JSON.stringify(context);
});
myView = new myView({
user : {{{json user}}} // note triple brackets to disable HTML encoding
});
You can simple stringify the JSON:
var user = {}
user = {'id' : 123, 'name' : 'First Name'};
// for print
user.stringify = JSON.stringify(user);
Then in template print by:
{{{user.stringify}}};
I'm using server-side templating in node-js, but this may apply client-side as well. I register Jonathan's json helper in node. In my handler, I add context (such as addressBook) via res.locals. Then I can store the context variable client-side as follows:
<script>
{{#if addressBook}}
console.log("addressBook:", {{{json addressBook}}});
window.addressBook = {{{json addressBook}}};
{{/if}}
</script>
Note the triple curlies (as pointed out by Jim Liu).
You are trying to pass templating syntax {{ }} inside a JSON object which is not valid.
You may need to do this instead:
myView = new myView({ user : user });
In the Node Router - Stringify the response object. See below line.
response.render("view", {responseObject:JSON.stringify(object)});
In HTML Script tag - user Template literals (Template strings) and use JSON.parse.
const json= `{{{responseObject}}}`;
const str = JSON.parse(json);
Worked like a charm!
You can render the keys/values of a list or object in a Handlebars template like this:
{{#each the_object}}
{{#key}}: {{this}}
{{/each}}
If you want more control over the output formatting you can write your own helper. This one has a recursive function to traverse nested objects.
Handlebars.registerHelper('objToList', function(context) {
function toList(obj, indent) {
var res=""
for (var k in obj) {
if (obj[k] instanceof Object) {
res=res+k+"\n"+toList(obj[k], (" " + indent)) ;
}
else{
res=res+indent+k+" : "+obj[k]+"\n";
}
}
return res;
}
return toList(context,"");
});
We used handlebars for email templates and this proved useful for a user like the following
{
"user": {
"id": 123,
"name": "First Name",
"account": {
"bank": "Wells Fargo",
"sort code": " 123-456"
}
}
}
To condense (what I found to be) the most helpful answers...
JSON helper for handlebars (credit):
Handlebars.registerHelper("json", function (context) {
return JSON.stringify(context);
});
JSON helper for express-handlebars (credit and I updated to newest conventions):
app.engine(
"handlebars",
exphbs.engine({
defaultLayout: "main",
helpers: {
json: function (context) {
return JSON.stringify(context);
}
}
})
);
And then on the templating side: {{json example}}
Just improving the answer from #sajjad.
Adding a 'pre' tag will make it look a lot nicer.
<pre>
{{#each the_object}}
{{#key}}: {{this}}
{{/each}}
</pre>

Categories