Knockout with ASP.NET MVC4 - asp.net-mvc

Looking to start using Knockout with ASP.NET MVC4. Have watch some examples and encountered the following questions.
Today I write my view models backend, I can totally replace it
with knockout view models on the client side?
Is there anything like DataAnnotations in Knockout for
validation?

Yes, you remove the server view and view models. All are now are now on the client.
See Knockout validation
Also, you may want to check out OData/WCF data services (http://blogs.msdn.com/b/astoriateam/). It basically gives you a Model and Controller. With this approach you server ends up only serving static HTML pages and Model data as AJAX calls. And it also supports "paging" of data.
IMHO, this the way of the future.
Other links of interest:
Authorisation - http://msdn.microsoft.com/en-us/library/dd728284.aspx
Routing - http://blogs.msdn.com/b/rjacobs/archive/2010/04/05/using-system-web-routing-with-data-services-odata.aspx or http://code.msdn.microsoft.com/WCF-Data-Service-with-285746ac

Knockout.js is a great library. But if you ask people what to use knockout or angular.
Most of them will tell you Angular.js is better, though they are very similar.
I use knockout in my projects. And there are many things that can simplify your development.
For example. I use server side validation only. When user clicks on "submit", my javascript collects model and sends it to controller (asyncronously AJAX). Controller has validation, and if validation fails the response would be HTTP:500 and body will be validation result structure, that displays all errors in correct places in HTML.
From user's perspective it seems like client-side validation.
You can see how it works in this example: Create Order Example (Upida.Net).

You can use this library or this
or use this samole
<script id="customMessageTemplate" type="text/html">
<em class="customMessage" data-bind='validationMessage: field'></em>
</script>
<fieldset>
<legend>User: <span data-bind='text: errors().length'></span> errors</legend>
<label>First name: <input data-bind='value: firstName'/></label>
<label>Last name: <input data-bind='value: lastName'/></label>
<div data-bind='validationOptions: { messageTemplate: "customMessageTemplate" }'>
<label>Email: <input data-bind='value: emailAddress' required pattern="#"/></label>
<label>Location: <input data-bind='value: location'/></label>
<label>Age: <input data-bind='value: age' required/></label>
</div>
<label>
Subscriptions:
<select data-bind='value: subscription, options: subscriptionOptions, optionsCaption: "Choose one..."'></select>
</label>
<label>Password: <input data-bind='value: password' type="password"/></label>
<label>Retype password: <input data-bind='value: confirmPassword' type="password"/></label>
<label>10 + 1 = <input data-bind='value: captcha'/></label>
</fieldset>
<button type="button" data-bind='click: submit'>Submit</button>
<br />
<br />
<button type="button" data-bind='click: requireLocation'>Make 'Location' required</button>
ko.validation.rules.pattern.message = 'Invalid.';
ko.validation.configure({
registerExtenders: true,
messagesOnModified: true,
insertMessages: true,
parseInputAttributes: true,
messageTemplate: null
});
var captcha = function (val) {
return val == 11;
};
var mustEqual = function (val, other) {
return val == other();
};
var viewModel = {
firstName: ko.observable().extend({ minLength: 2, maxLength: 10 }),
lastName: ko.observable().extend({ required: true }),
emailAddress: ko.observable().extend({ // custom message
required: { message: 'Please supply your email address.' }
}),
age: ko.observable().extend({ min: 1, max: 100 }),
location: ko.observable(),
subscriptionOptions: ['Technology', 'Music'],
subscription: ko.observable().extend({ required: true }),
password: ko.observable(),
captcha: ko.observable().extend({ // custom validator
validation: { validator: captcha, message: 'Please check.' }
}),
submit: function () {
if (viewModel.errors().length == 0) {
alert('Thank you.');
} else {
alert('Please check your submission.');
viewModel.errors.showAllMessages();
}
}
};
viewModel.confirmPassword = ko.observable().extend({
validation: { validator: mustEqual, message: 'Passwords do not match.', params: viewModel.password }
}),
viewModel.errors = ko.validation.group(viewModel);
viewModel.requireLocation = function () {
viewModel.location.extend({ required: true });
};
ko.applyBindings(viewModel);

Related

Use Devextreme js Widget in ASP.NET Core

I'm trying to find a way to use Devextreme RadioGroup js widget with ASP.NET Core.
I've created this simple View:
<form asp-action="SelectSourceData" asp-controller="Home" method="post">
<div class="form-group">
<label for="rg-mode">Please Choose Migration Mode</label>
<div id="rg-mode"></div>
</div>
<button type="submit" class="btn btn-primary">Proceed</button>
</form>
#section Scripts {
<script>
$(function () {
$("#rg-mode").dxRadioGroup({
dataSource: modes,
displayExpr: "text",
valueExpr: "val",
value: "by-org"
})
});
var modes = [
{ text: "By Organisation", val: "by-org" },
{ text: "By Contract Type", val: "by-contr" },
{ text: "By Employee", val: "by-emp" },
{ text: "Mixed Mode", val: "mm" }
];
</script>
}
When user presses Proceed button SelectSourceData action method is invoked:
[HttpPost]
public ViewResult SelectSourceData(string val)
{
// get selected value here ... ?
return View();
}
My question is: is it possible to somehow obtain the value selected in dxRadioGroup widget?
Following #Stephen's advice I added a hidden input field:
<div class="form-group">
<input id="hdnMode" name="mode" type="hidden" value="by-org" class="form-control" />
<label for="rg-mode">Please Choose Migration Mode</label>
<div id="rg-mode"></div>
</div>
and registered a handling function for value changed event:
$(function () {
$("#rg-mode").dxRadioGroup({
dataSource: modes,
displayExpr: "text",
valueExpr: "val",
value: "by-org",
onValueChanged: function (e) {
var previousValue = e.previousValue;
var newValue = e.value;
// Event handling commands go here
$("#hdnMode").val(newValue);
}
})
});
The action method now correctly obtains the value submitted by the form:
[HttpPost]
public ViewResult SelectSourceData(string mode)
{
// mode argument successfully set to submitted value
var t = mode;
....

Knockout-Validation Show Template before input

I have a simple JSFiddle example http://jsfiddle.net/b625zeL5/6/
<script>
ko.validation.init({
registerExtenders: true,
messagesOnModified: true,
insertMessages: false,
parseInputAttributes: true,
messageTemplate: 'errorTemplate',
decorateInputElement: true,
errorElementClass: 'error'
}, true);
var ViewModel = function(){
this.email = ko.observable("")
.extend({ required: true })
.extend({ email: true });
this.password = ko.observable("")
.extend({ required: true });
};
var viewModel = new ViewModel();
viewModel.errors = ko.validation.group(viewModel);
ko.applyBindings(viewModel);
</script>
<form>
<span data-bind="validationMessage: email"></span>
<input type="text" id="email" data-bind="value: email, validationElement: email, valueUpdate:'keyup'" /> <br/>
<span data-bind="validationMessage: password"></span>
<input type="text" id="password" data-bind="value: password, validationElement: password, valueUpdate:'keyup'"/>
</form>
<script type="text/html" id="errorTemplate">
Error: <span data-bind="validationMessage: field">X</span>
</script>
As you can see - I disabled insertMessages because I need error messages to show before input field. Thus I added span with "data-bind="validationMessage: email"" before each text input.
I defined in validation config
messageTemplate: 'errorTemplate'
but error messages still plain text. How can I get messageTemplate to work?
Because you turned off insertMessages, knockout validation won't use your error message template and it will use what you inserted above each field.
You have two options:
For each observable that has a validation, add a custom error message.
Example 1:
this.password = ko.observable("")
.extend({ required: {
params: true,
message: "Error: This is required"
}
});
Change your error template to something like this:
Example 2:
<script type="text/html" id="errorTemplate">
Error: <span data-bind="validationMessage: error_field"></span>
</script>
.. and inside the form, you can call the template like:
<form>
<!-- ko template: { name: 'errorTemplate', data: { error_field: email } }-->
<!-- /ko -->
<input type="text" id="email" data-bind="value: email, validationElement: email, valueUpdate:'keyup'" /> <br/>
...
...
see jsfiddle here with example 2 in action : http://jsfiddle.net/mhgv48e8/
Hope it helps :)

are jqueryvalidation rules using OR possible?

I'm creating a small jquery mobile project and have decided to use jqueryvalidation http://jqueryvalidation.org/ for form validation. I have a popup box where the user enters a number which is either their phone or email (unfortunately this has to stay like this because of the database) so I want to use the validation to say that the field must either contain email: or digits:.
Do you know if this is possible? Or a workround? Using depends: won't work either in this case as there is no conditional that will work on every database (the primary phone/email will not always be filled).
<form id='addNumber' action ='' method='post' data-ajax='false'>
<div class="ui-field-contain">
<label for="phoneType">Type</label>
<select name="phoneType" id="phoneType" data-native-menu="false">
<?php echo $phoneInnerOptions; ?>
</select>
</div>
<div class="ui-field-contain">
<label for="phoneNumber">Number</label>
<input type="text" name="phoneNumber" id="phoneNumber" value="">
</div>
<div class="ui-field-contain">
<label for="primary">Primary Contact</label>
<select name="primary" id="primary" data-native-menu="false" >
<option value="1">Primary Phone</option>
<option value="2">Primary Email</option>
<option value="3"></option>
</select>
</div>
<div class='ui-grid-a'>
<div class='ui-block-a'><input type='submit' value='Update' class='ui-btn ui-btn-inline' data-transition='pop' /></div>
<div class='ui-block-b'><a href='#' id="addNumberReset" class='ui-btn' data-rel='back' data-transition='pop'>Cancel</a></div>
</div>
</form>
And the current validation:
$().ready(function() {
// validate add number form
$("#addNumber").validate({
errorPlacement: function(error, element) {
error.insertAfter(element.parent()); // <- make sure the error message appears after parent element (after textbox!)
},
rules: {
phoneNumber: "required",
},
messages: {
phoneNumber: "Please enter a valid phone or email",
}
}); //end validate
});// end function
Any help or advise with this one would be appreciated :)
Your best option in this case is to just write your own rule using the .addMethod() method.
simple example from docs:
jQuery.validator.addMethod("myrule", function(value, element) {
// return 'true' to pass validation or return 'false' to fail validation
return this.optional(element) || /^http:\/\/mycorporatedomain.com/.test(value);
}, "Please specify the correct domain for your documents");
markup to declare this example rule:
rules: {
myfield: {
myrule: true // only passes validation if "http://mycorporatedomain.com" is entered
}
}
simple example from docs using parameters:
jQuery.validator.addMethod("myrule", function(value, element, params) {
// return 'true' to pass validation or return 'false' to fail validation
return this.optional(element) || value == params[0] + params[1];
}, jQuery.validator.format("Please enter the correct value for {0} + {1}"));
markup to declare this example rule:
rules: {
myfield: {
myrule: [5,20] // only passes validation if '25' is entered
}
}
this.optional(element) in both examples makes the field entry "optional". If you also want the field required, just remove this part.
You can browse through the additional-methods.js file to see dozens of real working examples of this method.
Heres the code I ended up using incase anyone else might need it.. thanks for the help on this one sparky
//creating the new rule
//Matches UK landline + mobile, accepting only 01-3 for landline or 07 for mobile to exclude many premium numbers
jQuery.validator.addMethod('phonesUK', function(phone_number, element) {
phone_number = phone_number.replace(/\(|\)|\s+|-/g,'');
return this.optional(element) || phone_number.length > 9 &&
phone_number.match(/^(?:(?:(?:00\s?|\+)44\s?|0)(?:1\d{8,9}|[23]\d{9}|7(?:[45789]\d{8}|624\d{6})))$/);
});
//use phonesUK or standard email
jQuery.validator.addMethod("phoneOrEmail", function(value, element) {
return this.optional(element) ||
($.validator.methods["phonesUK"].call(this, value, element)) ||
($.validator.methods["email"].call(this, value, element));
}, "Please enter a valid phone number or email address");
//apply it to my page
$(document).on("pagecreate", function () {
// validate new number form
$("#addNumber").validate({
errorPlacement: function(error, element) {
error.insertAfter(element.parent()); // <- make sure the error message appears after parent element (after textbox!)
},
rules: {
phoneNumber:
{
phoneOrEmail: true,
required: true,
}
},
messages: {
phoneNumber: "Please enter a valid phone number or email address",
},
//check if valid - post if is
submitHandler: function(form) {
$('#PopUpAddNumber').popup('close');
$.post("customer_AddNewNumber.php", $("#addNumber").serialize(), function(response)
{
LoadCustomerNumber();
});
}
}); //end validate
//reset form after validate
$('#addNumberReset').click(function () {
$('#addNumber').validate().resetForm();
});
}); // end function

knockout-kendo widgets with knockout validation not working

I need to implement knockout validation with knockout-kendo.
I have this html:
<textarea class="k-textbox" data-bind="value: description"></textarea>
<input data-bind="kendoComboBox: {
data: myOptions,
value:myOptionId,
dataTextField: 'MyOptionName',
dataValueField: 'MyOptionId'}"/>
<input data-bind="kendoDatePicker: {value: dueDate}"/>
Javascript:
...
viewModel: {
description: ko.observable('').extend({ required: true }),
dueDate: ko.observable('').extend({ required: true }),
myOptions: ko.observableArray([]),
myOptionId: ko.observable('').extend({ required: true })
}
...
ko.applyBindingsWithValidation(self.viewModel, $ctx[0]);
The validation works fine for the description field, bound to the text area; but it doesn't work for the comboBox or the datePicker.
I have checked the documentation, and also this jsFiddle, but I haven't been able to get it to work.
Any help would be greatly appreciated.
It looks like the issue is that the <span class="validationMessage" data-bind="validationMessage: dueDate"></span> doesn't get automatically generated for knockout-kendo tags. Just add a tag per knockout-kendo element, ex:
<input data-bind="kendoComboBox: {
data: myOptions,
value:myOptionId,
dataTextField: 'MyOptionName',
dataValueField: 'MyOptionId'}"/>
<span class="validationMessage" data-bind="validationMessage: value:myOptionId"></span>
<input data-bind="kendoDatePicker: {value: dueDate}"/>
<span class="validationMessage" data-bind="validationMessage: dueDate"></span>
Remember to put before your view model:
ko.validation.configure({
registerExtenders: true,
messagesOnModified: true,
insertMessages: true,
parseInputAttributes: true,
messageTemplate: null
});
ko.validation.registerExtenders();

Validate on Blur

I've created a JSFiddle to help demonstrate my question: http://jsfiddle.net/jeffreyrswenson/CrYWn/5/
Here's what I'd like to see:
Messages should not appear when page loads.
Messages should appear when submit button is pushed.
Messages should appear after input value is changed and user leaves element. (Tabs or clicks to next field)
Messages should appear after user leave an input without changing.(For example a field is required and the user tabs through the field, but doesn't enter a value. I'd like the validation message to appear when this happens.)
The first four work as I'd expect. Is the last item possible and if so, what do I need to change to enable that behavior?
HTML:
<label>First name:
<input data-bind='value: firstName' />
</label>
<br/>
<label>Last name:
<input data-bind='value: lastName' />
</label>
<br/>
<button type="button" data-bind='click: submit'>Submit</button>
<br/>
<span data-bind='text: errors().length'></span> errors
ViewModel:
var viewModel = function () {
ko.validation.configure({
decorateElement: true,
registerExtenders: true,
messagesOnModified: true,
insertMessages: true,
parseInputAttributes: true,
messageTemplate: null
});
this.firstName = ko.observable().extend({
required: true
});
this.lastName = ko.observable().extend({
required: true,
pattern: {
message: 'Hey this doesnt match my pattern',
params: '^[A-Z0-9]+$'
}
});
this.submit = function () {
if (this.errors().length == 0) {
alert('Thank you.');
} else {
this.errors.showAllMessages();
}
};
this.errors = ko.validation.group(this);
};
You just need to use the standard valueUpdate option of the value binding where you can specify additional events to trigger your property change and with that the validation.
So you just need to add the valueUpdate: "blur" setting on your bindings:
<label>First name:
<input data-bind='value: firstName, valueUpdate: "blur"' />
</label>
<br/>
<label>Last name:
<input data-bind='value: lastName, valueUpdate: "blur"' />
</label>
Demo JSFiddle.
In my case, I needed the value to update after key down because I was making some fields visible if the input had a value. I wanted the underlying value to update but didn't want the validation to show until the user tabbed to the next input.
A bit of CSS and a couple of bindings is what worked for me:
CSS:
div.validationWrapper.standard-focus.has-focus .validationMessage
{
display: none;
}
HTML:
<div class="validationWrapper standard-focus" data-bind="css: { 'has-focus': MyObservableHasFocus() }">
<input class="standard-focus" type="text" data-bind="hasFocus: MyObservableHasFocus, value: MyObservable, valueUpdate: 'afterkeydown'" />
</div>
Knockout:
self.MyObservable = ko.observable('').extend({/* Your validation here */});
self.MyObservableHasFocus = ko.observable(false);
The result is an observable that updates it's value after key up and shows the validation message after it loses focus.

Resources