Can't get jquery $ajax to call .NET MVC 2 controller method - ajax

I'm new to jquery and ajax - just can't seem to get this to work! See my related question: Use Json and AjaxLink to Toggle Link Values in ASP.NET MVC 2
Here's my jquery:
$(function () {
$("div[id^=add]").click(function (ev) {
ev.preventDefault();
updateMe(this.id.split('_')[1], "AddRequirement");
});
$("div[id^=remove]").click(function (ev) {
ev.preventDefault();
updateMe(this.id.split('_')[1], "RemoveRequirement");
});
});
function updateMe(myId, myAction) {
$.ajax({
type: "POST",
url: "AgreementType.aspx/" + myAction,
data: 'aId=' + <%:Model.AgreementType.Id%> + '&rId=' + myId,
dataType: "text",
error: function(request, msg){
alert( "Error upon saving request: " + msg );
},
success: function (data) {
alert(data);
}
});
}
Currently I have a two different divs. A foreach loop determines which one to display:
<%if(req.Agreements.Any(r => r.AgreementTypeId == Model.AgreementType.AgreementTypeId))
{%>
<div id="<%:string.Format("remove_{0}", req.Id)%>" class="divLink">Remove</div>
<% }
else
{ %>
<div id="<%:string.Format("add_{0}", req.Id)%>" class="divLink">Add</div>
<%{%>
Here's my controller action. Pretty simple:
public JsonResult AddRequirement(string aId, string rId)
{
string result = "Remove";
//Code to add requirement
return this.Json(result);
}
public JsonResult RemoveRequirement(string aID, string rID)
{
string result = "Add";
//Code to remove requirement
return this.Json(result);
}
}
All the success function needs to do it update the innerHtml of the target with the contents, and change the id to match. Seems so easy! And yet I can't seem to figure it out. TIA

Finally - the code that works. This will allow the user to click on a div which will call a different controller method based on the contents of that div, in effect allowing you to toggle toggle elements of the object in a foreach loop. I'm sure it could be improved upon; for instance, I probably don't need to get the value of the div from the controller method, but at least it works.
Javascript
<script type="text/javascript">
$(function () {
$("div[class^=toggleLink]").click(function (ev) {
ev.preventDefault();
var divText = $('#' + this.id).text();
if (divText == "Remove") {
updateMe(this.id, "Remove");
}
else if (divText == "Add") {
updateMe(this.id, "Add");
}
});
});
function updateMe(myId, myAction) {
$.ajax(
{
type: "POST",
url: "/AgreementType/" + myAction,
data: "aId=<%:Model.AgreementType.Id%>&rId=" + myId,
success: function (result) {
if (result.success) {
$('div#' + myId).text(result.value);
}
},
error: function (req, status, error) {
alert(req + " " + status + " " + error);
}
});
}
</script>
Controller
public ActionResult Add(string aId, string rId)
{
//Add to the template
string result = "Remove";
string nClass = "remLink";
return Json(new { success = true, value = result, newClass = nClass });
}
public ActionResult Remove(string aID, string rId)
{
//Remove from the template
string result = "Add";
string nClass = "addLink";
return Json(new { success = true, value = result, newClass = nClass });
}
Markup
<% foreach(var req in std.Requirements)%>
<% { %>
<tr>
<td>
<%if(req.Agreements.Any(r => r.AgreementTypeId == Model.AgreementType.Id))
{%>
<div id="<%:req.Id%>" class="toggleLink">Remove</div>
<% }
else { %>
<div id="<%:req.Id%>" class="toggleLink">Add</div>
<%} %>

Related

Ajax PostBack: Read data from Controller

How do I read the data from my controller in my ajax postback?
I have a Razor form
#using (Html.BeginForm("CreateDocument", "Pages", FormMethod.Post, new { id = "createDocumentForm" }))
{
....
}
And I catch the Submit action in JavaScript:
<script type="text/javascript">
$(document).ready(function () {
$("#createDocumentForm").submit(
function () {
showWaitMode();
$.ajax({
data: ("#createDocumentForm").serialize,
success: (e) => {
console.log(e);
},
error: (errorResponse) => {
alert(errorResponse)
}
})
return false;
}
);
});
</script>
In my controller I hit this method:
public ActionResult CreateDocument(NotatFletModel model)
{
var reuslt = new
{
Staus = true,
GoDocumentId = model.ContactId.ToString(),
ErrorMessage = model.DocumentKindId,
};
return Json(reuslt);
}
But in my Ajax success function I would like to get the data from my contorller. I expected it to be in my parameter e but it's not
So in short: How do I do an Ajax post and read the data posted back from the controller
Checkout my code for Form Post using ajax
Html :
#using (Html.BeginForm("CreateDocument", "Pages", FormMethod.Post, new { id = "createDocumentForm" }))
{
....
}
Jquery :
$("#createDocumentForm").submit(
function (e) {
showWaitMode();
e.preventDefault();
var form = $(this);
var url = form.attr('action');
$.ajax({
url: url,
type: 'POST',
data: form.serialize(), // serializes the form's elements.
success: function (data) {
console.log(data); // show response
},
error: (errorResponse) => {
alert(errorResponse)
}
})
return false;
}
);
Controller :
//You can Use FormCollection also to get data
//public ActionResult CreateDocument(FormCollection fc) {
[HttpPost]
public ActionResult CreateDocument(NotatFletModel model) {
//your logic
return Json(model, JsonRequestBehavior.AllowGet);
}

how to use cascading dropdownlist in mvc

am using asp.net mvc3, i have 2 tables in that i want to get data from dropdown based on this another dropdown has to perform.for example if i select country it has to show states belonging to that country,am using the following code in the controller.
ViewBag.country= new SelectList(db.country, "ID", "Name", "--Select--");
ViewBag.state= new SelectList("", "stateID", "Name");
#Html.DropDownListFor(model => model.Country, (IEnumerable<SelectListItem>)ViewBag.country, "-Select-")
#Html.DropDownListFor(model => model.state, (IEnumerable<SelectListItem>)ViewBag.state, "-Select-")
but by using this am able to get only the countries.
There is a good jQuery plugin that can help with this...
You don't want to refresh the whole page everytime someone changes the country drop down - an ajax call to simply update the state drop down is far more user-friendly.
Jquery Ajax is the best Option for these kind of questions.
Script Code Is Given below
<script type="text/javascript">
$(function() {
$("##Html.FieldIdFor(model => model.Country)").change(function() {
var selectedItem = $(this).val();
var ddlStates = $("##Html.FieldIdFor(model => model.state)");
$.ajax({
cache:false,
type: "GET",
url: "#(Url.Action("GetStatesByCountryId", "Country"))",
data: "countryId=" ,
success: function (data) {
ddlStates.html('');
$.each(data, function(id, option) {
ddlStates.append($('<option></option>').val(option.id).html(option.name));//Append all states to state dropdown through returned result
});
statesProgress.hide();
},
error:function (xhr, ajaxOptions, thrownError){
alert('Failed to retrieve states.');
statesProgress.hide();
}
});
});
});
</script>
Controller:
public ActionResult GetStatesByCountryId(string countryId)
{
// This action method gets called via an ajax request
if (String.IsNullOrEmpty(countryId))
throw new ArgumentNullException("countryId");
var country = GetCountryById(Convert.ToInt32(countryId));
var states = country != null ? GetStatesByConutryId(country.Id).ToList() : new List<StateProvince>();//Get all states by countryid
var result = (from s in states
select new { id = s.Id, name = s.Name }).ToList();
return Json(result, JsonRequestBehavior.AllowGet);
}
Try this,
<script type="text/javascript">
$(document).ready(function () {
$("#Country").change(function () {
var Id = $("#Country").val();
$.ajax({
url: '#Url.Action("GetCustomerNameWithId", "Test")',
type: "Post",
data: { Country: Id },
success: function (listItems) {
var STSelectBox = jQuery('#state');
STSelectBox.empty();
if (listItems.length > 0) {
for (var i = 0; i < listItems.length; i++) {
if (i == 0) {
STSelectBox.append('<option value="' + i + '">--Select--</option>');
}
STSelectBox.append('<option value="' + listItems[i].Value + '">' + listItems[i].Text + '</option>');
}
}
else {
for (var i = 0; i < listItems.length; i++) {
STSelectBox.append('<option value="' + listItems[i].Value + '">' + listItems[i].Text + '</option>');
}
}
}
});
});
});
</script>
View
#Html.DropDownList("Country", (SelectList)ViewBag.country, "--Select--")
#Html.DropDownList("state", new SelectList(Enumerable.Empty<SelectListItem>(), "Value", "Text"), "-- Select --")
Controller
public JsonResult GetCustomerNameWithId(string Country)
{
int _Country = 0;
int.TryParse(Country, out _Country);
var listItems = GetCustomerNameId(_Country).Select(s => new SelectListItem { Value = s.CountryID.ToString(), Text = s.CountryName }).ToList<SelectListItem>();
return Json(listItems, JsonRequestBehavior.AllowGet);
}

HttpPost with AJAX call help needed

what else do i need in my code please, I have this so far:
<script type="text/javascript">
function PostNewsComment(newsId) {
$.ajax({
url: "<%= Url.Action("AddCommentOnNews", "Home", new { area = "News" }) %>?newsId=" + newsId + "&newsComment=" + $("#textareaforreply").val(), success: function (data) {
$("#news-comment-content").html(data + $("#news-comment-content").html());
type: 'POST'
}
});
}
$("#textareaforreply").val("");
</script>
and
[HttpPost]
[NoCache]
public ActionResult AddCommentOnNews(int newsId, string newsComment)
{
if (!String.IsNullOrWhiteSpace(newsComment))
{
var currentUser = ZincService.GetUserForId(CurrentUser.UserId);
ZincService.NewsService.AddCommentOnNews(newsId, newsComment, currentUser.UserId);
Zinc.DataModels.News.NewsCommentsDataModel model = new DataModels.News.NewsCommentsDataModel();
var today = DateTime.UtcNow;
model.CommentDateAndTime = today;
model.NewsComment = newsComment;
model.Firstname = currentUser.Firstname;
model.Surname = currentUser.Surname;
model.UserId = CurrentUser.UserId;
return View("NewsComment", model);
}
return null;
}
<div class="actions-right">
<%: Html.Resource(Resources.Global.Button.Reply) %>
</div>
i have no idea how this works, because it is not working in FF???
and the other thing is i must not pass return null i must pass JSON false ???
any help please?
thanks
You should encode your request parameters. Right now you have concatenated them to the request with a strong concatenation which is a wrong approach. There's a property called data that allows you to pass parameters to an AJAX request and leave the proper url encoding to the framework:
function PostNewsComment(newsId) {
$.ajax({
url: '<%= Url.Action("AddCommentOnNews", "Home", new { area = "News" }) %>',
type: 'POST',
data: {
newsId: newsId,
newsComment: $('#textareaforreply').val()
},
success: function (data) {
$('#news-comment-content').html(data + $('#news-comment-content').html());
}
});
}
Also you haven't shown where and how you are calling this PostNewsComment function but if this happens on the click of a link or submit button make sure that you have canceled the default action by returning false, just like that:
$('#someLink').click(function() {
PostNewsComment('123');
return false;
});
and the other thing is i must not pass return null i must pass JSON false ???
You could have your controller action return a JsonResult in this case:
return Json(new { success = false });
and then inside your success callback you could test for this condition:
success: function (data) {
if (!data.success) {
// the server returned a Json result indicating a failure
alert('Oops something bad happened on the server');
} else {
// the server returned the view => we can go ahead and update our DOM
$('#news-comment-content').html(data + $('#news-comment-content').html());
}
}
Another thing you should probably be aware of is the presence of dangerous characters such as < or > in the comment text. To allow those characters I would recommend you build a view model and decorate the corresponding property with the [AllowHtml] attribute:
public class NewsViewModel
{
public int NewsId { get; set; }
[AllowHtml]
[Required]
public string NewsComment { get; set; }
}
Now your controller action will obviously take the view model as argument:
[HttpPost]
[NoCache]
public ActionResult AddCommentOnNews(NewsViewModel viewModel)
{
if (!ModelState.IsValid)
{
var currentUser = ZincService.GetUserForId(CurrentUser.UserId);
ZincService.NewsService.AddCommentOnNews(viewModel.NewsId, viewModel.NewsComment, currentUser.UserId);
var model = new DataModels.News.NewsCommentsDataModel();
var today = DateTime.UtcNow;
model.CommentDateAndTime = today;
model.NewsComment = newsComment;
model.Firstname = currentUser.Firstname;
model.Surname = currentUser.Surname;
model.UserId = CurrentUser.UserId;
return View("NewsComment", model);
}
return Json(new { success = false });
}

How to include the #Html.AntiForgeryToken() when deleting an object using a Delete link

i have the following ajax.actionlink which calls a Delete action method for deleting an object:-
#if (!item.IsAlreadyAssigned(item.LabTestID))
{
string i = "Are You sure You want to delete (" + #item.Description.ToString() + ") ?";
#Ajax.ActionLink("Delete",
"Delete", "LabTest",
new { id = item.LabTestID },
new AjaxOptions
{ Confirm = i,
HttpMethod = "Post",
OnSuccess = "deletionconfirmation",
OnFailure = "deletionerror"
})
}
but is there a way to include #Html.AntiForgeryToken() with the Ajax.actionlink deletion call to make sure that no attacker can send a false deletion request?
BR
You need to use the Html.AntiForgeryToken helper which sets a cookie and emits a hidden field with the same value. When sending the AJAX request you need to add this value to the POST data as well.
So I would use a normal link instead of an Ajax link:
#Html.ActionLink(
"Delete",
"Delete",
"LabTest",
new {
id = item.LabTestID
},
new {
#class = "delete",
data_confirm = "Are You sure You want to delete (" + item.Description.ToString() + ") ?"
}
)
and then put the hidden field somewhere in the DOM (for example before the closing body tag):
#Html.AntiForgeryToken()
and finally unobtrusively AJAXify the delete anchor:
$(function () {
$('.delete').click(function () {
if (!confirm($(this).data('confirm'))) {
return false;
}
var token = $(':input:hidden[name*="RequestVerificationToken"]');
var data = { };
data[token.attr('name')] = token.val();
$.ajax({
url: this.href,
type: 'POST',
data: data,
success: function (result) {
},
error: function () {
}
});
return false;
});
});
Now you could decorate your Delete action with the ValidateAntiForgeryToken attribute:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Delete(int id)
{
...
}
Modifying the answer by Bronx:
$.ajaxPrefilter(function (options, localOptions, jqXHR) {
var token, tokenQuery;
if (options.type.toLowerCase() !== 'get') {
token = GetAntiForgeryToken();
if (options.data.indexOf(token.name)===-1) {
tokenQuery = token.name + '=' + token.value;
options.data = options.data ? (options.data + '&' + tokenQuery)
: tokenQuery;
}
}
});
combined with this answer by Jon White
function GetAntiForgeryToken() {
var tokenField = $("input[type='hidden'][name$='RequestVerificationToken']");
if (tokenField.length == 0) { return null;
} else {
return {
name: tokenField[0].name,
value: tokenField[0].value
};
}
Edit
sorry - realised I am re-inventing the wheel here SO asp-net-mvc-antiforgerytoken-over-ajax/16495855#16495855

Removing a Partial View in MVC

I have a View with Name, CreatedDate, Address, etc. In the Address section I have State, City etc. I made this section a Partial View.
By default there will be one address section in mainView. I have a button "AddAddress". I want to add another address section if user clicks the button (add a partial view). After getting this partial view there should be a remove button to remove this partial view. I am not using Razor.
the following code is my Javascript to delete my address.
function deleteAddress(addressId, clientId) {
var url1 = "/Client/DeleteAddress";
if (confirm("Are you sure you want to delete this address?")) {
var result = false;
$.ajax({
url: url1,
type: 'POST',
async: false,
data: { AddressId: addressId, ClientId: clientId },
dataType: 'json',
success: function (data) {
result = data;
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
alert("XMLHttpRequest=" + XMLHttpRequest.responseText + "\ntextStatus=" + textStatus + "\nerrorThrown=" + errorThrown);
}
});
if (result) {
}
}
}
the following code is in my controller.
[HttpPost]
public JsonResult DeleteAddress(int AddressId, int ClientId)
{
if (AddressId != 0)
{
if (ClientId != 0)
{
ClientService.Client clientVuTemp = new ClientService.Client();
clientVuTemp = (ClientService.ClientView)TempData["EditClientData"];
clientVuTemp.Address.RemoveAt(AddressId);
//soft delete
clientVuTemp.Address[AddressId].IsActive = false;
_clientSvc.InserOrUpdateClientAddresses(clientVuTemp.Address);
}
else
{
}
return Json(true);
}
else
return Json(false);
}
In the Model we can have a property like IsAddAddressEnabled, Onclick on AddAddress you can set this as true and onclick on cancel you can set as false.
In View you can put an condition,
#if(Model.IsAddAddressEnabled)
{
Html.Partail(....)
}

Resources