I have a MVC 5 normal application.
In a textbot user need to write ad username (or maybe "name surname"). I use the [Remote] Annotation and a Validation function on controller is called.
Into the Validation function I make a LDAP query and if I find only 1 result I give true to validation, otherwise if nothing found or more than 1 result is found I return false.
Until here, there is no problem.
If validation is ok, I would to set the textbox value (or maybe an hidden value) with the exact AD username.
For example:
In my domain there is user marco.rossi, and is the only Marco in AD.
If I search "Marco" in AD validation is ok. But When user will submit I want pass domain\marco.rossi.
So I would set into an hidden or better change the textbox value from marco to domain\marco.rossi.
How I can set Textbox value into validation function?
Thank you in advance.
OK, after a lot of search, the solution is not the BEST solution, but it's working.
I read this post: http://www.garethelms.org/2011/01/asp-net-mvc-remote-validation-what-about-success-messages/
Gareth suggest to modify the jquery.validate.js
After the "hack", for every REMOTE validation, is called a javascript function that have {Action name}_response name.
So for this:
[Required]
[Remote("CheckADUserValidation", "CONTROLLER")]
public virtual string ad_username { get; set; }
I provided this function: (in the script section of the view)
function CheckADUserValidation_response(bIsValid, aErrors, oValidator)
{
// I disable immediatly the submit button to wait the right username
// so, also if validation is ok, I cannot submit until the right value is on the ad_username textbox
$('#btnSubmit').attr('disabled', 'disabled');
if (bIsValid == true) {
// after I call an Ajax on an Action, that instead of giving me true or error messages, give me the username
$.ajax({
type: "GET",
dataType: 'json',
url: '/CONTROLLER/ActionToHaveUsername/',
contentType: 'application/json;charset=UTF-8;',
async: true,
data: 'ad_username=' + $('#ad_username').val(),
success: function (response) {
if (response != '') {
// Ok there is the response
$('#ad_username').val(response);
$('#btnSubmit').removeAttr('disabled');
return true;
} else {
$('#btnSubmit').attr('disabled', 'disabled');
return false;
}
},
error: function (jqXHR, textStatus, errorThrown) {
alert(textStatus);
},
complete: function (jqXHR, textStatus) {
}
});
} else {
return false;
}
}
And this is the Action called on the Controller:
public JsonResult ActionToHaveUsername(string ad_username)
{
string tmpADName;
JsonResult tmpResult = new JsonResult();
// this function make the dirty work to take in input a name and search for unique ActiveDirectory Username, and return me in tmpADNName
AppGlobals.functions.CheckADUserValidation(ad_username, out tmpADName);
tmpResult.Data = tmpADName;
tmpResult.JsonRequestBehavior = JsonRequestBehavior.AllowGet;
return tmpResult;
}
The best result is encapsulating the ajax request into a timer that fires after 500ms, because I notice that sometimes the remote validation start also while writing on textbox.
So, for every character an async validation start, but when the validation return ok, the submit button is disabled and after 500ms the second request start and change the name for username. Every new character reset the timer, so only the last character fires really the second ajax.
At the end... 2 ajax is not the best scenario, but I really tried to use the JsonResult to have more data in return without lose the validation mechanism. But I don't find a way.
Related
I have a grid in kendo ui with batch editing and I need pass a array to my controller when user clicks update. I have the follow code:
index.jsp:
parameterMap: function(data, type) {
if (type != "read") {
data = data.models;
}
return data;
}
Controller.java:
#Post
#WithoutRoot
public void atualizar(List<MyClassViewModel> vm) {
result.nothing();
}
This way, although the data.models containing an array of objects that were changed, my List returns empty. How can I do that?
Try using kendo.stringify:
parameterMap: function(data, type) {
if (type != "read") {
data = kendo.stringify(data.models);
}
return data;
}
Not sure if this will fix your issue but I'm also using batch: true for my dataSource and this seems to be working for my view models.
You probably also want to check Chrome -> Developer Tools -> Network -> Headers-> Request Payload and see how your data is handed over to the server. Your MyClassViewModel property names should match exactly what you pass from the client.
I have a page called Bookprogram which contains 6 input controls namely, txtName, txtEmail, txtPhone, selectcat[dropdown for categories], txtDate, txtMessage. Now when am done with all the validations for the above control, I want to store the data in db. I know how to perform both in ajax as well as complete page posting.
If it's in ajax, after validations, I would just call $.ajax and post the data as a string and fetch it in controller as below:
[HttpPost]
public JsonResult BookProgram(string name, string email, string phone, string category, string date, string message)
{
//code to save into db
return Json(result);
}
If I have to post a whole page, after validations I would just do a $(form).submit(); and write as below in controller:
[HttpPost]
public ActionResult Bookprogram(Mymodel model)
{
//Code to save the data
return View();
}
I just want to know which is better, safe and good to use as I have to display a message after successful submission. I know I can take either of the ways to display message but Is postback[page refresh] really needed in this scenario and if yes what are the advantages of it over ajax post?
EDIT :
I just went through this link and tried to implement 2nd solution of highest voted answer but for my bad luck it wasn't hitting the controller itself. I have kept breakpoint in my controller.
$(form).on("submit", function (e) {
e.preventDefault();
ValidateForm(form);
var selectedVal = $(form).find('select').children(":selected").val();
if(selectedVal=="")
{
$(form).find('div.bootstrap-select').children(":first").addClass('alert-danger');
$(form).find('div.bootstrap-select').next('.text-danger').html('Please select a category!');
}
var formContainer = $(form + ' .text-danger');
if ($(formContainer).text().length == 0) {
$.ajax({
url: '/Home/BookProgram/',
type: "POST",
dataType: 'json',
contentType: "application/json; charset=utf-8",
data: $('#fbookprogram').serializeArray(),
success: function (data) {
if (data.result == "Success") {
alert('success');
}
else {
alert('fail');
return false;
}
return true;
}
});
}
$(form).unbind('submit');
return false;
});
Controller :
public ActionResult BookProgram(MyModel model)
{
if(ModelState.IsValid)
{
//code to save data
}
return Json(new { success = false });
}
What is that I am missing here.
Post Back
Browser Handling - The only advantage I can think of is that the browser will handle redirects and progress loading for you. You don't need to write the logic to redirect users or show a loading bar.
AJAX
Asynsconous -
With AJAX you're getting asyncronous calls so the browsers thread isn't blocked. This allows the user to still interact with the UI whilst waiting for the response from your request.
Better Performance -You generally don't need to reload the entire page resulting in less overhead & HTTP requests being made.
FYI - You can still model bind with JsonResult
public JsonResult BookProgram(Mymodel model)
{
//code to save into db
return Json(result);
}
Post back - is a classic workflow. Delegate most of inner work to your webbrowser. All your responce logic calculated on server side.
AJAX - is a modern way of building dynamic web-applications. Base approach for single-page-applications. Most of work in this case should be done on client side.
I am new to ajax and mvc... i have a problem with posting back data from jquery. The problem I have is the values are being populated the controller is hit database is updated and then it returns to the page with old data it is not refreshing I have to click f5 to see changes what am I doing wrong? Thanks in advance
Jquery
var values =
{
"PagePartIdentifier": element,
"PagePartContent": data
}
$.post(#Html.Raw(Json.Encode(Url.Action("UploadData", "Home"))),values,function(data)
{
// do stuff;
});
Model
public class PagePartModel
{
public string PagePartIdentifier { get; set; }
public string PagePartContent { get; set; }
}
Controller
[HttpPost, ValidateInput(false)]
[OutputCache(NoStore = true, Duration = 0, VaryByParam = "*")]
public ActionResult UploadData(PagePartModel pagePartm)
{
UpdatePage(pagePartm);
ModelState.Clear();
//return RedirectToAction("Index");
return Json(new { success = true });
}
Html is rendered from a helper method
public static PagePartModel PageAfterContent(this System.Web.Mvc.HtmlHelper html, int page)
{
string part = "AfterContent";
Blog.PageParts pageParts = new Blog.PageParts();
PagePartModel thispart = pageParts.GetContentForPageByPart(page, part);
return thispart;
}
Returns the model for each part to the page
When using $.post, you're sending the data to the server via ajax, so the page never reloads. I'm not sure what the UpdatePage(pagePartm); call in your post method is doing, but since that method is getting called with ajax, it can't change anything on the page. Now in your success handler on your $.post, you can manipulate the DOM to reflect the success or failure of your $.post call.
In your action, instead of returning your Json(new { success = true }); you should/could return the data that you want to be displayed on the page,
e.g.
return Json(new { pagePartm }); // if that is what should be returned
Then modify your $.post() to append the data into the DOM somewhere.
e.g.
$.post("your_controller_action", { name: "John", time: "2pm" },
function(data){
doStuff(data); // this is your point of interaction with the returned data
// or
$("#my_h3").val(data.pagePartm.PagePartIdentifier);
$("#my_div").append(data.pagePartm.PagePartContent);
});
from the jQuery.post documentation.
This will avoid the need to refresh the page to see the results.
jquery ajax post cache property is false ?
$.ajax({
url: '/youraction',
cache: false,
type: 'post'
success: function (data) {
},
error: function (e) {
alert(e.responseText);
}
});
I have a "submit feedback" form which uses "Ajax.BeginForm" to render a partial containing the form elements. The OnSuccess event is triggering even if the ModelState is not valid. Is this normal? I was expecting to be able to do a few postbacks resulting in an invalid model, then when the model is valid and there are no errors then the OnSuccess event would trigger?
I handle this issue with a fairly simple javascript technique:
First setup your OnSuccess like this:
OnSuccess = "UpdateSuccessful(data)"
Then your javascript function like this:
function UpdateSuccessful(data) {
if (data.indexOf("field-validation-error") > -1) return;
// Do your valid stuff here
}
This way, there is no need to mess with your controller, or more importantly, your controller can return the Partial View with the model errors without doing anything weird, ie:
public ActionResult SaveDetails(Project model)
{
if (ModelState.IsValid)
{
model.SaveProject();
}
return PartialView("ProjectForm", model);
}
And in your AjaxOptions:
UpdateTargetId = "FormContents"
Now just make sure you have a div or something with id="FormContents" wherever you want your form displayed.
Is this normal?
Yes, of course. If the server sends HTTP 200 the OnSuccess method is called. The notion of modelstate validity is server side only. As long as your controller action returns some view/partial/json/... the OnSuccess will trigger. If an exception is thrown inside your controller action then the OnError will be triggered instead of OnSuccess.
So in order to handle this case you could have your controller action do something along the lines of:
[HttpPost]
public ActionResult Process(MyViewModel model)
{
if (!ModelState.IsValid)
{
return Json(new { success = false });
}
return Json(new { success = true });
}
and then:
function success(result) {
if (result.success) {
// the model was valid
} else {
// the model was invalid
}
}
Now in the case of invalid model you might want to show the error messages to the user by refreshing the form. What you could do in this case is place your form inside a partial and in the event of an invalid modelstate you would return a partialview from your controller action and in the case of success a json object. So in your success handler you could test:
function success(result) {
if (result.success) {
// the model was valid
} else {
// there were errors => show them
$('#myform_container').html(result);
// if you are using client side validation you might also need
// to take a look at the following article
// http://weblogs.asp.net/imranbaloch/archive/2011/03/05/unobtrusive-client-side-validation-with-dynamic-contents-in-asp-net-mvc.aspx
// and reattach the client validators to the form as you are
// refreshing its DOM contents here
}
}
You can do the following:
var OnSuccess = function() {
if ($(".validation-summary-errors").length == 0) {
//Your javascript/jquery code goes here
}
}
Slight variation on Luis' answer:
function OnSuccess() {
if ($("span[class='field-validation-error']").length == 0) {
alert("Target Platform saved Successfully.");
}
}
I return a bad request instead of the View to ensure that the ajax call returns onfail and not onsuccess.
In the xhr.statustext you can find the string written in the bad request and manage correctly the onfail event.
Server side:
if (!ModelState.IsValid)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest, "Model not valid");
}
Client side:
$.ajax({
url: '',
method: 'POST'
}).fail(function (xhr) {
alert(xhr.statustext);
});
I have validated the JSON response from my C# Webmethod, so I don't believe that's the problem.
Am trying to parse the result using simple jQuery $.ajax, but for whatever reason I can't get the method to correctly fire and parse the result, also incidentally can't seem to get the function to fire the result. Are their any limits on the size of the JSON object that can be returned.
I also removed this code from inside a "Site.Master" page because it would always refresh when I hit the simple button. Do tags work correctly with jQuery elements like the button input I'm grabbing from the DOM?
function ajax() {
//var myData = { qtype: "ProductName", query: "xbox" };
var myData = { "request": { qtype: "ProductName", query: "xbox"} };
$.ajax({
type: "POST",
url: "/webservice/WebService.asmx/updateProductsList",
data: {InputData:$.toJSON(myData)},
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (msg) {
// var msg = {__type: "Testportal.outputData", id: "li1234", message: "it's work!", myInt:101}
alert("message=" + msg.d.ProductName + ", id=" + msg.d.Brand);
},
error: function (res, status) {
if (status === "error") {
// errorMessage can be an object with 3 string properties: ExceptionType, Message and StackTrace
var errorMessage = $.parseJSON(res.responseText);
alert(errorMessage.Message);
}
}
});
}
And the page:
<asp:Button ID="Button1" runat="server" OnClientClick="ajax();" Text="Button" />
And the Serverside Webmethod:
public class WebService : System.Web.Services.WebService
{
[WebMethod]
[ScriptMethod(UseHttpGet = true, ResponseFormat = ResponseFormat.Json)]
public OutputData updateProductsList(InputData request)
{
OutputData result = new OutputData();
var db = new App_Data.eCostDataContext();
var q = from c in db.eCosts
select c;
if (!string.IsNullOrEmpty(request.qtype) && !string.IsNullOrEmpty(request.query))
{
q = q.Like(request.qtype, request.query);
}
//q = q.Skip((page - 1) * rp).Take(rp);
result.products = q.ToList();
searchObject search = new searchObject();
foreach (App_Data.eCost product in result.products)
{
/* create new item list */
searchResult elements = new searchResult()
{
id = product.ProductID,
elements = GetPropertyList(product)
};
search.items.Add(elements);
}
return result;
}
And helper classes:
public class OutputData
{
public string id { get; set; }
public List<App_Data.eCost> products { get; set; }
}
public class InputData
{
public string qtype { get; set; }
public string query { get; set; }
}
One problem you may be having is that you aren't doing anything to prevent the button from submitting the form and executing a full postback/reload at the same time you're starting your $.ajax() callback.
I'd suggest wiring this up unobtrusively instead of using the OnClientClick property, like this:
$(document).ready(function() {
// May need to use $('<%= Button1.ClientID %>') if your Button is
// inside a naming container, such as a master page.
$('#Button1').click(function(evt) {
// This stops the form submission.
evt.preventDefault();
$.ajax({
// Your $.ajax() code here.
});
});
});
I also agree with Oleg that you should use json2.js for your JSON stringifying and parsing. In newer browsers, that will fall back to the browsers' native implementations of those methods, which is much faster and makes the parsing safer.
Update:
To answer your question about the data, no that doesn't look quite right.
What you want to ultimately send to the server is this (sans formatting):
{"request":{"gtype":"ProductName","query":"xbox"}}
To accomplish that, you want something like this:
var req = { request : { qtype: "ProductName", query: "xbox" }};
$.ajax({
data: JSON.stringify(req),
// Remaining $.ajax() parameters
});
Keep in mind that request, qtype, and query must match your server-side structure with case-sensitive accuracy.
You can also be more verbose in defining the request object (which I prefer, personally, to keep things clear and readable):
var req = { };
req.request = { };
req.request.qtype = "ProductName";
req.request.query = "xbox";
I've written a bit more about this here, if you're interested: http://encosia.com/2009/04/07/using-complex-types-to-make-calling-services-less-complex/
What does your server side code method look like? Set a break point. Is it even being hit?
It should look something like:
[WebMethod, ScriptMethod]
public string updateProductsList(string qtype, string query)
{ // stuff
}
Also, your javascript data params do not look formatted correctly.
It seems to me that your problem is that you try to use manual JSON serialization. There are more direct way. You should just declare [ScriptMethod (ResponseFormat = ResponseFormat.Json)] or [ScriptMethod (UseHttpGet = true, ResponseFormat = ResponseFormat.Json)] and return return direct an object instead of the string from the web method. On the client side (in JavaScript) I strictly recommend you to use JSON.stringify (from json2.js which can be downloaded from http://www.json.org/js.html) for the constructing of the data parameter of jQuery.ajax.
Look at Can I return JSON from an .asmx Web Service if the ContentType is not JSON? and How do I build a JSON object to send to an AJAX WebService? probably also in JQuery ajax call to httpget webmethod (c#) not working you have have an interest for more experiments.