Display json object dynamically - javascript

I have a json object in collection which I need to show it on the page.
Here is what I did:
I first call the helpers template then in that I fetch the json object from the collection:
I am using coffeescirpt and jade-handlebars, here goes my code in coffeescript:
Template.test.helpers
test: ->
test = Question.find().fetch();
test
In the console when I do Question.find().fetch() the following thing occurs:
QuestionData: Object
question1: "How many kids do I have ?"
question2: "when will i die ?"
question3: "how many wife do i have ?"
question4: "test"
__proto__: Object
_id: "w9mGrv7LYNJpQyCgL"
userid: "ntBgqed5MWDQWY4xt"
specialNote: "Rohan ale"
Now in the jade when I call the template by:
template(name="hello")
.test {{QuestionData}}
I can see only the [object] [object]. To see the question1,question2 I have to do the following:
template(name="hello")
.test {{QuestionData.question1}}, {{QuestionData.question2}}
How can I dynamically show all the questions without doing {{QuestionData.question1}} ...
Thank You in advance !!!

You can dynamically compose field names in a loop.
b = { q1: 'a1', q2: 'a2', q3: 'a3' };
for (x=1;x<=3;x++) { console.log( b[ 'q' + x ] ) }
That being said, there's a lot here that seems a misunderstanding to me. I'd step back and say that you should look into storing one question per mongo document. This gives you the easiest data for meteor to play with. Or, storing multiple questions in an array:
test = {
questions : [
"How many kids do I have ?"
"when will i die ?"
"how many wife do i have ?"
"test" ] ,
userid: "ntBgqed5MWDQWY4xt",
specialNote: "Rohan ale"
}
The problems come when you think how you store the answers, sort the questions, etc. Probably a collection called questions, with a field maybe called sortOrder, a field called tag, etc.
How did you pick up calling templates this way, rather than having them as html files that a router manages for you?

instead of just returning your json object with Questions.find().fetch() you could add another step to put your data into an array like:
test = function() {
var temp = [];
for (item in Questions.find().fetch()) {
temp.push(item);
};
return temp;
};
return test;
(sorry for not writing in coffee script, i'm not aware of the language abstraction)

To answer your question on how to do it, you can do something like this(in JS, sorry, not a coffeeScripter):
Template.Questionnaire.questions = function () {
var questions = [];
_.each(Object.keys(this), function (field) {
if(/^question.+/.test(field)) {
questions.push({ label: field, question: this[field]});
}
});
return questions;
};
And then in a template:
<template name="Questionnaire">
{{#each questions}}
<label>{{label}}</label>
<span>{{question}}</span>
{{/each}}
</template>
Something like that. But I agree with Jim Mack and that you should probably be storing this in an array.

Like as JIm Mack Posted, save your collection in an array
first of all insert your question in an array by doing these in your coffeescript:
x = document.getElementById('question-form')
length = x.length
i = 0
question = []
while i< length
aaa = x.elements[i]
question.push
questions: aaa
i++
then since you are using Jade-handlebars you need register helpers
in your jade file do these
{{#each arrayify myObject}}
{{#each this.name}}
p {{questions}}
{{/each}}
{{/each}}
The arrayify and myObject are the handlebars helpers. Then in your coffeescript
Handlebars.registerHelper "arrayify", (obj) ->
result = []
for temp in obj
userQuestion = temp.question
result.push
name: userQuestion
return result
Template.templatename.myObject = ->
temp = []
for item in Question.find().fetch()
temp.push item
return temp
Hope these will work.

Related

having a hard time displaying a key in a object array

i wanted to print the encircle ones itself in the console but im having a hrd time accessing it. so if i want to access "Vignesh" having a comment of "good" and assuming the result refers to the root of the tree, my code will be
console.log(result["Vignesh"]["comments"][0]["A"]);
how do i access the key of the comment? the "A" , "B" and "C"? because ill put it in a for loop so that it will display all his/her comments.
initial code for displaying a name("Gokul", "kavin" etc) with all his comments.
for(var key in result){ //key returns Gokul, Kavin etc
for(var key2 in result[key].comments){ //key2 returns exm 0 1 2 in comments
console.log(result[key]["comments"][key2]["A"].....);
}
}
This will work:
for(var key in result){ //key returns Gokul, Kavin etc
for(var key2 in result[key].comments){ //key2 returns exm 0 1 2 in comments
var comment = result[key]["comments"][key2];
console.log(comment[Object.keys(comments)[0]]);
}
}
BTW, it's preferable for readability to use dot notation instead of square brackets where possible. So result[key].comments instead of result[key]["comments"].
The key to get the property names of an object is to use Object.keys(). If you have control of the backend I do suggest remodeling the comments structure to a more readable format like comments: [{name: 'A' , text: 'good'}]. With that been said, here is how you can use Object.keys() to get the info you are looking for with current data model:
var result = {
Vignesh: {
avgrating: 2.33,
comments: [
{A: "good"},
{B: "Bad"},
{B: "so good"},
]
}
}
for (var topLevelUser in result){
if (result.hasOwnProperty(topLevelUser) && result[topLevelUser].comments){
console.log(topLevelUser);
var comments = result[topLevelUser].comments;
comments.forEach(function(comment){
var subUser = Object.keys(comment)[0];
var text = comment[subUser];
console.log(subUser, '=>', text)
});
}
}
Do it like this:
result["Vignesh"]["comments"][0].forEach(function(value,key){console.log('Comment '+key+': '+value+'; ')});

angularjs: resolve value from key pair

Is there any easy way to find a key in array and return its value instead of the key with angularjs (maybe by using expressions)?
right now, i do something like this:
vm.topics = [{id:1,value:"a"} , {id:2,value:"b"} , {id:3,value:"c"}];
vm.tickets= [{topic:2,summary:"summary 1"} , {topic:1,summary:"summary 2"}];
vm.getTopicName = function (id) {
for (int t=0 ; t<vm.topics.length ; t++)
if (vm.topics[t].id == id)
return vm.topics[t].value;
return id;
};
and in html part:
<tr data-ng-repeat="item in vm.tickets">
<td>{{vm.getTopicName(item.topic)}}</td>
<td>{{item.summary}}</td>
</tr>
Is there anything like
<td>{{item.topic | id as value in vm.topics}}</td>
Funny example, but i think it shows the point.
--- UPDATE ---
as #jantimon mentioned in comments, one way would be to change list to an object of real key pairs and simplify everything:
vm.topics1 = {};
for (var i=0; i < vm.topics.length; i++) {
var t = vm.topics[i];
vm.topics1[t.id] = t.value;
}
and HTML simply changes to:
<td>{{vm.topics1(item.topic)}}</td>
Actually you use two different arrays and from your comment (ajax call) I would create new array in Service that merges topics and tickets, something like:
[... ,
{
topic:2,
summary:"summary 1",
ticket_value: "b"
},
... ]
So controller should only draw it (without additional logic). This way will reduce watchers from your ng-repeat loop and you don't need to call (rebuild) getTopicName()
This is a right way I think,
To simplify your example, if you use Underscorejs library, you can write:
<td>{{topics[_.findIndex(topics, {id: item.topic})].value}}</td>
Demo in Fiddle
HTML
<div data-ng-repeat="item in tickets">
<td>{{topics[_.findIndex(topics, {id: item.topic})].value}} </td>
</div>
JS
$scope._ = _;
$scope.topics = [{id:1,value:"a"} , {id:2,value:"b"} , {id:3,value:"c"}];
$scope.tickets = [{topic:2,summary:"summary 1"} , {topic:1,summary:"summary 2"}];
**As a side note, try to avoid calling methods from HTML like:
<td>{{vm.getTopicName(item.topic)}}</td>

Create an Angularjs Filter with two file json

I'm new with angular and I have a problem with a filter.
I have two different file json like this:
[
{
"IdPers": "1067",
"CognNome": "JANE SMITH",
"Sex": "F"
},
{
"IdPers": "1093",
"CognNome": "JOHN SMITH",
"Sex": "M"
}
]
and:
[
{
"IdPers": "1067",
"DescRuol": "Membro"
},
{
"IdPers": "163",
"DescRuol": "Membro"
}
]
I Put a working Plunker: http://plnkr.co/edit/1xkyxRallRGtj83fSteg?p=preview
I have to create a filter with the field "DescRuol" which is in the file "OutCommissioni.json", the two file have the same field "id". I thought that I can do like a join but I can't make something that works! Thanks for any help
For future readers, please ignore my other answer - I mis-understood the question and worked out the details with OP in the comments there.
To have a select box with multiple options using the same value, first thing is to not use the id as the direct value that the select box will use - instead reference the object directly:
<select data-ng-options="item as item.DescRuol for item in OutCommissioni" id="DescRuol" data-ng-model="filter.IdPers" class="form-control input-sm"></select>
"item as item.DescRuol" will use the object itself as the model value, rather than just the id value.
Next, rather than using the "filter" object directly in the filter, provide a new object which contains the values you need from your filter object:
<tr data-ng-repeat="Person in OutAnagrafica|filter:{Sex:filter.Sex,IdPers:filter.IdPers.IdPers}">
Working example here: http://plnkr.co/edit/gMvuNny99b8aV66C8GAw?p=preview
Edit: ignore this answer - I misunderstood the question. New answer submitted with final details after I worked out what OP really wanted in the comments of this answer.
After fetching data from each file, normalize the difference in properties by assigning the relevant differing field to a common property, and append both sets of data to a single array.
var App = angular.module('App', []);
App.controller("OutAnCtrl", function ($http, $scope) {
$scope.data = [];
$http.get('OutAnagrafica.json')
.success(function (data) {
data.forEach(function(item) {
item.name = item.CognNome;
});
$scope.data.push.apply($scope.data, data);
});
$http.get('OutCommissioni.json')
.success(function (data) {
data.forEach(function(item) {
item.name = item.DescRuol;
});
$scope.data.push.apply($scope.data, data);
});
$scope.clearBox = function () {
$scope.filter = "";
};
});
Then finally change your repeater to use the merged data object "data" and the common property name.
<tr data-ng-repeat="Person in data|filter:filter">
<td>{{Person.IdPers}}</td>
<td>{{Person.name}}</td>
<td>{{Person.Sex}}</td>
</tr>
updated example: http://plnkr.co/edit/03rwNY7eLX9i9VCTHz7Z?p=preview
Edit: I probably mis-understood and you probably don't need those properties merged. The key part is just to append both arrays to a single array using Array.push.apply
// Create initial array
$scope.data = [];
// Append some arrays
$scope.data.push.apply($scope.data, [1,2,3]);
$scope.data.push.apply($scope.data, [4,5,6]);
// $scope.data will now contain [1,2,3,4,5,6]
Edit: I think this is what you're looking for?
http://plnkr.co/edit/jvyXlpv2iBh2n4pZ1miv?p=preview
<label for="DescRuol">DescRuol:</label>
<select data-ng-options="item.IdPers as item.DescRuol for item in OutCommissioni" id="DescRuol" data-ng-model="filter.IdPers" class="form-control input-sm"></select>

Passing array from node.js/express to jade template

Not sure what I'm doing wrong here..
questions.js
questions = [];
questions.AA = 'First'
questions.BB = 'Second'
questions.CC = 'Third'
res.render('questions', { title: questions[CC], questions: questions });
questions.jade
extends layout
block content
h1= title
p #{questions.CC}
each question in questions
p= question
Rendered
<body>
<h1>Third</h1>
<p>Third</p>
</body>
So
each question in questions
p= question
Doesn't seem to be working as I would expect. What am I missing?
You created an array and then stored values into alphabetic indices rather than integer indices. As such, each will not loop over them. You probably mean to define questions like this:
questions = []
questions[0] = 'First'
questions[1] = 'Second'
questions[2] = 'Third'
Or, more idiomatically:
questions = [
'First',
'Second',
'Third'
]
You’ll have to figure something out to replace how you were getting the title, but this should fix the loop.

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!

Categories