MVC Ajax prevent redirect to action controller - c#

In my view I have a modal window, it have the next form...
#using (Html.BeginForm("controllerAction", "Controller", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<div class="container" id="editRecordForm">
<div class="row">
<div class="col-md-6">
#Html.LabelFor(model => model.Author)
#Html.TextBoxFor(model => model.Author, new { #class = "form-control", #style = "height:auto" })
#Html.ValidationMessageFor(model => model.Author)
</div>
</div>
<br/>
<div class="row">
<div class="col-md-6">
#Html.LabelFor(model => model.Image)
<input type="file" name="file" accept="image/*">
</div>
</div>
<br />
<input type="submit" value="Submit" class="btn btn-primary">
</div>
}
this is the JS that contains the ajax request
<script>
var formdata = new FormData($('form').get(0));
$('form').submit(function () {
if ($(this).valid()) {
$.ajax({
url: this.action,
type: this.method,
cache: false,
data: formdata,
success: function (status, data) {
console.log(data);
}
});
}
return false;
});
</script>
The action controller receives two parameters the model and file
[HttpPost]
public async Task<JsonResult> controllerAction(HttpPostedFileBase file, Model model)
{
var json = new
{
Success = true,
StatusCode = "200",
ErrorDesc = "OK",
ErrorCode = "",
NewId = ""
};
//some process
return Json(json, JsonRequestBehavior.AllowGet);
}
The problem is why when the controller action finish, it redirects to the action controller url
http://controller/action
and it does not stay on the same page?
What Im doing wrong?

You are not preventing the default action of the form.
$('form').submit(function (e) {
e.preventDefault();
if ($(this).valid()) {
$.ajax({
url: this.action,
type: this.method,
cache: false,
data: formdata,
success: function (status, data) {
console.log(data);
}
});
}
return false;
});

The problem was the bad config on the javascript- ajax part
$('form').submit(function () {
var formdata = new FormData($('form').get(0));
if ($(this).valid()) {
$.ajax({
url: this.action,
type: this.method,
cache: false,
processData: false,
contentType: false,
data: formdata,
success: function (status, data) {
console.log(data);
}
});
}
return false;
});
thanks to Stephen for the help.

Related

Jquery Autocomplete blank field

I have this issue with autocomplete, it returns something like this:This
But when you check what returns post method everything is as it should be but in view we get in return just blank field, instead of word "Hardware".
My Code:
Constructuor Method:
[HttpPost]
public JsonResult CreateJS(string prefix)
{
List<CategoryModel> list = new List<CategoryModel>();
list = _context.Categories.ToList();
var CatList = (from N in list
where N.Name.StartsWith(prefix)
select new { value = N.Name,label = N.Name });
return Json(CatList);
View:
<link rel="stylesheet" href="//code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css">
<script src="//code.jquery.com/jquery-1.10.2.js"></script>
<script src="//code.jquery.com/ui/1.11.4/jquery-ui.js"></script>
<script>
$(document).ready(function () {
$("#Category").autocomplete({
source: function (request, response) {
$.ajax({
url: "/Incident/CreateJS",
type: "POST",
dataType: "json",
data: { Prefix: request.term },
success: function (data) {
response($.map(data, function (item) {
return { label: item.Name, value: item.Name };
}))
}
})
},
messages: {
noResults: "", results: ""
}
});
})
</script>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="IncidentDescription" class="control-label"></label>
<input asp-for="IncidentDescription" class="form-control" />
<span asp-validation-for="IncidentDescription" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Title" class="control-label"></label>
<input asp-for="Title" class="form-control" />
<span asp-validation-for="Title" class="text-danger"></span>
</div>
<div class="form-group">
<label for="Category">Cat:</label>
<input type"text" name="Category" id="Category"/>
</div>
There is no need to use $.map in the ajax callback functiom. Directly apply the data to the response.
<script>
$(document).ready(function () {
$("#Category").autocomplete({
source: function (request, response) {
$.ajax({
url: "/Incident/CreateJS",
type: "POST",
dataType: "json",
data: { Prefix: request.term },
success: function (data) {
response(data);
}
})
},
});
})
</script>

Submit selected dropdownList value in ASP.NET MVC project

I'm listing a list of clients in a partial view
#{
List<Clients> clientsList = ViewBag.ClientsList;
}
<script src="~/Scripts/jquery-3.1.1.min.js"></script>
<li class="dropdown">
Clients <span class="caret"></span>
<ul class="dropdown-menu" role="menu">
#foreach (Clients c in clientsList)
{
<li>#Html.ActionLink(c.NomClient, "Index", "Home", new {c.ID}, null)</li>
}
</ul>
</li>
What I want is, when a user click on a client in the dropdown list, it send the client to ID to a method on a controller, without clicking on a submit button, with or form for example.
I tried with an ActionLink, but only by passing the id in the URL and I would like to not have the clientId in the URL.
How can I do that ?
thx
Do as
HTML:
<ul class="dropdown-menu" role="menu">
#foreach (Clients c in clientsList)
{
<li>#c.NomClient</li>
}
</ul>
javascript:
// assuming you're using jQuery
$(".dropdown-menu").change( function (event) {
$.ajax({
url: "Home/Index/" + $(this).val(),
data: { id = $(this).val() /* add other additional parameters */ },
cache: false,
type: "POST",
dataType: "html",
success: function (data, textStatus, XMLHttpRequest) {
//do stuff
}
});
});
You can use Jquery for that.
Create a class on your li and an event on click on this class. Simply redirect your page with a window.location.href and a #Url.Action().
JQuery
$(".dropdownclient").click(function(){
window.location.href="#Url.Action('Method','Controller')/"+$(this).data("id");
});
HTML
<ul class="dropdown-menu" role="menu">
#foreach (Clients c in clientsList)
{
<li class='dropdownclient' data-id="#c.ClientID">#Html.ActionLink(c.NomClient, "Index", "Home", new {c.ID}, null)</li>
}
</ul>
Try this with jQuery. Your ID will not be part of the URL.
<ul class="dropdown-menu" role="menu">
#foreach (Clients c in clientsList)
{
<li><button data-action="do-stuff" data-url="#Url.Action("Index", "Home")" data-id="#c.ID">#c.NomClient</button></li>
}
</ul>
$("[data-action='do-stuff']").on('click', function (event) {
var opt = $(this).data();
$.ajax({
url: opt.url,
data: { id = opt.id },
cache: false,
type: "POST"
success: function (data, textStatus, XMLHttpRequest) {
//do stuff
}
});
});
#Html.DropDownListFor(m => m.NomClient, new SelectList(ViewBag.ClientsList,"Key", "Value"), "Select", new { #class = "dropdown-menu" })
$(".dropdown-menu").change(function (event) {
$.ajax({
url: "Home/Index/",
data: { id = $(this).val() /* add other additional parameters */ },
type: "POST",
success: function (data) {
//do stuff
}
});
});

select change event fires during binding

I'm building a multi-step form using knockoutjs in my asp.net mvc 5 application.
the problem is, during binding, the change event for my dropdown is firing. similar to this issue reported here.
I have tried everything suggested in the post above, but the event is still firing twice.
<div class="row">
<div class="col-md-4">
<div class="form-group">
#Html.LabelFor(model => model.Step1.Country, new { #class = "control-label" })
#Html.DropDownListFor(model => model.Step1.Country, Model.Step1.Countries, new { #class = "select-country", #style = "width: 100%;", data_bind = "value: Model.Step1.Country" })
</div>
</div>
<div class="col-md-4">
<div class="form-group">
#Html.LabelFor(model => model.Step1.State, new { #class = "control-label" })
#Html.DropDownListFor(model => model.Step1.State, Model.Step1.States, new { #style = "width: 100%;", data_bind = "value: Model.Step1.State" })
</div>
</div>
<div class="col-md-4">
<div class="form-group">
#Html.LabelFor(model => model.Step1.City, new { #class = "control-label" })
#Html.TextBoxFor(model => model.Step1.City, new { maxlength = "50", #class = "form-control", data_bind = "value: Model.Step1.City" })
</div>
</div>
</div>
Wizard Plugin:
(function ($) {
$.fn.Wizard = function (options) {
//Set the form of the current wizard
var $form = $("#" + options.formId);
var ViewModel = function (d, m) {
var self = this;
self.Model = ko.mapping.fromJS(d, m);
self.Model.GeneralErrors = ko.computed(function () {
return ko.utils.arrayFilter(self.Model.Errors(), function (item) {
return !!item.MemberName;
});
});
self.Model.Step1.Country.subscribe(function (value) {
alert(value);
console.log(value);
});
self.SelectionChanged = function (element) {
}
}
var vm = new ViewModel(options.model, options.mapping);
ko.applyBindings(vm, this[0]);
vm.UpdateOnChange = true;
return this;
};
}(jQuery));
<script type="text/javascript">
$(function () {
$("#WizardWrapper").Wizard({
formId: "WizardForm",
model: #(Html.Raw(Json.Encode(Model))),
url: "/DataCollection/#HttpContext.Current.Request.RequestContext.RouteData.Values["controller"].ToString()/",
mapping: {
create: function (options){
var m = ko.mapping.fromJS(options.data);
return m;
}
}
});
});
</script>
Does anyone know how I can fix this?
Thanks user3297291,
thanks, adding valueAllowUnset stopped the event firing when binding and fires when a selection is made.
However, just one problem,the event fires again during postback when save is click. the event is triggered again by
ko.mapping.fromJS(data, self.Model);
in the ajax post below.
Save Event:
self.Next = function (element) {
var validator = $(element).closest("form").validate();
if ($(element).closest("form").valid()) {
$.ajax({
url: options.url + action,
type: 'POST',
dataType: 'json',
contentType: 'application/json',
data: ko.toJSON(self.Model),
success: function (data) {
self.UpdateOnChange = false;
ko.mapping.fromJS(data, self.Model);
self.UpdateOnChange = true;
},
error: function (jqXHR, textStatus, errorThrown) {
}
});
} else {
validator.focusInvalid();
}
}
Button:
<input data-bind="event: { click: Next.bind($data, $element) }" type="submit" class="btn btn-default btn-prev btn-sky" value="Next" />
Update:
In order to fix the issue with the subscription triggering again after Country is updated, I used this solution with a few changes.
self.dirty = ko.observable(false);
self.selectedCountry = ko.observable();
self.dirtyCalculations = ko.computed(function () {
var value = self.Model.Step1.Country();
if (value == self.selectedCountry()) {
self.selectedCountry(null);
self.dirty(false);
} else {
self.selectedCountry(value);
self.dirty(true);
}
});
self.Model.Step1.Country.subscribe(function (value) {
if (value != undefined && self.dirty()) {
$.ajax({
url: options.url + "GetState",
type: 'POST',
dataType: 'json',
contentType: 'application/json',
data: ko.toJSON(self.Model),
traditional: true,
success: function (data) {
self.UpdateOnChange = false;
ko.mapping.fromJS(data, self.Model);
self.UpdateOnChange = true;
}
});
} else {
self.resetDirtyFlag();
}
});
Simple answer: You could (mis?)use the valueAllowUnset binding.
var VM = function(initial) {
this.selection = ko.observable(initial);
this.updateCount = ko.observable(0);
this.selection.subscribe(function() {
this.updateCount(this.updateCount() + 1);
}, this);
}
ko.applyBindings(new VM(1), document.querySelector(".example1"));
ko.applyBindings(new VM(2), document.querySelector(".example2"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<div class="example1">
<h1>with valueAllowUnset</h1>
<select name="" id="" data-bind="value: selection, valueAllowUnset: true">
<option value="0">0</option>
<option value="1">1</option>
<option value="2">2</option>
</select>
<div>
Updates: <span data-bind="text: updateCount"></span>
</div>
</div>
<div class="example2">
<h1>without valueAllowUnset</h1>
<select name="" id="" data-bind="value: selection">
<option value="0">0</option>
<option value="1">1</option>
<option value="2">2</option>
</select>
<div>
Updates: <span data-bind="text: updateCount"></span>
</div>
</div>
Alternative solution: I'd suggest to use the options binding to render your options via knockout instead of MVC. It makes it a bit easier to debug client side. But this might be personal preference.

Cascade DropDownList

I have a cascade DropDownList, but in the second dropdown when I post data to controller the valeu property in the object that my action receives is null, and I dont know why.
My controller.
[HttpPost]
public JsonResult ListaEstados(String id)
{
var estados = Util.getEstados(id);
return Json(estados);
}
[HttpPost]
public ActionResult AddCidade(Cidade c)
{
c.Cadastrar(c);
return RedirectToAction("AddCidade");
}
My View
#model Projeto_P1.Models.Cidade
#{
ViewBag.Title = "Cadastro de Cidades";
}
#using (Html.BeginForm("AddCidade", "Geral", FormMethod.Post))
{
<div class="container">
<fieldset>
<div>
#Html.Label("Cidade")
#Html.EditorFor(model => model.Nome)
</div>
<div>
#Html.Label("País")
#Html.DropDownList("Pais", (SelectList)ViewData["paises"], "Selecione", new { id = "PaisID"})
</div>
<div>
#Html.Label("Estado")
#Html.DropDownListFor(model => model.Estado, Enumerable.Empty<SelectListItem>(), "Selecione")
</div>
<br />
<input type="submit" value="Cadastrar" />
</fieldset>
</div>
}
<script type="text/javascript">
$(document).ready(function () {
$("#PaisID").change(function () {
$.ajax({
url: "ListaEstados",
type: 'POST',
data: { ID: $(this).val() },
datatype: 'json',
success: function (data) {
var elements = "";
$.each(data, function () {
elements = elements + '<option values="' + this.ID + '">' + this.Nome + '</option>'
})
$('#Estado').empty().attr('disabled', false).append(elements);
}
});
});
});
</script>
Ive solved my problem, there is a S in ajax code, I have´t seen it: elements = elements + '<option values="' + this.ID...
I took it and it worked.

Submit form with jquery ajax

I'm trying to learn MVC and one the things I want to do is submit a form to an action in my controller and this action will return the submitted data. Sounds simple but I've been trying for hours without any success.
my view:
#using (Html.BeginForm("BlogComment","Blog"))
{
#Html.ValidationSummary(true)
<legend class="AddAComment">Add a comment</legend>
<div class="commentformwrapper">
<div class="editor-text">
<span class="editor-label">User Name:</span>
</div>
<div class="editor-text">
<input type="text" id="username" />
</div>
<div class="editor-text">
<textarea id="comment" rows="6" cols="23"></textarea>
</div>
<div class="editor-field">
<input type="hidden" id="hiddendate" />
</div>
<input type="submit" id="submit" value="Create" />
</div>
}
my controller:
[HttpPost]
public ActionResult CommentForm(Comment comment)
{
Comment ajaxComment = new Comment();
ajaxComment.CommentText = comment.UserName;
ajaxComment.DateCreated = comment.DateCreated;
ajaxComment.PostId = comment.PostId;
ajaxComment.UserName = comment.UserName;
mRep.Add(ajaxComment);
uow.Save();
//Get all the comments for the given post id
return Json(ajaxComment);
}
and my js:
$(document).ready(function () {
$('form').submit(function () {
$.ajax({
url: '#Url.Action("CommentForm")',
type: "POST",
dataType: "json",
contentType: "application/json; charset=utf-8",
data: {
PostId: $('.postid').val(),
UserName: $('#username').val(),
DateCreated: new Date(),
CommentText: $('#comment').val()
},
success: function (result) {
alert("success " + result.UserName);
},
error: function (result) {
alert("Failed");
}
});
return false;
});
});
You don't need to write any client side code to do this, FYI.
To use the ajax methods successfully in MVC, you will need to do the following. Add this key to appsettings in web.config:
<appSettings>
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
</appSettings>
As well as include the unobtrusive ajax script:
<script src="/Scripts/jquery.unobtrusive-ajax.min.js" type="text/javascript"></script>
Then create div container around your form and replace Html.BeginForm with Ajax.BeginForm
<div id="ajaxReplace">
#using (Ajax.BeginForm("BlogComment", "Blog", null, new AjaxOptions { UpdateTargetId = "ajaxReplace", OnSuccess = "doFunctionIfYouNeedTo", OnFailure = "ShowPopUpErrorIfYouWant" }))
{
#Html.ValidationSummary(true)
<legend class="AddAComment">Add a comment</legend>
<div class="commentformwrapper">
<div class="editor-text">
<span class="editor-label">User Name:</span>
</div>
<div class="editor-text">
<input type="text" id="username" />
</div>
<div class="editor-text">
<textarea id="comment" rows="6" cols="23"></textarea>
</div>
<div class="editor-field">
<input type="hidden" id="hiddendate" />
</div>
<input type="submit" id="submit" value="Create" />
</div>
}
</div>
Then in your controller you'll return something like this:
return PartialView(ajaxComment);
This will save you maintaining a script to do this manually and will funnel you into using the framework as intended. It will also help you out with data annotation validation and all of the juicy stuff that goes with it,
I hope this helps in some way.
Try this:
The Model
public class Comment
{
public string CommentText { get; set; }
public DateTime? DateCreated { get; set; }
public long PostId { get; set; }
public string UserName { get; set; }
}
The View and js
#model SubmitMvcForWithJQueryAjax.Models.Comment
#using (Html.BeginForm("BlogComment","Blog"))
{
#Html.ValidationSummary(true)
<legend class="AddAComment">Add a comment</legend>
<div class="commentformwrapper">
<div class="editor-text">
<span class="editor-label">User Name:</span>
</div>
<div class="editor-text">
#Html.EditorFor(m => m.UserName)
</div>
<div class="editor-text">
#Html.TextAreaFor(m => m.CommentText, new { rows="6", cols="23"} )
</div>
<div class="editor-field">
#Html.HiddenFor(m => m.DateCreated)
</div>
<div class="editor-field">
#Html.HiddenFor(m => m.PostId)
</div>
<input type="submit" id="submit" value="Create" />
</div>
}
<script type="text/javascript">
$(document).ready(function () {
$('form').submit(function () {
var serializedForm = $(this).serialize();
$.ajax({
url: '#Url.Action("CommentForm")',
type: "POST",
data: serializedForm,
success: function (result) {
alert("success " + result.UserName);
},
error: function (result) {
alert("Failed");
}
});
return false;
});
});
</script>
The Controller
public class CommentController : Controller
{
//
// GET: /Comment/
public ActionResult Index()
{
return View(new Comment());
}
[HttpPost]
public ActionResult CommentForm(Comment comment)
{
Comment ajaxComment = new Comment();
ajaxComment.CommentText = comment.UserName;
ajaxComment.DateCreated = comment.DateCreated ?? DateTime.Now;
ajaxComment.PostId = comment.PostId;
ajaxComment.UserName = comment.UserName;
//mRep.Add(ajaxComment);
//uow.Save();
//Get all the comments for the given post id
return Json(ajaxComment);
}
}
Basically you are passing javascript object literals directly. So, before you pass data to your controller, it must be in JSON format(because you have specified application/json. see your $.ajax call).
SO, you are missing JSON.stringify()
data: JSON.stringify({
PostId: $('.postid').val(),
UserName: $('#username').val(),
DateCreated: new Date(),
CommentText: $('#comment').val()
}),
OR
var someObj = {
PostId: $('.postid').val(),
UserName: $('#username').val(),
DateCreated: new Date(),
CommentText: $('#comment').val()
};
$.ajax({
/// your other code
data: JSON.stringify(someObj),
// your rest of the code
});
Instead of
data: {
PostId: $('.postid').val(),
UserName: $('#username').val(),
DateCreated: new Date(),
CommentText: $('#comment').val()
},
Try
$('form').submit(function () {
var obj = {
PostId: $('.postid').val(),
UserName: $('#username').val(),
DateCreated: new Date(),
CommentText: $('#comment').val()
};
$.ajax({
...,
data: JSON.stringify(obj),
...,
});
return false;
});
You have to convert data to string before sending it to server. and JSON.stringify does that job

Categories

Resources