Handlebars.net: Reached end of template before block expression 'currency' was closed - handlebars.net

I have a template that looks like this:
(I removed some elements of the table just to keep the code short)
{{#each Tables}}
<div id='report-container'>
<table id='report-table'>
<tr class='header-row'>
<th style='width: 150px; max-width: 150px !important;'>{{this.Title}}</th>
<th>Total Company Net Sales $</th>
...
</tr>
{{#each this.Data}}
<tr>
<td>{{RowTitle}}</td>
<td>{{currency TotalCompanyNetSales}}</td>
...
</tr>
{{/each}}
</table>
</div>
{{/each}}
With a helper:
handleBars.RegisterHelper("currency", (writer, context, parameters) =>
{
var value = decimal.Parse(parameters[0].ToString());
value /= 1000;
var result = value.ToString("0,-28:C2");
return result;
});
Im not sure if the object itself is relevant but I can post if necessary. The problem is just with the helper. When I try to compile the template I get the following error message:
"Reached end of template before block expression 'currency' was closed"
If I remove the currency helper the value displays fine. It never even calls the currency function. Any idea what I am doing wrong here?

The problem is related to a misuse of new (to Handlebars.Net) return helper syntax: helper you're declaring is actually a block helper returning value:
handleBars.RegisterHelper("currency", (writer /*this is not `writer` but `options`*/, context, parameters) =>
{
// your code here
return result; // change is caused by the `return` statement
});
In order to fix the helper and still use return feature you should simply drop the options argument from lambda:
handleBars.RegisterHelper("currency", (context, parameters) =>
{
// your code here
return result;
});

Related

MVC foreach statement

Im new with MVC.
I have a model called UAV.
│Callsign│NumDeliveries│Mileage│MaxVelocity│MinVelocity│
 Hawk61   37    96    20     10
 BURL14   2047     57     30     15
 OTTO93   82    72    25     10
in cshtml file, i made a table only using Callsign, NumDeliveries, Mileage.
<table class="UAV_table" id="UAV_table">
<tr>
<th>Callsign</th>
<th>NumDeliveries</th>
<th>Mileage</th>
</tr>
#foreach (UAV uav in Model.UAVs)
{
<tr onclick="click_row()">
<td onclick="click_row()">
#Html.DisplayFor(modelItem => uav.Callsign)
</td>
<td>
#Html.DisplayFor(modelItem => uav.NumDeliveries)
</td>
<td>
#Html.DisplayFor(modelItem => uav.Mileage)
</td>
</tr>
}
</table>
 so the table shows all datas for Callsign, NumDeliveries, Mileage.
what i want to do is, when i click the row of the table, i want to see only that correspond information.
#foreach (UAVs uavid in Model.uavs)
{
<p class="detail_title" id="detail_title">
UAV: # (#Html.DisplayFor(modelItem => uavid.MaxVelocity))
</p>
}
for example, using above line of code, if i click first row of that table(callsign = Hawk61), i want to see like UAV: # 20 (MaxVelocity for Hawk61). MaxVelocity is not in the table, so i need to get it from database.
But I have problem with showing data. If i use right above code, it has #foreach statement, it shows all the Hawk61, BURL14, OTTO93's MaxVelocity.
it shows me like
UAV:# 20
UAV:# 30
UAV:# 25
I need to see only what i selected. (just shows what i click, in this example, only need to show UAV:# 20 which is first row, Hawk61's MaxVelocity).
is there any way to get the data from database not using foreach statement?
Thank you.
Since the values of MaxVelocityand MinVelocity are populated, you can make use of data- attributes to store the values in the DOM and use jquery to display them. For example
#foreach (UAV uav in Model.UAVs)
{
<tr class="uavrow" data-maxvelocity="#uav.MaxVelocity" data-minvelocity="#MinVelocity">
<td>#Html.DisplayFor(modelItem => uav.Callsign)</td>
<td>#Html.DisplayFor(modelItem => uav.NumDeliveries)</td>
<td>#Html.DisplayFor(modelItem => uav.Mileage)</td>
</tr>
}
And include some elements to display the associated data when you click on the row
<div>
<div><span>Call Sign: </span><span id="callsign"></span>
<div><span>Max Velocity: </span><span id="maxvelocity"></span>
<div><span>Min Velocity: </span><span id="minvelocity"></span>
</div>
And the script
$('.uavrow').click(function) {
// Get the call sign for the td element
$('#callsign').text($(this).children('td').eq(0).text());
// Get the velocity from the data attributes
$('#maxvelocity').text($(this).data('maxvelocity'));
$('#minvelocity').text($(this).data('minvelocity'));
});
If however the value were not populated, or you have a large number of properties to display, then it may be better to make an ajax call to a method (passing the callsign) which returns a partial view containing the details
<div id="uavdetails"></div>
$('.uavrow').click(function) {
var callSign = $('#callsign').text($(this).children('td').eq(0).text());
var url = '#Url.Action("Details", "YourController")';
$('#uavdetails').load(url, { CallSign: callsign });
});
Controller
public ActionResult Details(string CallSign)
{
UAV uav = // Get the UAV base on the CallSign value
return PartialView(uav);
}
Actually you have all data that you need in there.
The only thing that you need is to show proper item by using JavaScript.
You need to add parameter to your function call here:
<tr onclick="click_row('#uav.Callsign')">
And also add css class here:
#foreach (UAVs uavid in Model.uavs)
{
<p class="detail_title #uavid.Callsign" id="detail_title" style="display=none;">
UAV: # (#Html.DisplayFor(modelItem => uavid.MaxVelocity))
</p>
}
And then add a bit of javascript:
<script>
function click_row(elClass){
var elements = document.getElementsByClassName("detail_title");
for (i = 0; i < x.length; i++) {
if(x[i].className.contains(elClass)){
x[i].style.display = 'block';
} else{
x[i].style.display = 'none';
}
}
};
<script/>

Template repeat not working for nested list (Polymer.dart)

Due to the lack of multi-dimensional array support in dart, I thought of using List.
Dart code :
class MyModel extends Object with Observable {
#observable
List<List<int>> dataList = toObservable(new List<List<int>>());
}
void main() {
initPolymer().run(() {
Polymer.onReady.then((_) {
var template = querySelector("#bindValueTemplate") as AutoBindingElement;
var model = template.model = new MyModel();
for (int i=0; i<2;i++) {
List<int> in1 = new List<int>();
for (int j=0; j<2; j++) {
in1.add(j);
}
model.dataList.add(in1);
}
});
});
}
HTML file (snippet):
<body fullbleed touch-action="auto">
<template id="bindValueTemplate" is="auto-binding-dart">
<div id="dynamic_area" layout horizontal>
<table template repeat="{{row in dataList}}">
<tr template repeat="{{col in row}}">
<td>{{col}}</td>
</tr>
</table>
</div>
</template>
</body>
Error I get in console:
Uncaught Error: Error evaluating expression 'row': Class 'MyModel' has no instance getter 'row'.
NoSuchMethodError: method not found: 'row'
Receiver: Instance of 'MyModel'
Arguments: []
When I added a 'row' list variable in MyModel with a getter, it throws the following error :
Uncaught Error: Unsupported operation: can't eval an 'in' expression
My understanding of template repeat was wrong. The repeat clause is to be applied for the the element itself, and not the children. This fixed the problem :
<body fullbleed touch-action="auto">
<template id="bindValueTemplate" is="auto-binding-dart">
<div id="dynamic_area" layout horizontal>
<table>
<tr template repeat="{{row in dataList}}">
<td template repeat="{{col in row}}">{{col}}</td>
</tr>
</table>
</div>
</template>
</body>
And the updated dart code :
class MyModel extends Object with Observable {
#observable
List<List<int>> dataList = toObservable(new List<List<int>>());
#observable
List<int> row = []; //I don't know why it works even without toObservable()
}
I am marking the question as resolved because my specific problem was resolved. But the question still remains what if we actually want to repeat table elements !
You assign the model to the template and only afterwards add the data.
I guess you need to make the inner lists observable too.
List<int> in1 = toObservable(new List<int>());
or a bit shorter
List<int> in1 = toObservable(<int>[]));
But the error message seems to point more to this issue http://dartbug.com/12742
Can you please try if it works inside a Polymer element instead of AutoBindingElement.
EDIT
Normally you don't add repeat on an element. Normally you use
<template repeat="{{x in y}}">
<!-- repeate this y.length times -->
</template>
There are exceptions. For example <ul>, <tr>, and a few others,
because browsers do not allow HTML like
<table>
<!-- this template element is just dropped by some browsers because
only some specific elements are allowed inside a `<table>` element. -->
<template repeat="{{x in y}}">
<tr>
</tr>
<!-- repeate this y.length times -->
</template>
As a workaround for such situations
<table>
<tr repeat="{{x in y}}"> <!-- here not the children but the element itself is repeated -->
</tr>
</table>

Knockout automapped array with formatted (computed?) column

I have a CRUD single page using Knockout, everything works OK, I get the data from a JSON call, it fills an automapped observable array with the list of objects.
I can add or edit single items in that array.
The issue comes with formatting a currency (numeric) column I show in the table with the list of objects. I have tried using js functions, in a lot of ways but the formatted currency amount of the table does not update when I update an item.
If I use a binding for formatting the field then I can't edit it because it converts into a String.
What I need is a one-way binded (auto updated) formatted column for my currency column. But I can't create a computed column right away because I'm using an automapped array of objects. I tried adding the computed using the example in http://knockoutjs.com/documentation/plugins-mapping.html, but I don't know how to use it with an mapped array.
My viewmodel is something like this:
//--Accounts - Viewmodel Knockout
function accountViewModel() {
var self = this;
self.accounts = ko.observableArray(); //this is the list of objects
self.account = ko.observable(); //single item for creating or editing
//--get list------
self.getAccounts = function () {
$.postJSON(appURL + 'Accounts/GetList', function (data) {
ko.mapping.fromJS(data.Records, {}, self.accounts);
});
};
self.getAccounts();
}
Each account item have fields like:
-Id
-Name
-Balance <-- this is the column I want to format
Using it in the page:
<table data-bind="visible: accounts().length > 0">
<thead>
<tr>
<th scope="col">Id</th>
<th scope="col">Name</th>
<th scope="col">Balance</th>
</tr>
</thead>
<tbody id="accounts" data-bind="foreach: accounts">
<tr>
<td><span data-bind="text: Id"></span></td>
<td></td>
<td style="text-align:right;">
<span data-bind="text: formatCurrency(Balance), css: { negative: Balance() < 0, positive: Balance() > 0 }"></span>
</td>
</tr>
</tbody>
</table>
formatCurrency is just a js function for formatting the number:
formatCurrency = function (value) {
debugger;
if (value!=undefined)
return "$" + withCommas(value().toFixed(2));
//had to use value() instead of value, because of toFixed
}
Thanks!
When you set the text to the return value of a function (text: formatCurrency(Balance)) it only runs once. It's not an observable, so it's value will never update again. What you need is a true-blue computed observable. In order to get that, you'll have to customize the mapping. So simply create a view model for your individual account object, and then map your returned data onto that.
var SingleAccountViewModel = function (account) {
var model = ko.mapping.fromJS(account);
model.FormattedBalance = ko.computed(function () {
return formattedCurrency(model.Balance);
});
return model;
}
Then when you get your data back from your AJAX response:
$.postJSON(appURL + 'Accounts/GetList', function (data) {
self.accounts($.map(data.Records, SingleAccountViewModel));
});
The jQuery.map method will iterate through the array and return a new array composed of the return values of the function passed. In this case, that's your view model, which will now have a FormattedBalance computed on it that you can bind to.

How do I add an Event Listener to a Dynamic Element?

I have the following HTML:
<table>
<thead>
<tr>
<th>Id</th>
<th>Name</th>
<th>Description</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>Item 1</td>
<td>Description of Item 1</td>
<td>
Edit
Delete
</td>
</tr>
<tr>
<td>2</td>
<td>Item 2</td>
<td>Description of Item 2</td>
<td>
Edit
Delete
</td>
</tr>
</tbody>
</table>
The table rows (tr elements) are added dynamically.
I wire up a click event to all Edit links like this:
void wireUpTableEvents() {
var editLinks = queryAll('#order-items table tbody [data-action="edit"]');
editLinks.forEach((element) {
element.on.click.add((event){
print(element.attributes['data-item-id']);
});
});
}
As said above, the table rows (tr elements) are added dynamically so the above code only works if I call wireUpEvents after I execute the method which adds the rows.
Does anyone know the syntax or adding a event listener to elements using DART's on.click.add() when the elements are dynamcially added in the future?
I tried checking the DART documentation but the documentation on Event Listeners is blank.
If I would be using jQuery I could be using something similar to:
$("#order-items table")on("click", "tbody [data-action="edit"]", function(){...})
...but I want to write my sample app only using DART.
Edit
Though future sounds great for callbacks it seemed slightly overkill for what I needed as there is no long running task in my scenario.
The closest I was able to get to attach my event listener to a static element but processing the click events of future sub-elements was this:
void wireUpTableEvents() {
var tableBody = query('#order-items table tbody');
// Attach Event Listener to the static tbody, which always exists.
tableBody.on.click.add((event) {
var clickedElement = event.srcElement;
var itemId = clickedElement.attributes['data-item-id'];
// Check if the clicked element was either one of the edit links or one of the delete links.
switch (clickedElement.attributes['data-action']) {
case 'edit':
// Replace print with calling a method to process edit request for this item.
print('processing edit click from item with id: $itemId');
break;
case 'delete':
// Replace print with calling a method to process delete request for this item.
print('processing delete click from item with id: $itemId');
break;
}
});
}​
The above code can execute before any of the actual tr elements are loaded and still works after the tr elements are loaded at some unknown later stage.
I also found that it now covers any dynamically added row, pre-loaded ones as well as other dynamically added ones for new records etc.
It sounds like you need to use Dart's Future object. John Evans has a recent post that gives an excellent overview. I'll try to give a simple example:
Let's say I have a class called htmlInDart which I call as follows:
void main() {
var htmlExample = new HtmlInDart().createStyles();
htmlExample
..then((htmlExample) => htmlExample.buildPage())
..then((htmlExample) => htmlExample.addListeners());
}
The class might look something like this:
class htmlInDart {
htmlInDart();
Future<htmlInDart> createStyles() {
final c = new Completer();
// create some styles
c.complete(this);
return c.future;
}
Future<htmlInDart> buildPage() {
final c = new Completer();
// build the page
c.complete(this);
return c.future;
}
Future<htmlInDart> addListeners() {
final c = new Completer();
// add some listeners
c.complete(this);
return c.future;
}
Hopefully this gives you some idea of how to implement it for your case.
Is there any reason you can't add the callback when you are adding the rows in the first place? Something like:
void addRow(TableElement table, ...) {
TableRowElement item = new TableRowElement();
...
table.nodes.add(item);
item.on.click.add((callback) { });
}

Getting index value on razor foreach

I'm iterating a List<T> in a razor foreach loop in my view which renders a partial. In the partial I'm rendering a single record for which I want to have 4 in a row in my view. I have a css class for the two end columns so need to determine in the partial whether the call is the 1st or the 4th record. What is the best way of identifying this in my partial to output the correct code?
This is my main page which contains the loop:
#foreach (var myItem in Model.Members){
//if i = 1
<div class="grid_20">
<!-- Start Row -->
//is there someway to get in for i = 1 to 4 and pass to partial?
#Html.Partial("nameOfPartial", Model)
//if i = 4 then output below and reset i to 1
<div class="clear"></div>
<!-- End Row -->
</div>
}
I figure I can create a int that I can update on each pass and render the text no problem here but it's passing the integer value into my partial I'm more concerned about. Unless there's a better way.
Here is my partial:
#{
switch()
case 1:
<text>
<div class="grid_4 alpha">
</text>
break;
case 4:
<text>
<div class="grid_4 omega">
</text>
break;
default:
<text>
<div class="grid_4">
</text>
break;
}
<img src="Content/960-grid/spacer.gif" style="width:130px; height:160px; background-color:#fff; border:10px solid #d3d3d3;" />
<p>#Model.Name<br/>
#Model.Job<br/>
#Model.Location</p>
</div>
Not sure if I'm having a blonde day today and this is frightfully easy but I just can't think of the best way to pass the int value in. Hope someone can help.
#{int i = 0;}
#foreach(var myItem in Model.Members)
{
<span>#i</span>
i++;
}
//this gets you both the item (myItem.value) and its index (myItem.i)
#foreach (var myItem in Model.Members.Select((value,i) => new {i, value}))
{
<li>The index is #myItem.i and a value is #myItem.value.Name</li>
}
More info on my blog post
http://jimfrenette.com/2012/11/razor-foreach-loop-with-index/
Or you could simply do this:
#foreach(var myItem in Model.Members)
{
<span>#Model.Members.IndexOf(myItem)</span>
}
Take a look at this solution using Linq. His example is similar in that he needed different markup for every 3rd item.
foreach( var myItem in Model.Members.Select(x,i) => new {Member = x, Index = i){
...
}
You could also use deconstruction and tuples and try something like this:
#foreach (var (index, member) in #Model.Members.Select((member, i) => (i, member)))
{
<div>#index - #member.anyProperty</div>
if(index > 0 && index % 4 == 0) { // display clear div every 4 elements
#: <div class="clear"></div>
}
}
For more info you can have a look at this link
Is there a reason you're not using CSS selectors to style the first and last elements instead of trying to attach a custom class to them? Instead of styling based on alpha or omega, use first-child and last-child.
http://www.quirksmode.org/css/firstchild.html
IndexOf seems to be useful here.
#foreach (myItemClass ts in Model.ItemList.Where(x => x.Type == "something"))
{
int currentIndex = Model.ItemList.IndexOf(ts);
#Html.HiddenFor(x=>Model.ItemList[currentIndex].Type)
...
All of the above answers require logic in the view. Views should be dumb and contain as little logic as possible. Why not create properties in your view model that correspond to position in the list eg:
public int Position {get; set}
In your view model builder you set the position 1 through 4.
BUT .. there is even a cleaner way. Why not make the CSS class a property of your view model? So instead of the switch statement in your partial, you would just do this:
<div class="#Model.GridCSS">
Move the switch statement to your view model builder and populate the CSS class there.
Very Simple:
#{
int i = 0;
foreach (var item in Model)
{
<tr>
<td>#(i = i + 1)</td>`
</tr>
}
}`
In case you want to count the references from your model( ie: Client has Address as reference so you wanna count how many address would exists for a client) in a foreach loop at your view such as:
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.DtCadastro)
</td>
<td style="width:50%">
#Html.DisplayFor(modelItem => item.DsLembrete)
</td>
<td>
#Html.DisplayFor(modelItem => item.DtLembrete)
</td>
<td>
#{
var contador = item.LembreteEnvolvido.Where(w => w.IdLembrete == item.IdLembrete).Count();
}
<button class="btn-link associado" data-id="#item.IdLembrete" data-path="/LembreteEnvolvido/Index/#item.IdLembrete"><i class="fas fa-search"></i> #contador</button>
<button class="btn-link associar" data-id="#item.IdLembrete" data-path="/LembreteEnvolvido/Create/#item.IdLembrete"><i class="fas fa-plus"></i></button>
</td>
<td class="text-right">
<button class="btn-link delete" data-id="#item.IdLembrete" data-path="/Lembretes/Delete/#item.IdLembrete">Excluir</button>
</td>
</tr>
}
do as coded:
#{ var contador = item.LembreteEnvolvido.Where(w => w.IdLembrete == item.IdLembrete).Count();}
and use it like this:
<button class="btn-link associado" data-id="#item.IdLembrete" data-path="/LembreteEnvolvido/Index/#item.IdLembrete"><i class="fas fa-search"></i> #contador</button>
ps: don't forget to add INCLUDE to that reference at you DbContext inside, for example, your Index action controller, in case this is an IEnumerable model.
I prefer to use this extension method:
public static class Extensions
{
public static IEnumerable<(T item, int index)> WithIndex<T>(this IEnumerable<T> self)
=> self.Select((item, index) => (item, index));
}
Source:
https://stackoverflow.com/a/39997157/3850405
Razor:
#using Project.Shared.Helpers
#foreach (var (item, index) in collection.WithIndex())
{
<p>
Name: #item.Name Index: #index
</p>
}

Resources