Run script on loading DropDownListFor - ajax

I have a view with the following line of code:
#Html.DropDownListFor(m => m.FrequencyTypes, (List<SelectListItem>)ViewBag.FreqTypes, null, new { #onchange = "toggleOptionalDisplay(this.value)", #class = "form-control" })
This works great for when the drop down is changed but I can't work out how to run the script when the drop down is first loaded.

I got this working by changing the drop down to:
#Html.DropDownListFor(m => m.FrequencyTypes, (List<SelectListItem>)ViewBag.FreqTypes, null, new { #onchange = "toggleOptionalDisplay(this.value)", #class = "form-control", #id = "freqtype", #style = "width:300px;" })
and adding the following extra script (which calls my original function):
<script>
$(document).ready(function () {
toggleOptionalDisplay($("#freqtype").val());
})
</script>

I think this could helped you, but this approach uses jQuery
$(document).ready(function() {
$('select[name="FrequencyTypes"]').change();
});

Related

toastr js is not showing toasts

I am using toastr.js for notification, my drop down code is
<%= Html.DropDownListFor(m => m.MakeText, Model.MakeSelect, string.Empty, new { data_bind = "optionsText: Make,value: Make", Id = "ddMake", style = "width: 200px;font-size: 20px" })%>
and in site typescript is
$(document).ready(function () {
viewModel.Make.subscribe(function (item) {
item && toastr.success('selected make');
});
)}
but problem is i can not see toasts, once i implement only
toastr.success('selected make')
its work good, Can you please tell me what is the issue in subscribe code.
Thanks
item is falsy. That would mean item && toastr.success('selected make'); gets short-circuited and toastr.success('selected make'); is never evaluated.

Knockout.js wizard validation on each step

I have managed to create a simple wizard based on an answer given by Niemeyer. This works fine. I want to add validation. I have managed to add a required validion on the field Firstname. Leaving this empty displays an error. But what I could not succeed in is the following:
Validate the model in the current step, and have the go next enabled or disabled based whether there are errors. If it is too difficult to enable or disable the next button, that is ok. I can also live without the button disabled when there are errors. As long as the user is prevented to proceed to the next step when there are errors.
. My view looks like this:
//model is retrieved from server model
<script type="text/javascript">
var serverViewModel = #Html.Raw(Json.Encode(Model));
</script>
<h2>Test with wizard using Knockout.js</h2>
<div data-bind="template: { name: 'currentTmpl', data: currentStep }"></div>
<hr/>
<button data-bind="click: goPrevious, enable: canGoPrevious">Previous</button>
<button data-bind="click: goNext, enable: canGoNext">Next</button>
<script id="currentTmpl" type="text/html">
<h2 data-bind="text: name"></h2>
<div data-bind="template: { name: getTemplate, data: model }"></div>
</script>
<script id="nameTmpl" type="text/html">
<fieldset>
<legend>Naamgegevens</legend>
<p data-bind="css: { error: FirstName.hasError }">
#Html.LabelFor(model => model.FirstName)
#Html.TextBoxFor(model => model.FirstName, new { data_bind = "value: FirstName, valueUpdate: 'afterkeydown'"})
<span data-bind='visible: FirstName.hasError, text: FirstName.validationMessage'> </span>
</p>
#Html.LabelFor(model => model.LastName)
#Html.TextBoxFor(model => model.LastName, new { data_bind = "value: LastName" })
</fieldset>
</script>
<script id="addressTmpl" type="text/html">
<fieldset>
<legend>Adresgegevens</legend>
#Html.LabelFor(model => model.Address)
#Html.TextBoxFor(model => model.Address, new { data_bind = "value: Address" })
#Html.LabelFor(model => model.PostalCode)
#Html.TextBoxFor(model => model.PostalCode, new { data_bind = "value: PostalCode" })
#Html.LabelFor(model => model.City)
#Html.TextBoxFor(model => model.City, new { data_bind = "value: City" })
</fieldset>
</script>
<script id="confirmTmpl" type="text/html">
<fieldset>
<legend>Naamgegevens</legend>
#Html.LabelFor(model => model.FirstName)
<b><span data-bind="text:NameModel.FirstName"></span></b>
<br/>
#Html.LabelFor(model => model.LastName)
<b><span data-bind="text:NameModel.LastName"></span></b>
</fieldset>
<fieldset>
<legend>Adresgegevens</legend>
#Html.LabelFor(model => model.Address)
<b><span data-bind="text:AddressModel.Address"></span></b>
<br/>
#Html.LabelFor(model => model.PostalCode)
<b><span data-bind="text:AddressModel.PostalCode"></span></b>
<br/>
#Html.LabelFor(model => model.City)
<b><span data-bind="text:AddressModel.City"></span></b>
</fieldset>
<button data-bind="click: confirm">Confirm</button>
</script>
<script type='text/javascript'>
$(function() {
if (typeof(ViewModel) != "undefined") {
ko.applyBindings(new ViewModel(serverViewModel));
} else {
alert("Wizard not defined!");
}
});
</script>
The knockout.js implementation looks like this:
function Step(id, name, template, model) {
var self = this;
self.id = id;
self.name = ko.observable(name);
self.template = template;
self.model = ko.observable(model);
self.getTemplate = function() {
return self.template;
};
}
function ViewModel(model) {
var self = this;
self.nameModel = new NameModel(model);
self.addressModel = new AddressModel(model);
self.stepModels = ko.observableArray([
new Step(1, "Step1", "nameTmpl", self.nameModel),
new Step(2, "Step2", "addressTmpl", self.addressModel),
new Step(3, "Confirmation", "confirmTmpl", {NameModel: self.nameModel, AddressModel:self.addressModel})]);
self.currentStep = ko.observable(self.stepModels()[0]);
self.currentIndex = ko.dependentObservable(function() {
return self.stepModels.indexOf(self.currentStep());
});
self.getTemplate = function(data) {
return self.currentStep().template();
};
self.canGoNext = ko.dependentObservable(function () {
return self.currentIndex() < self.stepModels().length - 1;
});
self.goNext = function() {
if (self.canGoNext()) {
self.currentStep(self.stepModels()[self.currentIndex() + 1]);
}
};
self.canGoPrevious = ko.dependentObservable(function() {
return self.currentIndex() > 0;
});
self.goPrevious = function() {
if (self.canGoPrevious()) {
self.currentStep(self.stepModels()[self.currentIndex() - 1]);
}
};
}
NameModel = function (model) {
var self = this;
//Observables
self.FirstName = ko.observable(model.FirstName).extend({ required: "Please enter a first name" });;
self.LastName = ko.observable(model.LastName);
return self;
};
AddressModel = function(model) {
var self = this;
//Observables
self.Address = ko.observable(model.Address);
self.PostalCode = ko.observable(model.PostalCode);
self.City = ko.observable(model.City);
return self;
};
And I have added an extender for the required validation as used in the field Firstname:
ko.extenders.required = function(target, overrideMessage) {
//add some sub-observables to our observable
target.hasError = ko.observable();
target.validationMessage = ko.observable();
//define a function to do validation
function validate(newValue) {
target.hasError(newValue ? false : true);
target.validationMessage(newValue ? "" : overrideMessage || "This field is required");
}
//initial validation
validate(target());
//validate whenever the value changes
target.subscribe(validate);
//return the original observable
return target;
};
This was a tricky one, but I'll offer a couple of solutions for you...
If you simply want to prevent the Next button from proceeding with an invalid model state, then the easiest solution I found is to start by adding a class to each of the <span> tags that are used for displaying the validation messages:
<span class="validationMessage"
data-bind='visible: FirstName.hasError, text: FirstName.validationMessage'>
(odd formatting to prevent horizontal scrolling)
Next, in the goNext function, change the code to include a check for whether or not any of the validation messages are visible, like this:
self.goNext = function() {
if (
(self.currentIndex() < self.stepModels().length - 1)
&&
($('.validationMessage:visible').length <= 0)
)
{
self.currentStep(self.stepModels()[self.currentIndex() + 1]);
}
};
Now, you may be asking "why not put that functionality in the canGoNext dependent observable?", and the answer is that calling that function wasn't working like one might thing it would.
Because canGoNext is a dependentObservable, its value is computed any time the model that it's a member of changes.
However, if its model hasn't changed, canGoNext simply returns the last calculated value, i.e. the model hasn't changed, so why recalculate it?
This wasn't vital when only checking whether or not there were more steps remaining, but when I tried to include validation in that function, this came into play.
Why? Well, changing First Name, for example, updates the NameModel it belongs to, but in the ViewModel, self.nameModel is not set as an observable, so despite the change in the NameModel, self.nameModel is still the same. Thus, the ViewModel hasn't changed, so there's no reason to recompute canGoNext. The end result is that canGoNext always sees the form as valid because it's always checking self.nameModel, which never changes.
Confusing, I know, so let me throw a bit more code at you...
Here's the beginning of the ViewModel, I ended up with:
function ViewModel(model) {
var self = this;
self.nameModel = ko.observable(new NameModel(model));
self.addressModel = ko.observable(new AddressModel(model));
...
As I mentioned, the models need to be observable to know what's happening to them.
Now the changes to the goNext and goPrevious methods will work without making those models observable, but to get the true real-time validation you're looking for, where the buttons are disabled when the form is invalid, making the models observable is necessary.
And while I ended up keeping the canGoNext and canGoPrevious functions, I didn't use them for validation. I'll explain that in a bit.
First, though, here's the function I added to ViewModel for validation:
self.modelIsValid = ko.computed(function() {
var isOK = true;
var theCurrentIndex = self.currentIndex();
switch(theCurrentIndex)
{
case 0:
isOK = (!self.nameModel().FirstName.hasError()
&& !self.nameModel().LastName.hasError());
break;
case 1:
isOK = (!self.addressModel().Address.hasError()
&& !self.addressModel().PostalCode.hasError()
&& !self.addressModel().City.hasError());
break;
default:
break;
};
return isOK;
});
[Yeah, I know... this function couples the ViewModel to the NameModel and AddressModel classes even more than simply referencing an instance of each of those classes, but for now, so be it.]
And here's how I bound this function in the HTML:
<button data-bind="click: goPrevious,
visible: canGoPrevious,
enable: modelIsValid">Previous</button>
<button data-bind="click: goNext,
visible: canGoNext,
enable: modelIsValid">Next</button>
Notice that I changed canGoNext and canGoPrevious so each is bound to its button's visible attribute, and I bound the modelIsValid function to the enable attribute.
The canGoNext and canGoPrevious functions are just as you provided them -- no changes there.
One result of these binding changes is that the Previous button is not visible on the Name step, and the Next button is not visible on the Confirm step.
In addition, when validation is in place on all of the data properties and their associated form fields, deleting a value from any field instantly disables the Next and/or Previous buttons.
Whew, that's a lot to explain!
I may have left something out, but here's the link to the fiddle I used to get this working: http://jsfiddle.net/jimmym715/MK39r/
I'm sure that there's more work to do and more hurdles to cross before you're done with this, but hopefully this answer and explanation helps.

MVC3 Text Box Text change Event

I have the following scenario, using mvc3:
I have a database table which holds a RecordID, RecordName and RecordType. Displayed are three text boxes, one for each of the fields mentioned previously.
My Question is, when i enter a RecordID into the relevant text box, i want to be able to show the RecordName and RecordType for that particular RecordID. How can i achieve this?
In View:
#Html.TextBoxFor(model => model.RecordId)
#Html.TextBoxFor(model => model.RecordName)
#Html.TextBoxFor(model => model.RecordType)
<script language="javascript">
$('#RecordId').change(function(){
var recordId = this.value;
$.getJSON("/MyController/GetRecordById",
{
id: recordId
},
function (data) {
$('RecordName').val(data.Name);
$('RecordType').val(data.Type);
});
});
</script>
In Controller:
public JsonResult GetRecordById(int id)
{
var record = recordRepository.GetById(id);
var result = new {
Name = record.Name,
Type = record.Type
}
return Json(result, JsonRequestBehavior.AllowGet);
}

#Html.DropDownList width

Q: How to set width for #Html.DropDownList (and not in css)?
#Html.DropDownList("ListId", String.Empty, new {style="width: 250px;"}) #* no go!*#
The second argument of the DropDownList helper must be an IEnumerable<SelectListItem>. You are passing a string (an empty one to be more precise). So in order to use this helper you will have to respect its signature:
#Html.DropDownList(
"ListId",
Enumerable.Empty<SelectListItem>(),
new { style = "width: 250px;" }
)
Obviously generating an empty dropdown list is of little use. You probably have a view model (you should by the way) that you want to use to bind to:
#Html.DropDownList(
"ListId",
Model.MyList,
new { style = "width: 250px;" }
)
and of course because you have a view model you should prefer to use the DropDownListFor helper:
#Html.DropDownListFor(
x => x.ListId,
Model.MyList,
new { style = "width: 250px;" }
)
and finally to avoid cluttering your HTML with styles you should use an external CSS:
#Html.DropDownListFor(
x => x.ListId,
Model.MyList,
new { #class = "mycombo" }
)
where in your external CSS you would define the .mycombo rule:
.mycombo {
width: 250px;
}
Now you have what I consider a proper code.
You should use the View Model approach. However the lazy way out is just to give the 2nd parameter a null.
#Html.DropDownList("ListId", null, new {style="width: 250px;"})
#Html.DropDownListFor(model => model.Test,
new SelectList(new List<YourNamespace.Modelname>(), "Id", "Name"),
null, new { #id = "ddlTest", #style="width: 250px;" })
There is a jquery technique that allows you to set the width without having to deal with the #Html.DropDownList constructor.
<script language="javascript" type="text/javascript">
$(document).ready(function () {
$("#ListId").width(300);
});
</script>

jQuery unobtrusive validation in .NET MVC 3 - showing success checkmark

Using jQuery unobtrusive validation within a .NET MVC project and that seems to be working fine. I'm now trying to show a green checkmark when the field validates correctly (client-side and/or remote).
Here's a sample field declaration:
<div class="clearfix">
#Html.LabelFor(model => model.Address1, "Street")
<div class="input">
#Html.TextBoxFor(model => model.Address1, new { #class = "xlarge", #maxlength = "100", #placeholder = "e.g. 123 Main St" })
<span class="help-message">
#Html.ValidationMessageFor(model => model.Address1)
<span class="isaok">Looks great.</span>
</span>
<span class="help-block">Enter the street.</span>
</div>
</div>
What I'd like to do is add a class 'active' to the "span.isaok" which in turn has a checkmark for a background image.
I tried using highlight/unhighlight:
$.validator.setDefaults({
onkeyup: false,
highlight: function (element, errorClass, validClass) {
$(element).addClass(errorClass).removeClass(validClass);
$(element.form).find("label[for=" + element.id + "]").addClass("error");
$(element).parent().find("span.isaok").removeClass("active");
},
unhighlight: function (element, errorClass, validClass) {
$(element).removeClass(errorClass).addClass(validClass);
$(element.form).find("label[for=" + element.id + "]").removeClass("error");
if ($(element).val().length > 0) {
$(element).parent().find("span.isaok").addClass("active");
}
}
});
but that shows a green checkmark for all fields even if they're empty! (hence obviously wrong)
I then tried using the 'success' option but that never seems to be fired.
What am I missing?
Edit: So I found this blog post and was able to tap into the success function i.e.
$(function () {
var settings = $.data($('form')[0], 'validator').settings;
settings.onkeyup = false;
settings.onfocusout = function (element) { $(element).valid(); };
var oldErrorFunction = settings.errorPlacement;
var oldSuccessFunction = settings.success;
settings.errorPlacement = function (error, inputElement) {
inputElement.parent().find("span.isaok").removeClass("active");
oldErrorFunction(error, inputElement);
};
settings.success = function (label) {
var elementId = '#' + label.attr("for");
$(elementId).parent().find("span.isaok").addClass("active");
oldSuccessFunction(label);
};
});
but now if the form isn't valid it shows both the error message and the valid mark...
and the latter disappears as soon as I click anywhere on the page.
This appears to be an issue with the jquery.validate.unobtrusive interfering with the settings added later in $.validator.setDefault. The trick is to load the unobtrusive script after the custom settings. See here and vote to fix it here.
In case any one has a similar problem, I finally got this working by using the un-minified version of jquery.validate.unobtrusive.js and adding my js to the onError and onSuccess methods. Existing code was left as it. Use the re-minified version during deployment.
Thanks.
This is not a direct answer to your question. I am going to offer an alternative approach to this: TwitterBootstrapMVC.
With this library all you'd have to write for each input is:
#Html.Bootstrap().ControlGroup().TextBoxFor(m => m.Address1)
And that's it. You will have label, input, and validation message - all taken care of, without javascript. It generates proper html mark up for you. You just need to make sure that you have proper standard css for classes like .field-validation-error, .field-validation-valid...

Resources