In mongodb i have json values like and it is not fixed. Some time it will be only 2 or 3 and sometime it will be very large.
{"_id" : "p83oZAo7fdhNuDD34",
"Active Template Name" : "Windows Mobile",
"ProductId" : "456",
"Subcategory" : "on",
"Size" : "on",
"Material" : "A",
"Price" : "2345",
"Combo Id" : "67u",
"Color" : "red",
"Status" : "Pending"
},
{
"_id" : "p83oZAo7fdhNuDD34",
"Material" : "A",
"Price" : "2345",
"Combo Id" : "67u",
"Color" : "red",
"Status" : "Pending"
}
I want to show all keys like (id, Active Template Name, ProductID .......) as table header and values (p83oZAo7fdhNuDD34,Windows Mobile,456 .......) in tbody.
I am not getting the exact way to perform this in meteor. My collection name is products and Html code is bellow.
<template name="productvalue">
<table>
</table>
</template>
Use a {{#each}} block helper to iterate over your collection products.
<template name="productvalue">
<table>
<thead>
<th>Id</th>
<th>Active Template Name</th>
<th>ProductId</th>
[...]
</thead>
<tbody>
{{#each products}}
<tr>
<td>{{_id}}</td>
<td>{{activeTemplateName}}</td>
<td>{{ProductId}}</td>
[...]
</tr>
{{/each}}
</tbody>
</table>
</template>
You also need to define helpers to rename the problematic keys containing invalid Spacebars characters.
Template.productvalue.helpers({
products: function(){
return Products.find();
},
activeTemplateName: function(){
return this["Active Template Name"];
},
[...]
});
If you want to display a table with all the possible properties in the header, and each row with each column filled or not whether the property is defined or not for the document in that row, then you will need to:
Ahead of time (in onCreated or onRendered), find all possible properties for your dataset, order them, and store them in a "header" object accessible to your helpers. (either in Session or using a reactive variable) Make it reactive if necessary, using this.autorun().
Then, do the same as above, except just returning the stored ordered list for tableHeader
And for rowContent, iterate over your stored header and fill an array with empty strings for each undefined field in the current document
Example:
function getHeader(products) {
var header = {};
for (var key in products) {
for (var property in products[key]) {
header[property] = true;
}
}
return Object.keys(header);
}
Template.productvalue.onRendered(function () {
var products = Products.find().fetch();
Session.set('header', getHeader(products));
this.autorun(function () {
var products = Products.find().fetch();
Session.set('header', getHeader(products));
});
});
Template.productvalue.helpers({
'tableHeader': function () {
return Session.get('header');
},
'rowContent': function (document) {
var row = [];
var header = Session.get('header');
for (var key in header) {
row.push(document[header[key]] || "");
}
return row;
}
});
And in template:
<template name="productvalue">
<table>
<thead>
{{#each tableHeader}}
<th>{{this}}</th>
{{/each}}
</thead>
<tbody>
{{#each products}}
<tr>
{{#each rowContent this}}
<td>{{this}}</td>
{{/each}}
</tr>
{{/each}}
</tbody>
</table>
</template>
I still recommend using a reactive variable instead of Session, but the demonstration is complicated enough as it is.
Related
I am having trouble displaying data much like what is described here, but my object is not conveniently labelled in numbers: How do I iterate over an unknown object in a Meteor Spacebars template?
Data maybe be nested more than once, and might differ but always end in an array.
I am open to new data structures too.
Sample Data:
{
"Category A":
{
"Sub-Category1":
{
"Sub-Sub-Category1": ['Value1', 'Value2']
},
"Sub-Category2":
{
"Sub-Sub-Category2": ['Value3'],
"Sub-Sub-Category3": ['Value4']
}
},
"Category B":
{
"Sub-Category1": ['Value5']
}
}
You're going to need a recursive template to handle arbitrary nesting, a helper that enumerates the keys of an object, and a helper that gets the value of the parent object corresponding to a key.
html:
<template name="nest">
{{#if isArray}}
{{#each this}}
{{this}} <!-- we're assuming that array elements aren't themselves objects -->
{{/each}}
{{#elseif isObject}}
{{#each keys}}
{{#with value}}
{{> nest }}
{{/with}}
{{/each}}
{{else}} <!-- catch the case of a scalar key value (no array) -->
{{this}}
{{/if}}
</template>
js:
Template.nest.helpers({
isArray(){
return typeof(this) === "object" && this.length && this.length > 0;
},
isObject(){
return typeOf(this) === "object" && !this.length;
},
keys(){
return Object.keys(this); // returns an array of strings
},
value(){
return Template.parentData()[this]; // look up the hierarchy to get the parent object then select the data for the current key
}
});
I have a collection with this item:
{
"item1": ["foo", "bar", "baz"],
"item2": ...
}
I made a helper function to repeat a template for each item in item1
Template.temp.helpers({
items: function() {
return Col.find({},{item1:1});
}
});
and this is the template
<template name="temp">
{{#each items}}
{{> anotherTemplate}}
{{/each}}
</template>
But I get back an empty array. Why doesn't it work?
Try with {{#each items.item1}}
Because, Col.find({},{item1:1}) just remove all other field from result.
Limit Fields to Return from a Query
It's like SELECT item1 FROM table in SQL
If you need repeat your template for each item in item1, you need to precise which array should be use.
<template name="temp">
{{#each items.item1}}
{{> anotherTemplate}}
{{/each}}
</template>
Meteor mongo methods are a little different you cannot use.
return Col.find({},{item1:1});
you can use it this way:
return Col.find({},{fields:{'item1':1}});
Maybe you want:
{{#each items}}
{{#each item1}}
{{> anotherTemplate}}
{{/each}}
{{/each}}
Or this:
Template.temp.helpers({
items: function() {
return Col.find({},{item1:1}).map(function(item){
return item.item1
})
}
});
That way items will return the item1 array. Originally it was returning an array of objects with just one element, the item1 arrays of each object:
[{
item1: ["foo","bar","baz"]
},
{
item1: ["lah","nah","jah"]
},
{
item1: ["see","gee","bee"]
}]
this way you'll get an array of arrays: [["foo","bar","baz"], ["lah","nah","jah"], ["see","gee","bee"]]
I think you need to do return something like this from helper
return Col.findOne({}).item1
It should work now
Thanks
I want to check if the field "imageUrl" are inserted from a form into a MongoDb collection.
If it has a value, I want to return the URL, else return false. I'm not used to Mongo, and wonder how I can achieve this. Not every entry have a imageUrl field, but some do. So I need to check if it even exists for every document.
Here's my helper, where I want to have the logic:
Template.CatchesList.helpers({
catches: function () {
return Catches.find({}, {sort: {date: -1}});
},
image: function() {
if (this.imageURL) // Need proper logic here
return true;
else
return false;
}
});
And in my template:
{{#if image}}
<td><img width="100" src="{{imageUrl}}"></td>
{{/if}}
MongoDB has the $exists operator to filter results where the property does not exist in the document. So you can change your query to:
return Catches.find({ "imageUrl": { "$exists": true }}, { "sort": { "date": -1 }});
And then only items that have the property will be returned.
If you are only talking about templates, then a simple conditional test on the field returns logically where it is present or not present:
{{#each catches}}
{{> catch }}
{{/each}}
Then:
<template name="catch">
<tr>
<!-- other fields -->
<td>{{#if imageUrl}}<img width="100" src="{{imageUrl}}">{{/if}}</td>
</tr>
</template>
Where only the logic contained within {{#if}}{{/if}} will actually render.
I did this in an app and it worked for me:
Courses.find({owned_by_contract:user_contract._id}).forEach(function(doc){
var foo = ("your_field_name" in doc) ? doc.course_objective_english.value:"N/A";
}):
Collection 1:
nodeDB : [{
"VARIANTS": [
{"NAME" : Brand},
{"NAME" : Price},
{"NAME" : Colour},
{"NAME" : Size}
]
}]
A form is generated from VARIANTS.The values of this form are to be pushed into New DB called ProductDB
Collection2:
ProductDB [{
{"Brand" : Lee},
{"Price" : 100},
{"Color" : Red},
{"Size" : M}
}]
The values are taken from the user interface.
EDIT
JS File:
Template.dpVar.variant=nodeDB.find({}, { "VARIENTS.NAME": 1, _id : 0 } );
// Wait for a 'submit'
Template.inputDB.events = {
'submit' : function (e, tmpl) {
e.preventDefault();
var NAME= {
NAME: tmpl.find("#NAME").value
};
nodeDB.insert(template_name);
}
}
It seems you are using meteor JS.
You need to perform action onclick of submit button,
<table id="TemplateCreateNewStructure" class=" table table-withborder table-type1">
</table>
Then call ajax and display your data in table then click on submit button, insert your record in new collection like tis way
function createPreviewFormForTemplate(opt){
if VARIANTS.name == 'Brand'
tr = tr='<tr><td>'+VARIANTS.name+'</td><td <input id="dtBoxIN" class="form-control" type="text" placeholder="ENter Brand"/> <div id="dtBox"></div></td></tr>';
$("#TemplateCreateNewStructure").append(tr);
Once you done with all condition then save tables data into a object and that object you need to insert into another collection
you can get your value by using trim method
$("#submit").click(function(){
data = {
"brand": $("#dtBoxIN").val().trim(),
};
you need to send this data object to your backend code
at the backend code you need to run this command
db.collection.insert(data)
When I subscribe to a mongodb collection in the client and publish in the server whilst switch auto-publish off. Do I need to specify each individual find query I am declaring in my helper functions within the publish method? Or is it sufficient to just return Meteor.collection.find() in the Publish statement and that should give access to the entire collection?
Lost? Please see below
In my application I have 2 mongo collections setup. One Called 'Tables' and another called 'Rolls'.
In my client.js file I have two handlebars helper functions:
Template.tables.tableList = function(){
return Tables.find();
}
Template.tableBox.table = function(tableID){
return Rolls.find({"Roll.tableName": tableID}, {sort: {date: -1}, limit:10});
}
to correspond to my templates:
<template name="tables">
<div class="table-area">
{{#each tableList}}
{{> tableBox}}
{{/each}}
</div>
</template>
<template name="tableBox">
<table id="{{name}}" class="table table-condensed">
<tr class="n{{minBet}}">
<th>{{name}}</th>
<th> Min:</th>
<th>{{minBet}}</th>
<th>{{cPlayers}}</th>
</tr>
<tr>
<td>D1</td>
<td>D2</td>
<td>D3</td>
<td>Tot</td>
</tr>
{{#each table name}}
{{> tableRow}}
{{/each}}
</table>
</template>
<template name="tableRow">
<tr class={{rowColor Roll.dice1 Roll.dice2 Roll.dice3 Roll.total}} "bold">
<td>{{Roll.dice1}}</td>
<td>{{Roll.dice2}}</td>
<td>{{Roll.dice3}}</td>
<td>{{Roll.total}}</td>
</tr>
</template>
The first helper function returns all the Tables in the collection.
The 2nd returns the last 10 Rolls in descending order.
Using autopublish - everything works fine. My page shows all the tables and within each table the last 10 dicerolls.
When I switch autopublish off and try and setup corresponding subscribe/publish statements. It doesn't work. Only the Tables are shown - but the data from the Rolls collection is not populating my template.
Corresponding Subscribe and Publish Code:
In client.js:
Meteor.subscribe('tables');
Meteor.subscribe('rolls');
In server/publications.js:
Meteor.publish('tables', function() {
return Tables.find();
});
Meteor.publish('rolls', function() {
return Rolls.find();
});
My assumption is that it is to do with my slightly complicated query in my handlebars helper function for the rolls table? Is it not a simple subscribe to the whole collection (i.e. publish the return of Rolls.find()) and then be able to access all mongo query subsets that I define within my client? Is there something I'm missing here? Thanks for any help.
This seems like it is due to Rolls collection not being fully loaded on the client yet at the time you query for it. You can try something like:
Template.tables.tableList = function(){
return Tables.find();
}
Template.tableBox.table = function(tableID){
Deps.autorun(function () {
return Rolls.find({"Roll.tableName": tableID}, {sort: {date: -1}, limit:10});
});
}
The Deps.autorun(func) block runs the encapsulated function whenever the reactive dependencies change.