How to pass handlebar item to function? - handlebars.js

So, let's say that this is part of my code:
<li data-product-id="{{this.id}}"></li>
and after a few lines, I have this
<button id="Button" onclick="addToCart(${{this.id}})">Press</button>
However, ${{this.id}} doesn't seem to be right.
What should I write instead?

I am not sure what the dollar sign $ in the argument to your onclick handler is intended for. However, the onclick handler is JavaScript and therefore must contain valid JavaScript code.
If the dollar sign is to prepended to the product ID in the addToCart argument, then you will need to use quotations in order to make this argument a valid JavaScript string:
<button id="Button" onclick="addToCart('${{this.id}}')">Press</button>
Perhaps the dollar sign is not intended to be a part of the argument and it is being used mistakenly in a similar way to a JavaScript template string. If this is the case, the quotes will be required in the addToCart call only if the argument is intended to be a string. If the argument is to be a string, then the template should be:
<button id="Button" onclick="addToCart('{{this.id}}')">Press</button>
But if the argument is to be a number, then the quotes should not be included:
<button id="Button" onclick="addToCart({{this.id}})">Press</button>
I have provided a fiddle for reference.
Update
To "get" the item is a little more complicated. This is because, one the template is rendered, there is no existing reference to the data that was passed to the template function.
There are different approaches to solving this problem and the solution may be dependant upon your requirements. However, one simple way to render the entire product item object as the argument to addToCart would be to JSON.stringify the item where it is rendered. This would require writing a Handlebars helper, like:
Handlebars.registerHelper('serialize', obj => JSON.stringify(obj));
You would then utilize this helper in your template with:
<button id="Button" onclick="addToCart({{serialize this}})">Press</button>
I have created an example fiddle.

Related

Get length of a string with data-link

I would like to display the length of the text in my textarea. But since I don't want to build an event handler for it, I would like to try to solve this with the data-link. Unfortunately I don't find a way to do this.
<textarea id="commentText" data-link="commentText()"></textarea>
<span><span id="commentTextLength">{^{>commentText().length}}</span>/300</span>
You can simply change the expression from commentText().length to commentText()^length.
See "deep linking".
In that way you make the expression update whenever there is an observable change in commentText() itself.
So you can write:
{^{>commentText()^length}}
or
<span data-link="commentText()^length"></span>
This works equally whether you are using a plain string value commentText^length or a computed observable commentText()^length as in your example.

Can validate and converter be combined in jsViews data-link?

I can ensure data exists in an input element by including validate and required in jsViews' data-link attribute like this:
<input type="text" data-link="{validate activityCode required=true}">
And by following Boris Moore's example I can ensure the data returned to the model is cast as an integer instead of input's default type of string:
$.views.converters({
toInt: function(value) {
return parseInt(value); // simple example, without error checking
}
});
<input type="text" data-link="{:activityCode:toInt}">
Where I'm having a problem is combining both validation and converter. Nothing binds to the input element using this:
<input type="text" data-link="{validate activityCode:toInt required=true}">
Does anyone know of syntax that allows both validation and convertBack functionality to exist in the same data-link attribute?
You can use the syntax convert=... convertBack=... on any tag.
See two-way binding - convert and convertBack and using converters with other tags. (The second docs reference is for JsRender, so concerns convert only. But if using JsViews data-linking, then convertBack=... works in just the same way.)
Search for "convertBack=" and you'll find some examples, including this with radiogroup and this one with validate.

Binding an inputText value to a viewScope with a computed name

I have an inputText component on a custom control and I am trying to bind the value to a viewScope, but the viewScope name is computed using a compositeData value and string.
If I hardcode the value binding it works, for example:
value="${viewScope['BillingDate_From']}"
The viewScope name is computed using the following javascript code:
compositeData.dateRangeFilter[0].from_fieldname + '_From'
I have tried many ways of achieving this but with no success, sometimes it errors, usually unexpected character errors but most of the time the inputText box is empty.
The code I have most recently tried:
value="${viewScope[#{javascript:compositeData.dateRangeFilter[0].from_fieldname + '_From'}]}"
I have found, and I don't know the reason for this, that trying to bind dynamically doesn't work if there's any string concatenation in the evaluation. The way I got around this was by creating a custom control that accepts a bindingValue and dataSource as parameters, then passing in the document and field name I want to use. For whatever reason, if the code uses composite data, it still allows for editing when the page loads.
Hi try this to build what you need:
The Control:
<xp:inputText id="inputText1">
<xp:this.value><![CDATA[${javascript:"#{"+compositeData.scopeName+"}";}]]></xp:this.value>
</xp:inputText>
<xp:text escape="true" id="computedField1">
<xp:this.value><![CDATA[${javascript:"#{"+compositeData.scopeName+"}";}]]></xp:this.value>
</xp:text>
The XPage using the Control:
<xc:cc id="xx">
<xc:this.scopeName><![CDATA[#{javascript:return "viewScope." + " calculatedScopeVarName";}]]></xc:this.scopeName>
</xc:cc>
<xp:button value="Beschriftung" id="button1">
<xp:eventHandler event="onclick" submit="true"
refreshMode="partial" refreshId="xx">
<xp:this.action><![CDATA[#{javascript://}]]></xp:this.action>
</xp:eventHandler>
</xp:button>
Instead of "viewScope" you cant add session or another scope and instead of calculatedScopeVar you can enter the name of your var. But this has a limit, it only works if the calculatedScopeVar is accesable through the component onLoad. For example it will not work if you use this control in a Repeat control and try to use the repeated array as calculatedScopeVar.

how to bind data as routeValue in telerik ListView template

My template modified from MvcMusicStore tutroial:
<script type="text/x-kendo-tmpl" id="template">
<div class="product">
<a href="#Url.Action("Details", "Store", new {id = ${ProductSubCategoryId} })">
<img src="#Url.Content("${AlbumArtUrl}")" alt="${Title} image" />
</a>
<span><h3>${Title}</h3></span>
<p>${kendo.toString(Price, "c")}</p>
</div>
</script>
but there is error in Url.Action method: Unexpected symbol '$'.
Update 1:
And i can't use
#Model.First(d => d.ProductCategoryId.Equals(Convert.ToInt32("${ProductSubCategoryId}"))).ProductCategory.Name
but same code in
#Url.Content("${AlbumArtUrl}")
work fine.
new {id = ${ProductSubCategoryId} }
This is C# code for an anonymous object, and C# doesn't know anything about JS templating. Hence the error telling you it doesn't know what that $ is doing there. Usually you'd pass something from your View model, which is only available serverside:
new {id = Model.ProductSubCategoryId }
Instead of using a URL helper, you might be better off with just a string href="Store/Details/${ProductSubCategoryId}". That may not be exactly what you need, but I don't know enough about the routing and your template to know if this is what you intended, or if ProductSubCategoryId is actually a property of your model.
In regards to your updated examples:
Url.Content( works because that function takes the parameter as the page is being rendered on the server, and just spits out with the string "${AlbumArtUrl}" in the HTML pretty much as it is, and the HTML will contain the string "${AlbumArtUrl}" so that when the JS template is parsed later on the client, it can interpret that variable. So in this case, the C# function .Content( doesn't need to understand that template variable, because to it, it is just a string that it embeds in the HTML. I would recommend using F12 in Chrome to view the GET response in the network tab so you can see the HTML source as it was returned from the action, so you have a better idea in your mind of what exactly what is happening at each step of the process. You'll be able to see that in your HTML returned, there is no C# code like Url.Content, but you will see the javascript template stuff like "${AlbumArtUrl}" because those values aren't rendered on the server side.
On the other hand Convert.ToInt32("${ProductSubCategoryId}") fails, because this function expects the string it's being passed to be an integer, such as Convert.ToInt32("2134"). As far as ToInt32 is concerned, it says, ok, I see "something" is a string, now I will try to interpret the string as a number which means I expect it to contain some digits, such as "456457" but you gave me a bunch of letters and symbols which means nothing to me, I can't convert that into an integer. Again, this is C# function that is running on the server as it generates the page, and "${ProductSubCategoryId}" means nothing to C# as it is a javascript template variable.
You are mixing server-side code with client-side code. This is invalid C# code:
#Url.Content("${AlbumArtUrl}")
You cannot use helper to generate URLs this way. I suggest you to go the normal way without using the Url helper.
If you are determined to use Url.Action, then here is a way. It is a hack but you can do this:
<a href="#Url.Action("Details", "Store")?id=${ProductSubCategoryId}">

passing querystring parameters

what is the best way of passing querystring to another page, i would definitly avoid like using.......
<a href="Page2.aspx?WONumber=12345">
is there any better way?
i was thinking create a Baseclass with few prop and update the baseclass?
thanks.
It sounds like you want to take the querystring argument, and use it in subsequent pages.
If it's not desirable to pass-forward this querystring argument from your current page, perhaps it's called page1.aspx, without using another querystring parameter, you could:
store the value in Session. Consider Session["WoNumber"] = Request.QueryString["WONumber"].ToString();
store the value in Cookies. You could use something like: Response.Cookies["WoNumber"].Value = Request.QueryString["WONumber"].ToString();
It really depends on where you're getting the value from. You can build a URL using UriBuilder or if it's simple enough string concatenation could be OK (though you'd have to make sure to Server.UrlEncode the values).
If the value is a constant, as your example implies, then there is nothing wrong with putting it directly into a query string, although I would still use a proper named constant, eg.
<a href="Page2.aspx?WONumber=<%= TheMagicOrderNumber %>
with the constant defined in the code-behind:
protected const int TheMagicOrderNumber = 12345
If your objection is the maintainability of "magic string" URLS, and you'd be prepared to use a button instead of an anchor, you could do worse than
<form method="GET" action="Page2.aspx">
<input type="hidden" name="WONumber" value="12345" />
<input type="submit" value="Navigate" />
</form>
this method will generalise to a query string of any complexity with any number of parameters.
There is a great article I came across a few months ago when I was looking for enhanced security with querystrings...
http://devcity.net/Articles/47/1/encrypt_querystring.aspx
It's a very good article, and has a bonus the author offers code examples in C# and VB.NET.
There are times when I prefer to use querystrings over sessions... small number of session objects is ok, but too many and it starts to become a bit tedious to debug problems.
You can encrypt a querystring parameter, if security is your concern.
Or you can use other holders, such s p.cambell says above (session & cookie).
You could also store it in a database, and have the page you go to retrieve it onload.
Just depends on your application requirements.
Another thing I've done is to use <asp:panel>, basically using a single page as though it were multiple pages. In this way, I also have access to viewstate to hold my variables. (Whenever a user clicks 'next', or whatever they would click to goto the next page, I simply hide the panel they're on, and show the panel they want to go to [visible = true/false] property)

Resources