ASP.NET MVC - Current Selected value doesnt get selected in IE - asp.net-mvc-3

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.

Related

DevExpress - Ajax form return null object

i work with Ajax.BeginForm
#model Shared.DataContracts.ConfigurationTransports
#using (Ajax.BeginForm("Save", "ConfigurationTransports",
new AjaxOptions
{
HttpMethod = "POST",
InsertionMode = InsertionMode.Replace
}))
{
Html.RenderPartial("~/Views/ConfigurationTransports/ConfigurationPartialContent.cshtml", Model);
}
And my easy form
#model Shared.DataContracts.ConfigurationTransports
#Html.DevExpress().Label(s =>
{
s.Name = "Id";
s.ClientVisible = false;
}).Bind(Model.Id).GetHtml()
#Html.DevExpress().CheckBox(settings =>
{
settings.Name = "checkBoxUseStop";
settings.Properties.ValueUnchecked = 0;
settings.Properties.ValueChecked = 1;
settings.Text = Resources.UseStops;
}).Bind(Model.UseStop).GetHtml()
#Html.DevExpress().Button(settings =>
{
settings.Name = "btnSave";
settings.UseSubmitBehavior = true;
}).GetHtml()
When I click save a post to method Save and parameter ConfigurationTransports is empty without value, but if i load my form i have there values from my send object.
public ActionResult Save(ConfigurationTransports transport)
{
//Some logic method
return View("Index", preprava.GetData());
}
I read a lot of topic on devexpress forum, but i cant find solution.
Do you have any idea?
thx
decorate your Action with [HttpPost] Annotation
[HttpPost]
public ActionResult Save(ConfigurationTransports transport)
{
//Some logic method
return View("Index", preprava.GetData());
}

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.

Controller return incorrect data with ajax ActionLink in mvc

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

Auto complete is not working in my asp.net MVC

i have the following repository method to search for users containing a search parameter:-
public IEnumerable<User> searchusers2(string q)
{
return from u in entities1.Users
where (u.UserID.Contains(q) || string.IsNullOrEmpty(q))
select u;
}
which is called suing the following action method:-
public ActionResult QuickSearch(string term)
{
var users = r.searchusers2(term);
users.Select(a => new { value = a.UserID });
return Json(users, JsonRequestBehavior.AllowGet);
}
and on the view i have the following code:-
#using (Ajax.BeginForm("Search", "User", new AjaxOptions
{
HttpMethod = "POST",
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "searchResults",
LoadingElementId = "progress"
}))
{
<input type="text" name="q" data-autocomplete-source="#Url.Action("QuickSearch", "User")" />
<input type="hidden" name="classid" value="#ViewBag.classid"/>
<input type="submit" value="Search" />
}
the above code is not working but if i change my action method to be as follow (without using a repository to perform the search) then the auto complete will work fine,,, so what might be causing this problem:-
public ActionResult QuickSearch(string term)
{
var users = entities1.Users
.Where(e => e.UserID.Contains(term))
.Select(r => new {value = r.UserID });
return Json(users, JsonRequestBehavior.AllowGet);
}
In the repository-version you're returning the whole User object in Json, The Select in
public ActionResult QuickSearch(string term)
{
var users = r.searchusers2(term);
users.Select(a => new { value = a.UserID });
return Json(users, JsonRequestBehavior.AllowGet);
}
is doing nothing because you're not storing the returned values, you'll either need to chain the call together, e.g:
public ActionResult QuickSearch(string term)
{
var users = r.searchusers2(term).Select(a => new { value = a.UserID });
return Json(users, JsonRequestBehavior.AllowGet);
}
or use a separate variable:
public ActionResult QuickSearch(string term)
{
var users = r.searchusers2(term);
var values = users.Select(a => new { value = a.UserID });
return Json(values, JsonRequestBehavior.AllowGet);
}

MVC3 Custom HTMLHelper, partial view or other solution to apply DRY principle

I've got an MVC3 Read Only view that contains a table displaying properties for an Item.
For many of the properties of the Item, we track the changes a Vendor has made to the item. So, for example, a vendor may update a property named 'Color' from a value of 'Blue' to 'Red'. In this View a table lists each property tracked in a table row, with a column showing the 'Old Value' and the 'New Value'. The next column either shows the current change's status (Awaiting Approval, Approved, or Rejected). However, for Admin users, the column will contain Links ('Approve', 'Reject', or 'Reset to Awaiting Approval').
My markup and Razor code for this is very repetitive and getting out of hand. I'd like to create an HTMLHelper for this, or possibly a partial view that I can use to move all the code into and then use it for each Item Property.
Here is an example of the code used for one Property. This code is repeated for another 10 or so properties.
I'm using some jquery and ajax for the actions. For example, when an change is rejected, the user must enter a reason for rejecting the change.
<tr id="rowId-color">
<td>#Html.LabelFor(model => model.Color)</td>
<td>#Html.DisplayFor(model => model.Color)</td>
#if (Model.ChangeLog != null && Model.ChangeLog.Item("Color") != null) {
var change = Model.ChangeLog.Item("Color");
var changeStatus = (ItemEnumerations.ItemChangeStatuses)change.ItemChangeStatusID;
<td>#change.OldValueDisplay</td>
<td id="tdstatusId-#change.ItemChangeID">
#if (changeStatus == ItemEnumerations.ItemChangeStatuses.AwaitingApproval && User.IsInRole("TVAPMgr")) {
#Ajax.ActionLink("Approve", "Approve", new { itemChangeID = change.ItemChangeID }, new AjaxOptions { HttpMethod = "POST", Confirm = "Approve this change?", OnSuccess = "actionCompleted" })
#Html.Raw("|")
<a href="#dialog" name="reject" data-id="#change.ItemChangeID" >Reject</a>
}
else if ((changeStatus == ItemEnumerations.ItemChangeStatuses.Rejected || changeStatus == ItemEnumerations.ItemChangeStatuses.Approved) && User.IsInRole("TVAPMgr")) {
#Ajax.ActionLink("Reset to Awaiting Approval", "Reset", new { itemChangeID = change.ItemChangeID }, new AjaxOptions { HttpMethod = "POST", Confirm = "Reset this change to Awaiting Approval?", OnSuccess = "actionCompleted" })
}
else {
#changeStatus.ToDisplayString()
}
</td>
<td id="tdreasonId-#change.ItemChangeID">#Html.DisplayFor(m => m.ChangeLog.Item(change.ItemChangeID).RejectedReason)</td>
}
else {
<td colspan="3">No Change</td>
}
</tr>
This really sounds more like a DisplayTemplate for the ItemChangeModel type, that way you can just do:
<tr id="rowId-color">
<td>#Html.LabelFor(model => model.Color)</td>
<td>#Html.DisplayFor(model => model.Color)</td>
#Html.DisplayFor(m => m.ChangeLog.Item("Color"))
</tr>
For each ChangeLog cell and the display template then is like a mini-view with a typed model of ItemChangeModel. So your view file would like like this:
#model ItemChangeModel
#if(Model != null) {
<td>#Html.DisplayFor(m => m.OldValueDisplay)</td>
<td id="tdstatusId-#Model.ItemChangeID">
#switch((ItemEnumerations.ItemChangeStatuses) Model.ItemChangeStatusID) {
case ItemEnumerations.ItemChangeStatuses.AwaitingApproval:
if(User.IsInRole("TVAPMgr")) {
#Ajax.ActionLink("Approve", "Approve", new { itemChangeID = change.ItemChangeID }, new AjaxOptions { HttpMethod = "POST", Confirm = "Approve this change?", OnSuccess = "actionCompleted" })
#Html.Raw("|")
<a href="#dialog" name="reject" data-id="#change.ItemChangeID" >Reject</a>
}
break;
case ItemEnumerations.ItemChangeStatuses.Rejected:
case ItemEnumerations.ItemChangeStatuses.Approved:
if(User.IsInRole("TVAPMgr")) {
#Ajax.ActionLink("Reset to Awaiting Approval", "Reset", new { itemChangeID = change.ItemChangeID }, new AjaxOptions { HttpMethod = "POST", Confirm = "Reset this change to Awaiting Approval?", OnSuccess = "actionCompleted" })
} else {
#changeStatus.ToDisplayString()
}
#break;
}
</td>
<td id="tdreasonId-#change.ItemChangeID">#Html.DisplayFor(m => m.RejectedReason) </td>
} else {
<td colspan="3">No Change</td>
}
(Hard to code in editor box, this could use some cleanup, but I think you will get the idea)
You add this display template (with the file name ItemChangeModel.cshtml) to the Views\Shared\DisplayTemplates folder and it will get used whenever a DisplayFor call is made on that type.
Its been noted in comments that you can't use a method in DisplayFor, but you can change that to an indexed property:
public class ChangeLog
{
public ItemChangeModel this[string key] { get { return Item("Color"); } }
}
Then use:
#Html.DisplayFor(m => m.ChangeLog["Color"])
You haven't shown nor explained how your domain and view models look like but I suspect that what you are using here is not an appropriate view model for this specific requirement of the view. A better view model would have been one that has a list of properties to approve which would be shown in the table.
Anyway, one possible approach is to write a custom HTML helper so that your view looks like this:
<tr id="rowId-color">
#Html.DisplayFor(x => x.Color)
#Html.ChangeLogFor(x => x.Color)
</tr>
...
and the helper might be something along the line of:
public static class HtmlExtensions
{
public static IHtmlString ChangeLogFor<TProperty>(
this HtmlHelper<MyViewModel> html,
Expression<Func<MyViewModel, TProperty>> ex
)
{
var model = html.ViewData.Model;
var itemName = ((MemberExpression)ex.Body).Member.Name;
var change = model.ChangeLog.Item(itemName);
if (change == null)
{
return new HtmlString("<td colspan=\"3\">No Change</td>");
}
var isUserTVAPMgr = html.ViewContext.HttpContext.User.IsInRole("TVAPMgr");
var changeStatus = (ItemChangeStatuses)change.ItemChangeStatusID;
var sb = new StringBuilder();
sb.AppendFormat("<td>{0}</td>", html.Encode(change.OldValueDisplay));
sb.AppendFormat("<td id=\"tdstatusId-{0}\">", change.ItemChangeID);
var ajax = new AjaxHelper<MyViewModel>(html.ViewContext, html.ViewDataContainer);
if (changeStatus == ItemChangeStatuses.AwaitingApproval && isUserTVAPMgr)
{
sb.Append(
ajax.ActionLink(
"Approve",
"Approve",
new {
itemChangeID = change.ItemChangeID
},
new AjaxOptions {
HttpMethod = "POST",
Confirm = "Approve this change?",
OnSuccess = "actionCompleted"
}).ToHtmlString()
);
sb.Append("|");
sb.AppendFormat("Reject", change.ItemChangeID);
}
else if ((changeStatus == ItemChangeStatuses.Rejected || changeStatus == ItemChangeStatuses.Approved) && isUserTVAPMgr)
{
sb.Append(
ajax.ActionLink(
"Reset to Awaiting Approval",
"Reset",
new {
itemChangeID = change.ItemChangeID
},
new AjaxOptions {
HttpMethod = "POST",
Confirm = "Reset this change to Awaiting Approval?",
OnSuccess = "actionCompleted"
}
).ToHtmlString()
);
}
else
{
sb.Append(changeStatus.ToDisplayString());
}
sb.AppendLine("</td>");
sb.AppendFormat(
"<td id=\"tdreasonId-{0}\">{1}</td>",
change.ItemChangeID,
html.Encode(model.ChangeLog.Item(change.ItemChangeID).RejectedReason)
);
return new HtmlString(sb.ToString());
}
}
A better approach would be to re-adapt your view model to the requirements of this view and simply use display templates.

Resources