Controller return incorrect data with ajax ActionLink in mvc - ajax

several days ago with searching i put an ajax button inside my page, but i didn't know the issue till now, the thing is happen, is that the result i receive is not the result from ajax redirection, but is result from first processing (though i was wonder why it do it twist)...
And what i wanna do is perform filtering through link button instead of button.
so i have two action, one is for my ajax button, and second for my index:
1.
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult ChooseCategoryAction(int? id)
{
Monitor.Enter(monitorObj);
// Save code here...
Session.Add("FilterCategory", id);
return RedirectToAction("Index");
}
2.
public override ActionResult Index()
{
.
.
.
int? id = (Session["FilterCategory"] != null) ? int.Parse(Session["FilterCategory"].ToString()) : (int?)null;
List<LinkEntity> filterList = null;
int catId = id ?? -1;
if (catId != -1)
{
filterList = new List<LinkEntity>();
foreach (LinkEntity linkEntity in linkList.Where(
where =>
(catId == 0 && #where.Category == null) ||
(#where.Category != null && #where.Category.Id == catId)).Select(
select =>
new LinkEntity(#select.Id, #select.Name, #select.Link, #select.Description,
#select.Category)))
{
filterList.Add(linkEntity);
}
}
else
{
filterList = linkList;
}
return View(filterList);
}
My View is like this:
<div class="split-left">
#if (ViewBag.CategoriesTags != null)
{
foreach (var cat in ViewBag.CategoriesTags)
{
<div class="link-item-category">
#using (Html.BeginForm())
{
#Ajax.ActionLink((string)cat.Name, "ChooseCategoryAction","Home", new { id = cat.Id }, new AjaxOptions { HttpMethod = "POST" }, new{#class = "category-link"})
}
</div>
}
}
</div>
When i click the link it should goes to Ajax method, then inbox, filter my data and return a view, but it first goes to inbox, then to Ajax, again to inbox, next it goes value seem to be true, but result which return is incorrect
i also before reaching to filtering step, tried following:
#Html.Hidden(((int)cat.Id).ToString())
#Html.ActionLink((string)cat.Name, "ChooseCategoryAction", "Home", null, new { #class = "category-link", onclick = "return false;" })
with following script:
<script type="text/javascript">
$(document).ready(function () {
$('.category-link').click(function () {
$(this).closest('form')[0].submit();
});
});
</script>
But it don't return to controller or don't refresh page

Related

Like button in MVC using 'Ajax.Beginform()' not able to display total likes on page

I am beginner in MVC and Ajax development and want a like button in my web, which should work like this: if the user clicks on it total likes will be incremented by 1 and if the user clicks it again (dislike) then it will decremented by 1. What I have done so far is this:
Here's the Model:
public class Like
{
public int Id { get; set; }
public virtual Video Video { get; set; }
public int VideoID { get; set; }
public string UserId { get; set; }
public virtual ApplicationUser ApplicationUser { get; set; }
}
Here is the Controller:
Post Method
[HttpPost]
public ActionResult Like(int Id, Like like)
{
if (ModelState.IsValid && User.Identity.IsAuthenticated == true)
{
like.Video = storeDB.Videos.Find(Id);
like.UserId = User.Identity.GetUserId();
var userlike = storeDB.Likes.Where(l => l.UserId == like.UserId && l.VideoID == Id);
if (userlike.Count() == 0)
{
storeDB.Likes.Add(like);
storeDB.SaveChanges();
}
else if (userlike.Count() == 1)
{
var likeDel = storeDB.Likes.FirstOrDefault(l => l.UserId == like.UserId && l.VideoID == Id);
storeDB.Likes.Remove(likeDel);
storeDB.SaveChanges();
}
List<Like> videoLikes = storeDB.Likes.Where(v => v.VideoID == Id).ToList();
int nooflikes = videoLikes.Count();
ViewBag.noLikes = nooflikes;
return Json(ViewBag.noLikes, JsonRequestBehavior.AllowGet);
}
else
{
ViewBag.Message = "Login to like this video";
return PartialView("Like", ViewBag.noLikes);
}
This is the Get method of Like:
public ActionResult Like(int id)
{
List<Like> videoLikes = storeDB.Likes.Where(v => v.VideoID == id).ToList();
int nooflikes = videoLikes.Count();
ViewBag.noLikes = nooflikes;
return Json(ViewBag.noLikes, JsonRequestBehavior.AllowGet);
}
and I have created a Partial View for this:
#if (ViewBag.Message != null)
{
<script>
$(document).ready(function () {
alert('#ViewBag.Message');
});
</script>
}
//to display total likes
<input type="text" id="likes" name="likes" value='#ViewBag.noLikes' readonly="readonly" style="border:none; background-color:transparent; width:20px" /><span style="color:black">likes</span>
and this is the main view in which I am using Ajax.BeginForm()
#using (Ajax.BeginForm("Like", "VOD", new { Id = Model.Id },
new AjaxOptions
{
HttpMethod = "Post",
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "likecount"
}))
{
<button type="submit" id="like" value="Like" class=" btn btn-primary btn-xs"> Like <span class="glyphicon glyphicon-thumbs-up" aria-hidden="true"></span> </button>
}
<span id="likecount">
#Html.Partial("Like", new Models.Like())
</span>
Now the issue is that when the page is first loaded it is not displaying total likes, and when I click on like button it returns 1 and when I click like button again it returns 0 but when I refresh the page or when I post back to another page total likes again disappear.
Can anybody help me?
Instead of doing so much code you can do above functionality in simple way.
You will required following to do so,
2 Action Methods,
1. Increment Like Count.
2. Decrease Like Count.
2 Buttons on web page
1. Like Button (Initially visible)
2. DisLike Button (Initially Invisible)
you can create a ajax request on both buttons something like bellow,
$("#btnLike").click(function () {
$.ajax({
type: "POST",
url: "Controller/LikeAction",
data: { /* Your Data */ };
success: function (result) {
// Hide Like Button & Show Dislike Button
},
error: function (error) {
alert("error = " + error);
}
});
});
Same way you can create ajax request for dislike button also. You just need to hide and show buttons.

ActionLink to submit Model value

I want my Ajax.ActionLink to pass a viewModel property to action.
Here is my ViewModel
public class ViewModel
{
public string Searchtext { get; set; }
}
My .cshtml
#Ajax.ActionLink("Bottom3", "Bottom3",new { name = Model.Searchtext}, new AjaxOptions
{
HttpMethod = "POST",
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "pointsDiv"
})
using(Html.BeginForm("Bottom3", "Home", FormMethod.Get))
{
#Html.TextBoxFor(x => x.Searchtext)
<button type="submit">Search</button>
}
<div id="pointsDiv"></div>
}
My Controller action:
public PartialViewResult Bottom3(string name)
{
var model = db.XLBDataPoints.OrderBy(x => x.DataPointID).Take(3).ToList();
return PartialView("Partial1", model);
}
But the name parameter passed to the action is always null. How do I solve this?
In your code... you have 2 different ways of posting to the server: the link and the form button.
The problem is that the ActionLink has no way to get the value from the input in client side... just the original value.
If you press the Search button, you will see a value posted.
Now, you can use some jQuery to modify a standard ActionLink (not the Ajax.ActionLink):
https://stackoverflow.com/a/1148468/7720
Or... you can transform your Form in order to do a Ajax post instead of a normal one:
https://stackoverflow.com/a/9051612/7720
I did this for a model of mine like so. I ONLY supported the HttpPost method. So add the HttpMethod="POST" to your Ajax.ActionLink
[HttpPost]
public ActionResult Accounts(ParametricAccountsModel model)
{
if (model.Accounts == null)
{
GetAccountsForModel(model);
}
if (model.AccountIds == null)
{
model.AccountIds = new List<int>();
}
return View(model);
}
On the razor view
#Ajax.ActionLink(
"Add Account to Order", "Accounts", "Parametric", null,
new AjaxOptions() { InsertionMode = InsertionMode.Replace, UpdateTargetId = "...", HttpMethod = "POST" },
new { #id = "AddParametricAccountLink" })
The model has a list of selected account ids. So in javascript, I modified the href of the action link dynamically.
function UpdateParametricAccountAction() {
var originalLink = '/TradeNCashMgmt/Parametric/Accounts';
var append = '';
var numberOfRows = $('#ParametricAccounts').find('.parametric-account- row').size();
for (var i = 0; i < numberOfRows; i++) {
if (i != 0) {
append += '&';
}
else {
append = '?';
}
var idValue = $('#NotionalTransactionsAccountId_' + i).val();
append += 'AccountIds%5B' + i + '%5D=' + idValue;
}
$('#AddParametricAccountLink').attr('href', originalLink + append);
}
Since the model binder looks for parameter names in the query string and form submission, it will pick up values using the href. So I posted a model object using the querystring on my Ajax.ActionLink. Not the cleanest method, but it works.

Asp.NET MVC ajax is loading bad page

I have a layout page inside which i have a table with delete button
when i press a delete button it is showing some thing like .
my ajex option is like.
#{
AjaxOptions xPost = new AjaxOptions();
xPost.HttpMethod = "POST";
xPost.Confirm = "Do you wish to submit this form ?";
xPost.OnBegin = "OnBegin";
xPost.OnComplete = "OnComplete";
xPost.OnFailure = "OnFailure";
xPost.OnSuccess = "OnSuccess";
xPost.LoadingElementDuration = 1000;
xPost.LoadingElementId = "divProgress";
xPost.UpdateTargetId = "divResponse";
xPost.InsertionMode = InsertionMode.Replace;
}
and on delete i am subbmiting the form to a controll like
public ActionResult Delete(int id)
{
ContactPersonManager.Delete(id);
return RedirectToAction("List");
}
As you are using ajax, you could return the URL from your action and have it redirected in javascript:
Controller
public ActionResult Delete(int id)
{
ContactPersonManager.Delete(id);
return Json(new { success = true, redirecturl = Url.Action("List") });
}
Then add something like this to your OnSuccess handler in javascript:
Javascript
function anOnSuccessFunction (data)
{
if (data.success == true)
{
window.location = data.redirecturl;
}
}
Markup
Make sure you point your Ajax options to the javascript function.
xPost.OnSuccess = "anOnSuccessFunction";

ASP.NET MVC - Current Selected value doesnt get selected in IE

In my Action for Editing an item in my model I have:
ViewBag.PossibleSource = context.Source.ToList();
In my View I have:
#Html.DropDownListFor(model => model.SourceID, ((IEnumerable<btn_intranet.Areas.DayBook.Models.DayBookSource>)ViewBag.PossibleSource).Select(option => new SelectListItem
{
Text = (option == null ? "None" : option.SourceName),
Value = option.SourceID.ToString(),
Selected = (Model != null) && (option.SourceID == Model.SourceID)
}))
In Chrome this works as expected. When I pass a model to my view, the current value that's set in my model is the selected value in the list. But in IE8 and 9 it's selected value is the ORIGINAL value my model was set as even though the update does work. So if I selected "hello" originally and then edited to "world". In chrome when i reload the page it will be set to "world" but in IE "hello" is selected in the dropdown even tho "world" is set in my database for my model. It is worth noting these are updated via AJAX
EDIT:
Ajax.Actionlink:
#Ajax.ActionLink(item.ItemNumber, "EditItem", new { id = item.QuoteLineID, enquiryId = item.EnquiryID }, new AjaxOptions()
{
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "EditItem"
})
This loads the form onto the view.
Ajax.BeginForm:
#using (Ajax.BeginForm("EditItem", new { controller = "QuoteLines" }, new AjaxOptions()
{
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "Summary"
}, new { #class = "manual-search cf" }))
{
...Other Model inputs
#Html.DropDownListFor(model => model.SourceID, ((IEnumerable<btn_intranet.Areas.DayBook.Models.DayBookSource>)ViewBag.PossibleSource).Select(option => new SelectListItem
{
Text = (option == null ? "None" : option.SourceName),
Value = option.SourceID.ToString(),
Selected = (Model != null) && (option.SourceID == Model.SourceID)
}))
<input type="submit" class="update-items" value="Update Line" />
}
EditItem Action GET request:
public virtual ActionResult EditItem(int id)
{
try
{
DayBookQuoteLines q = context.QuoteLines.Single(x => x.QuoteLineID == id);
ViewBag.PossibleSource = context.Source.ToList();
if (Request.IsAjaxRequest())
{
return PartialView("_EditItem", q);
}
else
{
return RedirectToAction("SalesDetails", new { controller = "Enquiries", id = q.EnquiryID });
}
}
catch (Exception ex)
{
return PartialView("_Error", ex.Message);
}
}
EditItem Action POST request:
[HttpPost]
public virtual ActionResult EditItem(DayBookQuoteLines q)
{
try
{
ViewBag.PossibleSource = context.Source.ToList();
if (ModelState.IsValid)
{
context.Entry(q).State = EntityState.Modified;
context.SaveChanges();
return PartialView("_GetSummary", context.Vehicles.Where(x => x.EnquiryID == q.EnquiryID).ToList());
}
return PartialView("_EditItem", q);
}
catch (Exception ex)
{
return PartialView("_Error", ex.Message);
}
}
I've fixed it, I renamed my GET request for EditItem to EditItemGet and then in my #Ajax.ActionLink I did:
#Ajax.ActionLink(item.ItemNumber, "EditItemGet", new { id = item.QuoteLineID, enquiryId = item.EnquiryID }, new AjaxOptions()
{
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "EditItem",
HttpMethod = "POST"
})
It was a Cache issue. Thats why it only failed in IE which likes Cache. I read before that making the request a POST request prevents Caching.

How do I process drop down list change event asynchronously?

I have a drop down list that I need to react to asynchronously. I cannot get the Ajax.BeginForm to actually do an asynchronous postback, it only does a full postback.
using (Ajax.BeginForm("EditStatus", new AjaxOptions { UpdateTargetId = "divSuccess"}))
{%>
<%=Html.DropDownList(
"ddlStatus",
Model.PartStatusList.OrderBy(wc => wc.SortOrder).Select(
wc => new SelectListItem
{
Text = wc.StatusDescription,
Value = wc.PartStatusId.ToString(),
Selected = wc.PartStatusId == Model.PartStatusId
}),
new { #class = "input-box", onchange = "this.form.submit();" }
)%>
<div id='divSuccess'></div>
<%
}
When the user selects an item from the list, it does a full postback and the controller method's return value is the only output on the screen. I am expecting the controller method's return value to be displayed in "divSuccess".
[AjaxAwareAuthorize(Roles = "Supplier_Administrator, Supplier_User")]
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult EditStatus(PartPropertiesViewModel partPropertiesViewModel)
{
var part = _repository.GetPart(partPropertiesViewModel.PartId);
part.PartStatusId = Convert.ToInt32(Request.Form["ddlStatus"]);
_repository.SavePart(part);
return Content("Successfully Updated Status.");
}
How about doing this the proper way using jQuery unobtrusively and getting rid of those Ajax.* helpers?
The first step is to use real view models and avoid the tag soup in your views. Views should not order data or whatever. It's not their responsibility. Views are there to display data that is being sent to them under the form of a view model from the controller. When I see this OrderBy in your view it's just making me sick. So define a clean view model and do the ordering in your controller so that in your view you simply have:
<% using (Html.BeginForm("EditStatus", "SomeControllerName", FormMethod.Post, new { id = "myForm" }) { %>
<%= Html.DropDownListFor(
x => x.Status,
Model.OrderedStatuses,
new {
#class = "input-box",
id = "myDDL"
}
) %>
<% } %>
<div id="divSuccess"></div>
and finally in a completely separate javascript file subscribe for the change event od this DDL and update the div:
$(function() {
$('#myDDL').change(function() {
var url = $('#myForm').attr('action');
var status = $(this).val();
$.post(url, { ddlStatus: status }, function(result) {
$('#divSuccess').html(result);
});
});
});
This assumes that in your controller action you would read the current status like this:
[AjaxAwareAuthorize(Roles = "Supplier_Administrator, Supplier_User")]
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult EditStatus(PartPropertiesViewModel partPropertiesViewModel, string ddlStatus)
{
var part = _repository.GetPart(partPropertiesViewModel.PartId);
part.PartStatusId = Convert.ToInt32(ddlStatus);
_repository.SavePart(part);
return Content("Successfully Updated Status.");
}
And when you see this you might ask yourself whether you really need a form in this case and what's its purpose where you could simply have a dropdownlist:
<%= Html.DropDownListFor(
x => x.Status,
Model.OrderedStatuses,
new Dictionary<string, object> {
{ "class", "input-box" },
{ "data-url", Url.Action("EditStatus", "SomeControllerName") },
{ "id", "myDDL" }
}
) %>
<div id="divSuccess"></div>
and then simply:
$(function() {
$('#myDDL').change(function() {
var url = $(this).data('url');
var status = $(this).val();
$.post(url, { ddlStatus: status }, function(result) {
$('#divSuccess').html(result);
});
});
});

Resources