Using AJAX to contact a method on server - c#

I want to use ajax/call a webmethod in the controller by clicking a button that is in a BeginForm
I have a submit button in a Html.BeginForm. Clicking this button will as we know, send the info from the model to the server. Here is the simplified code.
#using (Html.BeginForm())
{
...
<div class="form-group">
#Html.LabelFor(model => model.FirstName, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.FirstName, new { htmlAttributes = new { #class = "form-control", #readonly = "readonly" } })
#Html.ValidationMessageFor(model => model.FirstName, "Navn skal angives", new { #class = "text-danger" })
</div>
</div>
...
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Tilføj" class="btn btn-default" id="submitBut" />
</div>
</div>
}
The corresponding Controller looks like this
[HttpPost]
public ActionResult AttachCard(Card model, int MemberID)
{ ... }
I will need to add the annotation [WebMethod]
My issue is that I want to use JQuery Dialog to notify the client, when the card is added. For this I need a true or false value from the server. The dialog message will depend on this boolean value.
I have written some AJAX code. This is not tested yet, as I'm stuck
function attachCard(MemberID, action, controller) {
var url = '/' + action + '/' + controller;
$.ajax({
type: "POST",
url: url,
data: $("form").serialize(),
contentType: 'application/html; charset=utf-8',
dataType: "html",
success: function (status) {
alert("Test from server: " + status);
},
error: function (msg) {
alert("Error");
}
})
}
I want this ajax function to run when the user clicks on the button that you see in my Html.BeginForm. But is this possible? If I add an onclick listener while it's in the BeginForm, then the webmethod will be called twice I think, and this will result in an exception. I am thinking about moving that button out of the BeginForm, and add an onclick event on the button. But then the rest of the info from the model (in the BeginForm) won't be submittet.
How can I do this?

You can use Ajax.BeginForm instead. Here is my working sample code
#using (Ajax.BeginForm("CreateAndUpdate", "WidgetContent", new AjaxOptions
{
OnSuccess = "GroupSubmitted",
OnFailure = "GroupError",
}, new { role = "form", #id = "groupform" }))
{
}
And your Javascript callback functions
function GroupError(ajaxContext) {
//Error message
}
function GroupSubmitted(result) {
if (result.success) {
}
else {
}
}

Related

Using Html.BeginForm and ajax call same action conflict?

When I try to add Ajax to pass another data into my action controller my model parameter was affected the value was null and my Ajax parameter has a value. I do not think it is because I am using Html.beginform('index', 'payable') and I used Ajax url: '#Url.Action("index", "payable")', with the same ActionResult.
You can see the reference below.
#using (Html.BeginForm("index", "payable", FormMethod.Post, new { enctype = "multipart/form-data" }))<div class="col-md-2">
<div class="form-group">
#Html.LabelFor(x => x.Amount, new { #class = "form-label" })
#Html.TextBoxFor(x => x.Amount, new { #class = "form-control" })
</div>
</div>
<div class="col-md-2">
<div class="form-group">
#Html.LabelFor(x => x.ImagePath, new { #class = "form-label" })
<input type="file" name="file" id="files" />
</div>
</div>
<div class="col-md-2">
<div class="form-group">
<button type="submit" id="btnUpload" class="btn btn-primary btn-sm" onclick="saveSelected()"><i class="fas fa-save"></i> Submit Payment</button>
</div>
</div>{
My Ajax
function saveSelected() {
$.ajax({
url: '#Url.Action("index", "payable")',
type: 'POST',
data: { ids: ids },
traditional: true,
success: function (data) {
alert("success");
}
});
}
My Controller
public ActionResult Index(PayableFormModel model, HttpPostedFileBase file, int[] ids)
{
return View();
}
Html.Beginform and ajax cannot use at same time,even you add a
onclick function. So the ajax won't work and all data are submitted
by form. If you want to submit model and any other data, put all them into form or only use ajax.
When you upload file, model cannot get file's name or path directly. You should store file into a folder or directory,then assign this path to model's imagepath.(Examle code is blew)
In index page, {} should follow using(), otherwise it will report error.
public ActionResult Index(PayableFormModel model,HttpPostedFileBase file,int[] ids)
{
string filepath = Server.MapPath("~/image/");
Directory.CreateDirectory(filepath);
file.SaveAs(Path.Combine(filepath, file.FileName));
model.ImagePath = filepath + file.FileName ;
return View();
}

Show Json in same cshtml page using ajax after post

I'm working on a Search function, I'm returning a Json result from the Controller Action method. Everything is working fine, except that I want to show the results from the Action Method in the same Index page(my default page: http://localhost:51450/), but for some reason it routes to http://localhost:51450/Students/SearchStudent and in that page it just shows the result in json format: [{"StudentID":166,"Name":"ss","LastName":"s","Age":23}] and of course there is not any format in there. I'm using ajax with the purpose to show the results in the same Index page.. There should be something that I'm missing, what is it?
Controller Action Methods(1 just to show the view and the other to submit the filled form...):
public PartialViewResult SearchStudent()
{
return PartialView();
}
[HttpPost]
[ValidateAntiForgeryToken]
public JsonResult SearchStudent(string name)
{
List<Student> list = db.Students.Where(s => s.Name == name).ToList();
return Json(list, JsonRequestBehavior.AllowGet);
}
Partial View(The user should put a name and in then click submit):
#model Pedro2.Models.Student
using (#Html.BeginForm("SearchStudent", "Students", FormMethod.Post, new { #id = "formSearchStudent" }))
{
#Html.AntiForgeryToken()
<div class="form-group">
<div class="col-md-10">
#Html.LabelFor(model => model.Name)
#Html.TextBoxFor(model => model.Name)
</div>
</div>
<div class="form-group">
<input type="submit" value="Submit" id="submitSearch" data-url="#Url.Action("SearchStudent", "Students")" />
</div>
}
<div id="divResult"></div>
Index view(only the part concerning to this operation):
<p class="hand" id="pSearch" data-urlSearch="#Url.Action("SearchStudent","Students")"> Search by name</p>
<div id="ShowFormSearch"></div>
And the JQuery code:
$(function () {
$("#pSearch").click(function () {
ShowSearchPage();
return false;
})
$("#submitSearch").click(function () {
SearchStudent();
return false;
})
})
function SearchStudent() {
$.ajax({
type: 'get',
url: $("#submitSearch").data('url'),
data: $("#formSearchStudent").serialize + { name: $("#Name").val() },
datatype : 'json'
}).success(function (result) {
$("#divResult").html(result)
}).error(function () {
$("#divResult").html("An error occurred")
})
}
function ShowSearchPage()
{
$.ajax({
type: 'get',
url: $("#pSearch").data('urlsearch')
}).success(function (result) {
$("#ShowFormSearch").html(result)
}).error(function () {
$("#ShowFormSearch").html("An error occurred")
})
}
If you need to ask me anything just let me know

MVC Bootstrap form-control DropDownListFor validation error message not displaying

I am using MVC5 and I can not get the MVC validation message for DropDownList (with Bootsrap3). I researched similar problems on stackoverflow but any solutions work for me.
I want to user select option from drop down list. If he click "Submit" button and no option was selected he should get validation error message. Initially when page is loaded first time, any option is selected (selected is option with value "null").
Model:
public class CarsPriceSearchViewModel
{
[Required(ErrorMessage = "Proszę wybrać markę"), Range(1, Int32.MaxValue)]
[Display(Name = "Marka")]
public int SelectedBrandId { get; set; }
public SelectList Brands { get; set;}
[Required(ErrorMessage = "Proszę wybrać model"), Range(1, Int32.MaxValue)]
[Display(Name = "Model")]
public int SelectedModelId { get; set; }
}
Controller
public ActionResult Index()
{
oSelectList = new List<SelectListItem>() {
new SelectListItem(){ Value="1", Text="Audi"},
new SelectListItem(){ Value="2", Text="BMW"}
};
oSearchViewModel.Brands = new SelectList(oSelectList, "Value", "Text");
return View(oSearchViewModel);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Search(CarsPriceSearchViewModel searchOptions)
{
if (ModelState.IsValid)
{
//TO sth
}
return View(searchOptions);
}
View
<div class="panel-body">
#using (Html.BeginForm("Search", "Home", FormMethod.Post, new { id = "SearchCarsOffersForm" }))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<div class="row">
<div class="col-lg-2">
<div class="form-group">
#Html.LabelFor(m => m.SelectedBrandId)
#Html.DropDownListFor(m => m.SelectedBrandId,
Model.Brands,
"--Wybierz-Markę--",
new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.SelectedBrandId, "", new { #class = "text-danger" })
</div>
</div>
<div class="col-lg-2">
<div class="form-group">
#Html.LabelFor(m => m.SelectedModelId)
#Html.DropDownListFor(m => m.SelectedModelId,
new SelectList(Enumerable.Empty<SelectListItem>(), "ModelId", "ModelName"),
"--Wybierz-Model--",
new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.SelectedModelId, "", new { #class = "text-danger" })
</div>
</div>
</div>
<div class="panel-footer">
<button type="submit" id="SearchCarsOffers" class="btn btn-outline btn-primary btn-lg btn-block">
Szukaj
</button>
</div>
}
</div>
Remark
In _Layout.cshtml I have included scripts:
<script src="/Scripts/jquery.validate.js"></script>
<script src="/Scripts/jquery.validate.unobtrusive.js"></script>
<script src="/Scripts/jquery-1.10.2.js"></script>
<script src="/Scripts/jquery.validate.js"></script>
<script src="/Scripts/jquery.validate.unobtrusive.js"></script>
Scripts
$("#SelectedBrandId").change(function (event) {
$.ajax({
url: "UsedCarsPriceChart/FillBrandModels/",
data: { id: $(this).val() /* add other additional parameters */ },
cache: false,
type: "POST",
dataType: "JSON",
success: function (models) {
$("#SelectedModelId").html(""); // clear before appending new list
$("#SelectedModelId").append(
$('<option></option>').html("--Wybierz-Model--"));
for (var i = 0; i < models.length; i++) {
var model = models[i];
$("#SelectedModelId").append(
$('<option></option>').val(model.ModelId).html(model.ModelName));
}
//The same statement as above
//$.each(models, function (i, model) {
// $("#SelectedModelId").append(
// $('<option></option>').val(model.ModelId).html(model.ModelName));
//});
$("#VersionModelId").html(""); // clear before appending new list
$("#VersionModelId").append(
$('<option></option>').html("--Wybierz-Wersję--"));
}
});
});
$("#SelectedModelId").change(function (event) {
$.ajax({
url: "UsedCarsPriceChart/FillVersionModel/",
data: { id: $(this).val() },
cache: false,
type: "POST",
dataType: "JSON",
success: function (models) {
$("#VersionModelId").html(""); // clear before appending new list
$("#VersionModelId").append(
$('<option></option>').html("--Wybierz-Wersję--"));
$.each(models, function (i, model) {
$("#VersionModelId").append(
$('<option></option>').val(model.VersionModelId).html(model.VersionModelName));
});
}
});
});
Problem
TestCase #1: When page is loaded and I click submit button then validation messages are not displayed.
TestCase #2: When page is loaded and I select option "--Wybierz-Markę--" then the validation messages is not displayed (I suspect to be).
TestCase #3: When page is loaded and I select first option and next option "--Wybierz-Markę--" then the validation messages is not displayed (I suspect to be).
Problem source:
I figure out that this peace of script brokes this functionality (when I comment this my code works well):
$('#SearchCarsOffers').click(function () {
var form = $("#SearchCarsOffersForm");
var url = form.attr("action");
var formData = form.serialize();
$.post(url, formData, function (data) {
areaChart.setData(data);
//CreateMorrisArea(data);
});
return false;
});
Please explain me where exactly is the problem and how can I fix it?

mvc partial view autocomplete using modal jquery not displaying data in textboxfor

I have review many examples but have not been able to find an example to help me figure out my issue.
I have everything working up to the jquery autocomplete response. But the data is not showing in the textboxfor.
HTML
<div class="modal-body">
<div class="form-horizontal">
<div class="form-group">
#Html.LabelFor(model => model.Ship_To_Name, htmlAttributes: new { #class = "control-label col-md-2" })
<div id="ShipToName" class="col-md-10">
#Html.TextBoxFor(model => model.Ship_To_Name, new { #class = "autocomplete_with_hidden", data_url = Url.Action("AutoComplete", "Customer") })
#Html.HiddenFor(model => model.Ship_To_Code, new { id = "ShipToCode" })
#Html.ValidationMessageFor(model => model.Ship_To_Name, "", new { #class = "text-danger" })
</div>
</div>
Here is how the partial view is being called.
<a class="btn btn-success" data-modal="" href="/WebOrder/CreateShipTo" id="btnCreate">
<span class="glyphicon glyphicon-plus"></span>
</a>
<!-- modal placeholder-->
<div id='myModal' class='modal fade in'>
<div class="modal-dialog">
<div class="modal-content">
<div id='myModalContent'></div>
</div>
</div>
</div>
jquery
The below code is working but I can't get the data to display.
$(function () {
$('#myModalContent').on('keyup', '#Ship_To_Name.autocomplete_with_hidden', function (event) {
var target = $(this);
target.autocomplete({
minLength: 3,
source: function (request, response) {
var url = $(this.element).data('url');
$.ajax({
async: false,
cache: false,
dataType: "json",
type: "POST",
url: url,
data: { "term": request.term },
success: function (data) {
response($.map(data, function (item) {
return {
label: item.label,
value: item.id
};
}))
}
});
},
});
});
});
Controller:
public ActionResult Autocomplete(string term)
{
var model = db.Customers
.Where(m => term == null || m.Customer_Name.StartsWith(term))
.Take(10)
.Select(m => new
{
label = m.Customer_Name,
id = m.Ship_To_Code
}).ToArray();
return Json(model, JsonRequestBehavior.AllowGet);
}
Controller
public ActionResult CreateShipTo(WebOrderVM webOrderVM)
{
return PartialView("_AddShipToInfo", webOrderVM);
}
I see a little problem here. You are registering the jquery ui auto complete functionality on every key up event on that that textbox ! I don't think that is needed. You may simply register it once.
Also, to enable the autocomplete, you need minimal amount of code as such
$(function () {
$("#Name").autocomplete({
source: $("#Name").data('url'),
minLength: 1,
select: function (event, ui) {
//If you want to do something custom on the select event,
// you may do it here
// Ex : $("#SomeDiv").html(ui.item.label);
}
});
});
This should work as lonog as your action method returns you the data.
public ActionResult Autocomplete(string term)
{
var model = db.Customers
.Where(m => term == null || m.Customer_Name.StartsWith(term))
.Take(10)
.Select(m => new
{
label = m.Customer_Name,
id = m.Ship_To_Code
}).ToArray();
return Json(model, JsonRequestBehavior.AllowGet);
}
If you want the auto complete to work with dynamically loaded content, you should register the auto complete after you inject the content to DOM
Quick example
$.get(someUrlToGetDynamicContent,function(res){
$("#SomeContainer").append(res);
$(".someClassNameForTheTextBox").autocomplete({
source: urlToGetTheAutoCompleteData,
minLength: 1,
select: function (event, ui) { }
});
})

HiddenFieldFor not working for controls rendered conditionally

On my view I have some fields which are rendered conditionally. The fields are nullable booleans so I am using 'EditorFor()' with custom editor template for boolean (if this is important)
<div class="form-group">
#Html.LabelFor(m => m.HasAccount, new { #class = "col-sm-3 control-label" })
<div class="col-sm-9">
#Html.EditorFor(m => m.HasAccount)
</div>
</div>
<hr class="dotted" />
#if (Model.HasAccount2)
{
<div class="form-group">
#Html.LabelFor(m => m.ExtraField, new { #class = "col-sm-3 control-label" })
<div class="col-sm-9">
#Html.EditorFor(m => m.ExtraField)
</div>
</div>
<hr class="dotted" />
}
#Html.HiddenFor(m => m.ExtraField)
<div class="form-group">
#Html.LabelFor(m => m.Options, new { #class = "col-sm-3 control-label" })
<div class="col-sm-9">
<div class="input-group">
#Html.DropDownListFor(m => m.OptionID, Model.OptionsSelectList, "Choose an Option", new { #class = "form-control chosen-select" })
</div>
</div>
</div>
$('#Options').change(function () {
$.ajax({
url: '#Url.Action("ProcessOptions", "Home")',
type: "POST",
data: $('#ProcessForm').serialize(),
error: function (xhr, ajaxOptions, thrownError) {
alert("error");
},
success: function (result) {
$('#divContainer').html(result.ViewString);
}
});
});
Now when the View is posted then according to some condition in the controller I set the value of ExtraField to true or false. The controls for ExtraField will not be rendered unless the value for HasAccount2 is true so to store the value I use the HiddenFor() for ExtraField so that when the form is posted again then ExtraField is passed as true and not null because it is not rendered.
Now the HiddenFor() does not have any value which is returned from the model. How can I store the value for ExtraField as hidden in this scenario?
Edit
There is a dropdownlist on the view. The view is posted using JQuery Ajax when the select index of dropdownlist is changed. The model is passed to the controller and processed and the partial view is returned with model as Json. Below is the controller method,
[HttpPost]
public ActionResult ProcessOptions(MyOptions model)
{
if (model.OptionID == 1)
{
model.HasAccount2= true;
}
else if (model.OptionID == 3)
{
model.ExtraField = true;
}
return Json(this.RenderPartialViewToString("_Options", model););
}
The method RenderPartialViewToString is just converting the PartialView as string. It all works fine except the ExtraField. Now as you can see that based on some condition I am rendering ExtraField when HasAccount2 is set to true so that User can select true or false by himself but incase OptionID is 3 then I don't want the ExtraField checkbox to be rendered rather I want to set it explicitly from controller and store it in HiddenField so that when user submit the form for save then the ExtraField value is also passed.

Categories