I'm fairly new to meteor and I'm trying to iterate over a cursor using #each to populate a table. Here's my code:
<template name="choral">
<div class="container" style="padding-top: 25px">
<div class="table-responsive">
<form id="orderForm">
<table class="table table-borderless table-dark">
<thead class="thead-light">
<tr>
<th>Title:</th>
<th>See the Music:</th>
<th>Hear the Music:</th>
<th>Format:</th>
<th>Price (per copy):</th>
<th>Quantity:</th>
</tr>
</thead>
<tbody>
{{#each piece in pieces}}
<tr>
<td id="name">{{piece.name}}</td>
<td id="pdf">PDF</td>
<td id="audio">AUDIO</td>
<td id="format">FORMAT</td>
<td id="price">{{piece.score}}</td>
<td id="qty"><input type ="number" name ="quantity" min="5"></td>
</tr>
{{/each}}
</tbody>
<tfoot>
<tr>
<td colspan="5"></td>
<td><button class="button" type ="submit">Add to Cart</button></td>
</tr>
</tfoot>
</table>
</form>
</div>
</div>
my js.
Template.choral.helpers({
pieces: function(){
return choralm.find({});
}
});
I'm outputting a blank row between the #each tag. I publish the collection server side and subscribe. I'm just not sure where to look. Any ideas?
My publishment and subscription:
Meteor.publish('choralList', function() {
return choralm.find();
});
Template.choral.onCreated( function(){
Meteor.subscribe('choralList');
});
As far as I can see you are subscribing to your data but you are not "telling" your template, that the subscription is finished and it should redraw.
Therefore your template immediately renders while the subscription is ongoing and thus uses the yet empty collection data.
In order to inform your template that data has been updated you can use it's internal Tracker and store the information in a reactive data-source (for my example I use ReactiveDict instead of ReactiveVar).
import { ReactiveDict } from 'meteor/reactive-dict';
Template.choral.onCreated( function (){
// inside onCreated, this refers to the
// current template instance
const instance = this;
// let's attach a ReactiveDict to the instance
instance.state = new ReactiveDict();
// use the internal Tracker
instance.autorun(() => {
// subscribe and store a flag, once ready
const choralListSub = Meteor.subscribe('choralList');
if (choralListSub.ready()) {
instance.state.set('subscriptionComplete', true);
}
});
});
Next you add a helper, that returns the reactive value for 'subscriptionComplete':
Template.choral.helpers({
pieces(){
return choralm.find({});
},
subscriptionComplete() {
// we use 'state', our ReactiveDict,
// which we added as prop in onCreated
return Template.instance().state.get('subscriptionComplete');
}
});
And finally we let our template draw the data, once our subscription is complete. Until the subscription is complete (note the {{else}} block), we display a message about the loading status:
<template name="choral">
<div class="container" style="padding-top: 25px">
{{#if subscriptionComplete}}
<div class="table-responsive">
<form id="orderForm">
<table class="table table-borderless table-dark">
<thead class="thead-light">
<tr>
<th>Title:</th>
<th>See the Music:</th>
<th>Hear the Music:</th>
<th>Format:</th>
<th>Price (per copy):</th>
<th>Quantity:</th>
</tr>
</thead>
<tbody>
{{#each piece in pieces}}
<tr>
<td id="name">{{piece.name}}</td>
<td id="pdf">PDF</td>
<td id="audio">AUDIO</td>
<td id="format">FORMAT</td>
<td id="price">{{piece.score}}</td>
<td id="qty"><input type ="number" name ="quantity" min="5"></td>
</tr>
{{/each}}
</tbody>
<tfoot>
<tr>
<td colspan="5"></td>
<td><button class="button" type ="submit">Add to Cart</button></td>
</tr>
</tfoot>
</table>
</form>
</div>
{{else}}
<div>Loading template...</div>
{{/if}}
</div>
</template>
Related resources
TemplateInstance.autorun
http://blazejs.org/api/templates.html#Blaze-TemplateInstance-autorun
https://docs.meteor.com/api/tracker.html
Reactive stores
https://guide.meteor.com/data-loading.html#stores
Subscription readyness
https://guide.meteor.com/data-loading.html#readiness
Helpers
http://blazejs.org/guide/spacebars.html#Built-in-Block-Helpers
Related
This get the data from asp.net core webapi which is connected to Microsoft SQL Server. I'm trying to fetch but it returns undefined records in the list
This is Get method:
refreshList(){
this.http.get(this.baseURL).toPromise()
.then(res => this.list = res as PaymentDetail[]);
}
this is the way to make it accessible to html page:
constructor(public service : PaymentDetailService) { }
ngOnInit(): void {
this.service.refreshList();
}
this the way I show in front End:
<div class=col-md-6>
<table class="table">
<thead class="thead-light">
<tr>
<th>Card Owner</th>
<th>Card Number</th>
<th>Exp Date</th>
<th></th>
</tr>
</thead>
<tbody>
<tr *ngFor="let pd of service.list">
<td>{{pd.CardHolder}}</td>
<td>{{pd.CardNumber}}</td>
<td>{{pd.ExpirationdDate}}</td>
<td>
<i class="far fa-trash-alt fa-lg text-danger"></i>
</td>
</tr>
</tbody>
</table>
</div>
The response data is camel case format, so you need change the code below:
<tr *ngFor="let pd of service.list">
<td>{{pd.cardHolder}}</td>
<td>{{pd.cardNumber}}</td>
<td>{{pd.expirationdDate}}</td>
<td>
<i class="far fa-trash-alt fa-lg text-danger"></i>
</td>
</tr>
Imported data not displays in repeated table. It's only shows demo data. below is my template.
#{
<table class="table table-striped table-bordered">
<tbody>
#foreach (var Content in AsDynamic(Data["Default"]).OrderBy(m => m.wcName))
{
<tr>
<td width="30%">#Content.wcName </td>
<td>#Html.Raw(#Content.wcPosition)
#if (DotNetNuke.Common.Globals.IsEditMode())
{
#Content.Toolbar
}
</td>
</tr>
}
</tbody>
</table>
}
Your template only shows items assigned to this page/module, not "all data" - for that you would have to replace Data["Default"] with App.Data["your-content-type-name"].
You probably want to read more about this here: http://2sxc.org/en/blog/post/12-differences-when-templating-data-instead-of-content
//AJAX Webservice Call
ManualRegDiseaseData = $.parseJSON(rows.d);
var VM = new testView(ManualRegDiseaseData);
ko.applyBindings(VM);
var testView = function (DiseaseData) {
var self = this;
self.disease = ko.observableArray();
self.benefitData = ko.observableArray();
var sampleBenefit = [{ "Benefit": "Room", "Detail": "Ordinary", "Desc": "not herbal", "TotalDays": "2", "Remaining": "1000", "Claimed": "400", "Approved": "350", "Excess": "50" },
{ "Benefit": "Medicine", "Detail": "All", "Desc": "herbal", "TotalDays": "1", "Remaining": "2000", "Claimed": "800", "Approved": "600", "Excess": "100" }];
$.each(sampleBenefit, function (x, rowType) {
var obj = new BenefitObject();
obj.Benefit(rowType.Benefit);
obj.Detail(rowType.Detail);
obj.Desc(rowType.Desc);
obj.TotalDays(rowType.TotalDays);
obj.Remaining(rowType.Remaining);
obj.Claimed(rowType.Claimed);
obj.Approved(rowType.Approved);
obj.Excess(rowType.Excess);
self.benefitData.push(obj);
})
$.each(DiseaseData, function (x, rowType) {
var obj = new DiseaseObject();
obj.DiseaseCode(rowType.DiseaseCode);
obj.DiseaseName(rowType.DiseaseName);
self.disease.push(obj);
})
}
<table id="tblDisplayBenefit" class="">
<thead>
<tr>
<th>No.</th>
<th>Benefit </th>
<th>Detail </th>
<th>Description </th>
<th>Total Days </th>
<th>Remaining Inner Limit </th>
<th>Claimed </th>
<th>Approved </th>
<th>Excess </th>
<th>Reduce Max Limit </th>
</tr>
</thead>
<tbody data-bind="foreach: benefitData">
<tr>
<td data-bind="value: Benefit"></td>
<td data-bind="value: Detail"></td>
<td data-bind="value: Desc"></td>
<td data-bind="value: TotalDays"></td>
<td data-bind="value: Remaining"></td>
<td data-bind="value: Claimed"></td>
<td data-bind="value: Approved"></td>
<td data-bind="value: Excess"></td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="6" style="text-align: right">Total</td>
<td>Total Claimed</td>
<td>Total Approved</td>
<td>Total Excess</td>
</tr>
</tfoot>
</table>
Those are my JS snippet code and my html, the problem is, I can not data bind the sample JSON variable into my table. It seems I can not push my data into benefitData object.
I have been doing console.log the rowType, the Json data is readable through the console.log.
I dont know, this must be a simple data binding, yet I dont know where is the fault part.
I cant figure this out.
Thanks in advance for the suggestion!
Use text binding instead of value for text int the table cells:
<td data-bind="text: Benefit"></td>
<td data-bind="text: Detail"></td>
<td data-bind="text: Desc"></td>
<td data-bind="text: TotalDays"></td>
<td data-bind="text: Remaining"></td>
<td data-bind="text: Claimed"></td>
<td data-bind="text: Approved"></td>
<td data-bind="text: Excess"></td>
Js Fiddle
According to knockout documentation
The value binding links the associated DOM element’s value with a
property on your view model. This is typically useful with form
elements such as input, select and textarea.
In other words it works with form elements and makes two-way binding, so when you change the value knockout automatically updates your ViewModel.
On the other hand, text binding
Typically this is useful with elements like span or em that
traditionally display text, but technically you can use it with any
element.
So you should use text binding here, because <td> element has static content.
I am struggling to see how to use Handlebars with simple string arrays. I have the following object
When looping around the searchParam array I use something like :
{{#each model.searchParam}}
<table class="table table-bordered table-striped">
<thead>
<tr>
<th class="th-narrow">Property</th>
<th>Value</th>
</tr>
</thead>
<tbody>
<tr>
<td><span class="label">name</span></td>
<td>{{name}}</td>
</tr>
<tr>
<td><span class="label">type</span></td>
<td>{{type}}</td>
</tr>
</tbody>
</table>
{{/each}}
In the image above, how do I loop around the "searchInclude" array?
{{#each model.searchInclude}}
... wht do I reference here for the contents of the array?
{{/each}}
In case of an array, this will be the value and you can obtain the index with the Handlebar magic keyword #index
{{#each model.searchInclude}}
{{#index}}: {{this}}
{{/each}}
I am all new to Durandal and have been playing around with it for a few hours now. It seems very promising - but now I have run into a problem, I cannot figure out - and cannot find a solution with Google.
I have a view with three tables of data - creditCardLines, cashLines and drivingReimbursementLines. They fetch data from three different data sources - and the user can add new lines to cashLines and drivingReimbursementLines (left out the forms).
Problem: In the viewmodel, I can easily bind a list for data to the first foreach - but I cannot figure out how to bind data to the second and third.
In the activate function I make an ajax call to my server API to get the data for the first foreach - and then returns the promise, when this finishes. How do I get data for the second and third foreach here?
ViewModel:
define(function () {
var submit = function () {
this.displayName = 'Expenses';
this.creditCardLines = ko.observableArray();
var me = this;
this.activate = function () {
return $.get('/submit/GetCreditCardLines').then(function (creditCardLines) {
me.creditCardLines(creditCardLines.Data);
});
};
};
return submit;
});
View:
<section>
<h2 data-bind="html:displayName"></h2>
<h3>CreditCard lines</h3>
<table class="table">
<tbody data-bind="foreach: creditCardLines">
<tr>
<td class="date" data-bind="text: Date"></td>
<td data-bind="text: Description"></td>
<td data-bind="text: Amount"></td>
<td><input type="checkbox" data-bind="checked: ApprovedEmployee" /></td>
</tr>
</tbody>
</table>
<h3>Cash lines</h3>
<table class="table">
<tbody data-bind="foreach: cashLines">
<tr>
<td class="date" data-bind="text: Date"></td>
<td data-bind="text: Description"></td>
<td data-bind="text: Amount"></td>
</tr>
</tbody>
</table>
<!-- TODO: Generate form to add new lines -->
<h3>Driving reimbursement lines</h3>
<table class="table">
<tbody data-bind="foreach: drivingReimbursementLines">
<tr>
<td class="date" data-bind="text: Date"></td>
<td data-bind="text: Description"></td>
<td data-bind="text: Distance"></td>
<td data-bind="text: Rate"></td>
<td data-bind="text: Amount"></td>
</tr>
</tbody>
</table>
<!-- TODO: Generate form to add new lines -->
<!-- Approve and save all lines as a quote with lines -->
<input type="submit" value="Submit quote" />
</section>
This is how I've been dealing with multiple jQuery deferred calls in my view models:
return $.when(
$.get('/submit/GetCreditCardLines'),
$.get('/submit/GetCashLines'),
$.get('/submit/GetReimbursementLines'))
.then(function (creditCardLines, cashLines, reimbursementLines)
{
processCreditCardLines(creditCardLines);
processCashLines(cashLines);
processReimbursementLines(reimbursementLines);
})
.fail(function (status)
{
// Do whatever you need to if it fails
});
You don't need the process methods if you don't want them, but if you're doing anything complicated, I think it's neater to have them.
You should check out BreezeJS. It has an option to make a single Ajax call to pull multiple lookups.
Take a look at the BreezeJS docs for a detailed explanation: http://www.breezejs.com/documentation/lookup-lists