Knockout.js - javascript function on data-bind - asp.net

Is there a way i can call JavaScript function on data-bind like this:
<span id="lblSomePropVal" data-bind="text: MySomeFunction(SomeProperty())" ></span>
What i am trying to do is call MySomeFunction with the value of SomeProperty of my viewmodel. My SomeFunction will return some text based on value passed and that will be displayed in the span lblSomePropVal.
I tried it the way i have written in the example but it throws binding error.
Am i missing something here or is there any other way of doing this?
This is the error i am getting:
Microsoft JScript runtime error: Unable to parse bindings.
Message: [object Error];
Bindings value: text: MySomeFunction(SomeProperty())

I had a similar problem trying to calculate table cell entries. What worked for me was including 'MySomeFunction' in my data model, and then data-binding my table cells as:
<td data-bind="text: $root.MySomeFunction(SomeProperty)"></td>

You can use arbitrary JavaScript expressions for bindings, but keep in mind that they are evaluated in the viewmodel's context, so all functions in the expression have to be properties of viewmodel. In your case, MySomeFunction has to be a property of your viewmodel. If you create your viewmodel using mapping plugin, you can attach additional functions to the viewmodel like this:
var viewModel = ko.mapping.fromJS(data.d)
viewModel.MySomeFunction = function(...){...};

Well I am just going through the tutorial myself but I thought you had to set up a property and use ko.computed to give it its value (from the tutorial):
function AppViewModel() {
this.firstName = ko.observable("Bert");
this.lastName = ko.observable("Bertington");
this.fullName = ko.computed(function(){
return this.firstName() + " " + this.lastName();
},this);
}
Then you can have:
Full name: <strong data-bind="text: fullName"></strong>

I have managed to do this by using the context. If you need the whole code I can send it to you.
<h2 class="text" data-bind="html: currentProgram($context)"></h2>
function currentProgram(context){
var title = '<font size="1">' + context.$data.name + '</font>';
return title;
}
You will also need to set this
$.ajaxSetup({
async: false
});

<div style="font-size:18px;float:left;width:95%" data-bind="html: trimString(AccountName,25)"></div>
function trimString(value, maxLen) {
//Return undefined, and short strings
if (value === undefined) return undefined;
if (value.length < maxLen) return value;
return value.substring(0, (maxLen - 1));
}

Related

SAPUI5 Expression Binding

Is it possible to bind control property to model with dynamic property name, stored, for instance, within another model field? I thought we can use SAPUI5 Expression Binding for this purpose, but it doesn't work: binding in trace window is broken and expression seems to be not evaluated at all.
XML View
<TextArea value="{= ${StackOverflow>/bindTextAreaTo} }" />
Controller
oModel = this.getView().getModel("StackOverflow");
/*
* The model have two properties: question and comment
* I want value of TextArea to be bound to one of them based on some condition
*/
oModel.setProperty("/question", "");
oModel.setProperty("/comment", "");
oModel.setProperty("/bindTextAreaTo",
bAsk ? "StackOverflow>/question" : "StackOverflow>/comment" );
No, that's currently not possible.
However, there is a simple workaround for what you want to do (see below).
Basically, you create a view model and set some boolean value on the model. This flag is then used in your expression binding to define "dynamically" what property of what model shall be used...
XMLView
<TextArea value="{= ${view>/ask} ? ${StackOverflow>/question} : ${StackOverflow>/comment} }" />
Controller
var oModel = this.getView().getModel("StackOverflow");
oModel.setProperty("/question", "");
oModel.setProperty("/comment", "");
//...
var oViewModel = new sap.ui.model.json.JSONModel();
this.getView().setModel(oViewModel, "view);
//...
oViewModel.setProperty("/ask", bAsk);

Insert id into list if checkbox is checked

Net MVC and I have a table with products I want to buy.
I want to use a Checkbox to confirm the purchase.
But how can I insert the ID in a List<int>?
I have a class Approved with an attribute List<int> approve
I tried:
#Html.CheckBoxFor(m.approve.Add(id))
#Html.CheckBoxFor(m=>m.approve.Add(id))
#Html.CheckBoxFor(ViewBag.l.approve.Add(id)
How can that task be done ?
You can easyly bind a list to a model:
Model Binding To A List
So, you simply need to make a list of a class created for this, which includes the integer id, and a boolean to hold the checkbox state, somethign like this:
public class IdState
{
public int Id {get;set;}
public bool Checked {get;set;}
}
The list must be of this class, i.e. List<IdState>
The key is using a syntax like this:
Html.CheckBoxFor(m => m[i].Product)
Which will produce and input whose name is something like this:
name="[0].Product"
Then, the model binder will bind your list automatically. Of course, your post action must recevied a List<IdState> to function properly.
u can use html to insert id to your checkbox
#model yourModel
//for generate checkbox
<input type="checkbox" #(yourmodel ? " checked=checked " : null) name="YourCheckBoxName" value="#model.ID" >
use formCollection for get value in your controller from your view
I solved this problem that way:
This Javascript function walks through all checkboxes and saves the Id of the checked once to an hidden input.
<script>
function submit() {
var x = new Array();
for (i = 0; i < ids.length; i++){
if ($("#" + ids[i].toString() + ".cb").is(':checked')) {
x.push(ids[i]);
}
}
console.log(x.toString());
$("#str").val(x.toString());
}
</script>
After toggling a checkbox the value of the hidden input is refreshed
<script>
$(document).ready(function () {
$("input.cb").change(function () {
submit();
});
});
</script>
Here I create an array with all possible ids to improve simplicity and performance.
Otherwise I had to walk through all possible ids and check them.
<script>ids.push(#id);</script>
This is my checkbox:
<input type="checkbox" value="#id" id="#id" class="cb" />

knockout.js - data-bind auto update after function call

I have a case where I databind to a date field inside model in a list:
function Model(data) {
var self = this;
ko.mapping.fromJS(data, {}, this);
}
<div id="fieldOnPage" data-bind="text: formatDate(myDateField())"></div>
Then, in a modal, I display the same date field so it can be edited:
<div id="fieldInModal" data-bind="text: formatDate(myDateField())"></div>
However, since I'm calling the formatDate function does its work on the unwrapped observable, I'm unable to see the changes get written real-time back onto the main page when I edit the value in the modal.
Another caveat is that I using the ko.mapping plugin so I don't necessarily have a specific ko.computed field on myDateField. Is this possible to do with an external function like this? If not, how would I do it using the ko.computed if I had to specifically override the myDateField binding?
You could do something like
function Model(data) {
var self = this;
ko.mapping.fromJS(data, {}, this);
this.formattedDate = ko.computed(function () {
return formatDate(ko.utils.unwrapObservable(self.myDateField));
});
}
The bind to the formatted Date
<div id="fieldInModal" data-bind="text: formattedDate"></div>
Hope this helps.

Binding to nested properties where observables in the chain can be null

I just read about KnockoutJS and when I try to bind to sub-properties on objects that can be null I get binding errors, e.g.:
<div data-bind="text: selectedAccount().DocumentList().length"></div>
So once you call ko.applyBindings it tries to evaluate the above expression and if selectedAccount is null (which it is by default) it throws an error. I know that I can create a dependentObservable like so:
viewModel.docLength = ko.dependentObservable(function () {
return selectedAccount() ? selectedAccount().DocumentList().length : null;
})
But I was wondering if there's a solution other than putting properties in the ViewModel simply because I get a binding error.
A couple thoughts:
If you don't want to bother with the dependentObservable, then you can place your statement directly in the text binding like:
<div data-bind="text: selectedAccount() ? selectedAccount().DocumentList().length : null"></div>
or even shorter:
<div data-bind="text: selectedAccount() && selectedAccount().DocumentList().length"></div>
Depending on your scenario, you can also use the template binding to your advantage when dealing with potentially null values. It would be like this:
<div data-bind="template: { name: 'accountTmpl', data: selectedAccount }"></div>
<script id="accountTmpl" type="text/html">
${DocumentList().length}
</script>
Additionally, in the 1.3 release of Knockout there will be some control flow bindings that could be helpful to you. Particularly the "if" or "with" bindings would work for this situation. They are described here: https://groups.google.com/d/topic/knockoutjs/pa0cPkckvE8/discussion

Calling callback method for ASP.net validators

I am creating one web application in which I am showing watermark text for some fields.
For example: I have one text box "Name" in which I am showing "Fill Name" as watermark. I have one required field validator for this text box. So, I am clearing the text box before the required field validator chck the text box other wise it will treat "Fill Name" as valid data and it will not apply validations. But when the validations fails, the watermark is not coming. Can we register some kind of callback method on asp.net validators?
I just want to run one java script function when asp.net validations fails.
Thanks
Ashwani
Have a look at the TextboxWatermarkextender from the AjaxControlToolkit. That controls fulfills all your described wishes. Have a look at the InitialValue property.
I got the solution for this.
function HookFunction() {
var Original_ValidatorUpdateDisplay = ValidatorUpdateDisplay;
ValidatorUpdateDisplay = function (val) {
Original_ValidatorUpdateDisplay(val);
if (val) {
val.style.display = val.isvalid ? "none" : "inline-block";
}
};
var Original_ValidatorSetFocus = ValidatorSetFocus;
ValidatorSetFocus = function (val, event) {
if (val) {
ClearWaterMarkText($('#' + $(val).attr('controltovalidate')));
}
Original_ValidatorSetFocus(val, event);
};
}

Resources