MVC3 C# TextArea/CkEditor validation issue - asp.net-mvc-3

I have an MVC3 C# .Net Web App. We are using the ckEditor library to enhance the TextAreas in our app. When using a standard TextArea, the Validation operates correctly. However, in the enhanced TextAreas (implementing the ckEditor), when submitting the page, the Validation fires an error. "Description is Required" even when though there is data present in the TextArea. Upon a second click of the Submit, the form submits fine.
Domain class property:
[Display(Name = "Description")]
[Required(ErrorMessage = "Description is required.")]
public virtual string Description { get; set; }
HTML:
<td style="border: 0;text-align:left " >
#Html.TextAreaFor(model => model.Description,
new
{
rows = 5,
cols = 100,
#class = "celltext2 save-alert"
})
#Html.ValidationMessageFor(model => model.Description)
</td>
I think that applying the ckEditor attributes is messing it up somehow. Ideas?`
Let me clarify more. We have a .js file that queries the controls and then does ckEditor initialzation. when I remove the $(this).ckeditor({}) it works fine.
JS File:
$('textarea').each(function () {
$(this).ckeditor({});
});

Something like this might work:
$('textarea').each(function () {
var textarea = $(this);
$(this).ckeditor({}).on('blur', function() {
textarea.html( $(this).html() );
});
});
EDIT(I've never used the jQuery adapter, after a small lesson I found this to work, the above the blur never fires and $(this).html() is not defined):
$('textarea').each(function () {
var textarea = $(this);
textarea.ckeditor(function () {
textarea.ckeditorGet().on('blur', function () {
textarea.html( this.getData() );
});
});
});

I think it's a little simpler than that. CKE creates an iframe that it is used instead of the actual textarea and you do correctly need to update the contents of the textarea with the data inside CKEditor before submitting. I would suggest, however, that you do this on submit instead of on blur. I would recommend setting an id to the relevant DOM elements but you get the idea.
// Replace textarea(s)
$('textarea').each(function () {
$(this).ckeditor({});
});
// Bind on submit event to update the text
$('form').submit(function() {
// Upate textarea value with the ckeditor data
$('textarea').val(CKEDITOR.instances.ValueCKE.getData());
});

Related

Is there a way to use AJAX on a DropDownList changed event to dynamically modify a partial view on a page?

Is there a way to use AJAX on a DropDownList changed event to dynamically modify a partial view on a page?
My main page has a DropDownList (DropDownListFor) and a partial view which ONLY contains a list of "items". The items shown in this partial view are dependent upon the item selected in the DropDownList. There's a 1 to many relationship between the DropDownList item and the items in the partial view. So, when the user changes the value of the DropDownList, the content in the partial view will dynamically change to reflect the item selected in the DropDownList.
Here's my DropDownList:
<div data-role="fieldcontain">
Choose Capsule:<br />
#Html.DropDownListFor(x => x.CapsuleFK, new SelectList(Model.Capsules, "pk", "name", "pk"), new { id = "ddlCapsules" })
<br />
</div>
Here's my Partial View declaration on the same page:
<div data-role="fieldcontain">
#Html.Partial("_FillerPartial", Model.Fillers)
</div>
I'm not very familiar with Ajax, but looking at other examples, here's what I have for my Ajax:
$(document).ready(function () {
$('#ddlCapsules').change(function () {
// make ajax call to modify the filler list partial view
var selection = $('#ddlCapsules').val();
var dataToSend = { cappk: selection };
$.ajax({
url: 'Process/GetFillersByCapsule',
data: { cappk: dataToSend },
success: function (data) {
alert("server returned: " + data);
}
});
});
});
And finally, here's a screenshot of what's going on. By changing the "Choose Capsule" drop down list, I want the Filler list to update dynamically:
You can load the drop down list as a partial view from the controller using ajax.
The controller code:
[HttpGet]
public virtual ActionResult GetFillersByCapsule(string cappk)
{
var model = //Method to get capsules by pk, this returns a ViewModel that is used to render the filtered list.
return PartialView("PartialViewName", model);
}
The main view html:
<div id="filteredList">
</div >
The partial view
#model IEnumerable<MyCapsuleModel>
foreach (var x in Model)
{
//Render the appropriate filtered list html.
}
And you can load the filtered list using ajax:
$('#ddlCapsules').change(function () {
// make ajax call to modify the filler list partial view
var selection = $('#ddlCapsules').val();
var dataToSend = { cappk: selection };
$.ajax({
url: 'Process/GetFillersByCapsule',
data: { cappk: dataToSend },
success: function (data) {
$("#filteredList").empty();
$("#filteredList").html(data);
}
});
});
Hope this helps.
You can't update the partial, per se, because the partial will never be rendered again without a page reload. Once you receive the HTML, ASP is done, you're on your own at that point.
What you can do, of course, is switch out the content of a particular div or whatever using JavaScript. Your example in particular screams Knockout, so that's what I would recommend using.
Change your HTML to add a data-bind to your containing div:
<div data-role="fieldcontain" data-bind="foreach: filler">
<button data-bind="text: name"></button>
</div>
And your DropDownList:
#Html.DropDownListFor(x => x.CapsuleFK, new SelectList(Model.Capsules, "pk", "name", "pk"), new { id = "ddlCapsules", data_bind = "event: { change: updateFillers }" })
Then, some JavaScript:
var FillersViewModel = function () {
var self = this;
self.fillers = ko.observableArray([]);
self.updateFillers = function () {
var selection = $('#ddlCapsules').val();
var dataToSend = { cappk: selection };
$.ajax({
url: 'Process/GetFillersByCapsule',
data: { cappk: dataToSend },
success: function (data) {
self.fillers(data.fillers) // where `fillers` is an array
}
});
}
}
var viewModel = new FillersViewModel();
ko.applyBindings(viewModel);
This is a very simplistic example, and you'll need to do some more work to make it do everything you need it to do in your scenario, but the general idea is that every time the dropdown list is changed, Knockout will call your updateFillers method, which will execute the AJAX and put new data into the fillers observable array. Knockout automatically tracks changes to this array (hence the "observable" part), so an update is automatically triggered to any part of your page that relies on it. In this scenario, that's your div containing the buttons. The foreach binding will repeat the HTML inside for each member of the array. I've used a simple button element here just to illustrate, but you would include the full HTML required to create your particular button like interface. The text binding will drop the content of name in between the opening and closing tag. Refer to: http://knockoutjs.com/documentation/introduction.html for all the binding options you have.
There's much more you could do with this. You could implement templates instead of hard-coding your HTML to be repeated in the foreach. And, you can use your partial view to control the HTML for this template. The important part is that Knockout takes the pain out of generating all this repeating HTML for you, which is why I recommend using it.
Hope that's enough to get you started.

How to properly disable an Html Helper Textbox or TextBoxFor?

I have a razor display that is being used for entry. In one case, I would like the user to be able to populate the text box, in the other case, I would like to prevent the user from populating it. I am using code like:
#Html.TextBoxFor(model => model.Goop, new { #class = "text-box", maxlength = 2, onfocus = "javascript:this.select();" })
if (Model.Review.ReviewType.Equals("M"))
{
<script type="text/javascript">
$(function () {
$("#Goop").prop("disabled", true);
});
</script>
}
I have tried to do this several ways, jQuery (above), CSS attribs, javascript, ASP.NET... but all have the same issue: When the form is submitted, if the Goop textbox is disabled, the value for Goop in the model is Null. Ideas?
Thanks in advance!
Maybe it's not as cool without jQuery, but when I do this in my apps I do something along the lines of
if (Model.Review.ReviewType.Equals("M"))
{
#Html.DisplayFor(model => model.Goop)
#Html.HiddenFor(model => model.Goop)
}
else
{
#Html.TextBoxFor(model => model.Goop)
}
If a form element is disabled, it does not post a value. That's how it's supposed to work.
To work around this, you will need to do one of several things. You can enable the fields just before posting by intercepting the submit method. You can use a hidden field to store the data in addition to the disabled control. Or you can just assume the values on the controller side.
by the way, it should be .prop("disabled", "disabled"), which renders as disabled="disabled", that's standards compliant.

Avoiding Duplicate form submission in Asp.net MVC by clicking submit twice

I am rendering a form in Asp.net MVC with a submit button. The page redirects after successful record addition into the database. Following is the code :-
[HttpPost]
public ActionResult Create(BrandPicView brandPic)
{
if (ModelState.IsValid)
{
if (!String.IsNullOrEmpty(brandPic.Picture.PictureUrl))
{
Picture picture = new Picture();
picture.PictureUrl = brandPic.Picture.PictureUrl;
db.Pictures.Add(picture);
brandPic.Brand.PictureId = picture.Id;
}
db.Brands.Add(brandPic.Brand);
db.SaveChanges();
return RedirectToAction("Index");
}
return View();
}
But, while testing, I saw that if the form is clicked again and again, the multiple entries are submitted and saved into the database.
How can i make sure that if the form has been submitted once to the server, then no duplicates are submitted.
I don't think this is quite a duplicate of the answer referenced in the comment, since the link is for spring MVC, and this question is for .NET MVC.
I actually spent a few hours on this a while back, and came up with the following. This javascript hooks nicely with the unobtrusive jquery validation, and you can apply it to any form that has <input type="submit". Note that it uses jquery 1.7's on function:
$(document).on('invalid-form.validate', 'form', function () {
var button = $(this).find(':submit');
setTimeout(function () {
button.removeAttr('disabled');
}, 1);
});
$(document).on('submit', 'form', function () {
var button = $(this).find(':submit');
setTimeout(function () {
button.attr('disabled', 'disabled');
}, 0);
});
The setTimeouts are needed. Otherwise, you could end up with a button that is disabled after clicked even when client-side validation fails. We have this in a global javascript file so that it is automatically applied to all of our forms.
Update 16 Nov 2020 by #seagull :
Replaced selector input[type="submit"] with :submit so it will work with <button type="submit" /> as well
The solution for mvc applications with mvc client side validation should be:
$('form').submit(function () {
if ($(this).valid()) {
$(':submit', this).attr('disabled', 'disabled');
}
});
Disable the button on Submit clicked. This can be done using JQuery/Java Script.
Look at this example on how to do this.
You can use this one. It includes unobtrusive jQuery validation.
$(document).on('submit', 'form', function () {
var buttons = $(this).find('[type="submit"]');
if ($(this).valid()) {
buttons.each(function (btn) {
$(buttons[btn]).prop('disabled', true);
});
} else {
buttons.each(function (btn) {
$(buttons[btn]).prop('disabled', false);
});
} });
For jQuery validation please incllude
~/Scripts/jquery.validate.min.js
~/Scripts/jquery.validate.unobtrusive.min.js
You can use ajax.BeginForm insted of html.BeginForm to achieve this, if you use OnSuccess insted of OnBegin you can be sure that your method execute successful and after that your button turn to deactivate,with ajax you stay
in current view and you can update your current view instead of redirection
#using (Ajax.BeginForm(
new AjaxOptions
{
HttpMethod = "post",
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "dive",
OnBegin="deactive"
}))
{
//body of your form same as Html.BeginForm
<input type="submit" id="Submit" value="Submit" />
}
and use this jquery in your form:
<script type="text/javascript" language="javascript"> function deactive() { $("#Submit").attr("disabled", true); }</script>
be careful for using ajax you have to call this scrip in the end of your page
<script src="~/Scripts/jquery.unobtrusive-ajax.js"></script>
Disabling the button is fine via JavaScript but what if the user has it disabled or they bypass it? If you use client side security then back it up with server side. I would use the PRG pattern here.
window.onload = function () {
$("#formId").submit(function() {// prevent the submit button to be pressed twice
$(this).find('#submitBtnId').attr('disabled', true);
$(this).find('#submitBtnId').text('Sending, please wait');
});
}

Passing strongly type form model data in asp.net mvc through jquery

It is easy to submit form to an action method in the controller which has strongly typed textboxes for example, with a submit button, but what if I want to send the exact same form with the strongly typed textboxes through jquery perhaps the $.ajax call after something else has been clicked.
code like this:
#Html.TextBoxFor(m => m.topTenFav.YoutubeLink,new { id="youTubeLinkTxt"})
does all the work for us and it's very simple to map the properties of our object in the controller
[HttpPost]
public ActionResult AddTopTenFav(HomeViewModel topTen)
{
topTen.topTenFav.Date = DateTime.Now;
topTen.topTenFav.UserName = User.Identity.Name;
repository.AddTopTen(topTen);
repository.Save();
return RedirectToAction("Index");
}
How would I send this form to the controller, map the textboxes in the form to object's properties on a click event such as
$("#btnAddGenre").click(function () {}
#using (Html.BeginForm(
"AddTopTenFav", "Home", FormMethod.Post, new { id = "AddTopTenFavForm" }))
{
<span id="youTubeLinkSpan">Youtube Link</span>
<div>
#Html.TextBoxFor(m => m.topTenFav.YoutubeLink,new { id="youTubeLinkTxt"})
</div>
<span id="youTubeNameSpan">Song Title</span>
<div>
#Html.TextBoxFor(m => m.topTenFav.Title,new { id="youTubeNameTxt"})
</div>
<button type="submit" name="btnSubmit" value="">submit</button>
}
You can do the following post:
$(document).ready(function(){
$('#btnAddGenre').click(function () {
$.post(
$('#AddTopTenFavForm').attr('action'),
$('#AddTopTenFavForm').serialize,
function (data) {
window.location = #Url.Action("Index");
},
'html' // returned data type
);
});
});
I use the html data type so you can return whatever you want and the redirect occurs on the window.location using the #Url.Action to give the location.
Please if it work mark as accepted answer
yes you can post the data of strongly typed textboxex using jquery.
First you have to do
take the values of all the textboxex in jquery using the below code.
var xx= $("#xx").val();
this will give the val in xx from your mvc text box.
Then by using jquery ajax call you can call the action method.
the code is below.
$.get("/XXXX/YY/1", { xxName: xx }, function (data) {
var status = data;
alert(status);
if (status) {
return true;
}
else {
alert("The book with this name is already present. TRY DIFFERENT NAME!")
return false;
}
});
here xxxx is controller amd yy is action method name.the next parameter is the value of all the textboxes which you want to send as an parameter.
This will perform the ajax call and return the value.
Please tell me if you find any problem the i will give the whole code.

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