Basically I get a value from a dropdownlist and pass it to a client method through AJAX. Based on this value, I get data, which I want to put into a textbox.
<script type="text/javascript">
$('#dropdownlist').change(function () {
$.post('/Index/GetJSON/' + this.value, null,
function (data) {
$('#somefield').val(data)
});
});
</script>
So this method gets called:
[HttpPost]
public JsonResult GetJSON(int ID)
{
return Json(data);
}
Markup
#Html.EditorFor(m => m.somefield)
somefield does change it's value visually. But it does not get updated when I inspect it's value. It's as if val(data.ID) doesn't register to the model. Due to my code, I can't call ModelState.Clear() either...
The reason I use this approach, and not Ajax.Form and partial views, is because I have all the markup inside a HTML.BeginForm (which is submitted) with many different dropdownlists interacting through textboxes through AJAX, and you cannot nest Ajax.Form with HTML.BeginForm. Thus I cannot submit changes to the model through the Ajax.Form and call ModelState.Clear().
.val() sets the value property of an element if you want the change to be reflected in the elements value attr use .attr()
$('#somefield').attr('value', data)
Related
This is a follow on to similar question but taking suggestions into account.
Render part of page on dropdown selection
I have a chart on my main view which I would like to update partially when a dropdown selects different values.
The page renders correctly the first time, but when I select a new value in the dropdown, then I think the .submit script is failing in the script .submit() because when I put a break on window.submitAjaxForm it is never reached.
_PnlChart.cshtml
<img src="#Url.Action("CreateTraderPnlChart3")" width="600" height="600" align="middle" vspace="50" />
My mainview Index.cshtml:
<div class="w3-half">
<div id="ExportDiv">
#{ Html.RenderPartial("_PnlChart");}
</div>
#using (Ajax.BeginForm("GetEnvironment",
new RouteValueDictionary { { "Environment", "" } }, new AjaxOptions() { UpdateTargetId = "ExportDiv" }, new { id = "ajaxForm" } ))
{
#Html.DropDownList("PeriodSelection",
new SelectList((string[])Session["Periods"]),
(string)Session["Period"],
new
{ onchange = "submitAjaxForm()" })
}
</script>
<script type="text/javascript">
$('form#ajaxForm').submit(function(event) {
eval($(this).attr('onsubmit')); return false;
});
window.submitAjaxForm = function(){
$('form#ajaxForm').submit();
}
</script>
</div>
My controller:
public ActionResult PeriodSelection(string dropdownlistReturnValue) // dont know what dropdownlistReturnValue is doing?
{
Session["Period"] = dropdownlistReturnValue;
return PartialView("~/Views/Employee/_PnlChart.cshtml");
}
This line in your code,
eval($(this).attr('onsubmit')); return false;
I am not sure what you were intending to do here. But from your question, i assume you wanted to do a form submission. But that line will not submit the form. The expression $(this).attr('onsubmit') is going to return undefined as your form does not have an onsubmit attribute defined.
But you already have the form submit code in your other method (submitAjaxForm). So if you simply remove the $('form#ajaxForm').submit handler (apparently it does not do anything useful), your code will work. When you change the dropdown, it will make an ajax form submission.
But your form action is set to GetEnvironment action method. That means your ajax form submission will be to that action method. In your question you have a different action method which returns the updated chart content. It does not makes sense!
I personally prefer to write handwritten ajax calls instead of relying on the ajax action helper methods. The below is the code i would probably use (Except the dropdownlist code. read further)
<div id="ExportDiv">
#{ Html.RenderPartial("_PnlChart");}
</div>
#Html.DropDownList("PeriodSelection",
new SelectList((string[])Session["Periods"]),
(string)Session["Period"], new
{ data_charturl = Url.Action("PeriodSelection","Home")})
Now listen to the change event of the SELECT element.
$(function(){
$("#PeriodSelection").change(function(){
var v = $(this).val();
var url=$(this).data("charturl")+'?dropdownlistReturnValue='+v;
$("#ExportDiv").load(url);
});
});
You should consider using the a view model to pass the Dropdownlist data. Why not use the DropDownListFor helper method ? It looks much clean, Mixing a lot of C# code (See all the session casting and all.) makes it kind of dirty IMHO.
I'm looping through a collection on my model using Razor to display it. As an example:
#foreach(var item in myCollection)
{
<span id='item-#item.Id'>#item.Quantity</span>
<button type='button' onclick='updateQuantity(#item.Quantity+1);'>Add One</button>
}
In this example, updateQuantity performs an AJAX request, gets the new quantity back, and updates item-#item.Id with the new quantity. However, because #item.Quantity is pulled from the model (passed in via the page's GET method, #item.Quantity is never updated with the new value until the page is reloaded.
My question is: How can I make sure I'm always using the latest value, without having to reload the page?
Change the button inside your foreach loop like this:
#foreach(var item in myCollection)
{
<span id='item-#item.Id'>#item.Quantity</span>
<button id='updateButton' type='button'>Add One</button>
}
And, add this script to your View:
<script>
$("#updateButton").click(function() {
var quantity = $("#item-#item.Id").text();
updateQuantity(quantity);
})
</script>
And, in your updateQuantity() function, update the text inside the span after getting it back through Ajax.
I'm trying to make a HTML table with a checkbox column where this checkbox column is from a ViewModel:
public string FirstName ...
public string LastName ...
public bool Checked ...
I want to get the List<ViewModel> and pass it to the controller, using a Partial View, to verify the checked columns, because I want to delete the checked lines.
If I wanted to get the checked columns in the same controller, I do, but in a different controller, I don't. In my case, this 'Partial View' is a BS Modal.
What you need is a partial rendered through Ajax. You call the action method from a modal using load and POST the form data so it removes checked lines. You can call any controller you need from this, all you need is:
$('#target').load('#Html.Url("Action", "Controller")');
And on submit:
$('#targetform').submit(function (e) {
var data = JSON.stringify($(e.currentTarget).serialize());
$.post('#Html.Url("Action", "Controller")', data, function (html) {
$('#target').html(html);
});
e.preventDefault();
});
I have an ASP.NET MVC application that displays a list of items. In my view page I loop over the items and render each item with partial view, like so:
#foreach(var item in Model.items)
{
<li>
#Html.Partial("ItemView", item)
</li>
}
In the item view, I wrap each item with a form that has a 'Delete' button, like this:
#using(Html.BeginForm(...))
{
#Html.HiddenFor(m=>m.Id)
<label>#Model.Name (#Model.Id)</label>
<input type="submit" value="Delete"/>
}
The items are rendered properly, the resulting page has a nice list of all the items with their proper names and IDs displayed.
EDIT: The same happens with #Hidden, apparently, contrary to what I wrote before.
In addition, this only happens the second time the form is rendered (that is, after one of the Delete buttons is clicked), the first time everything is working properly. My action methods looks like this:
public ActionResult AllItems()
{
var model = new AllItemsModel();
return PartialView(model);
}
public ActionResult Delete(DeleteModel model)
{
.... Perform the delete ...
return PartialView("AllItems", new AllItemsModel());
}
Why is this happening?
I suspect that this happens because you already have an Id parameter in your RouteData:
public ActionResult SomeAction(int id)
{
var model = ...
return View(model);
}
and you have requested the page with /somecontroller/someaction/123. The HiddenFor helper now uses the Id from the route values and not the id of the item. Try renaming the property on your item view model to something different than id. For example ItemId.
Another possibility is that the problem occurs only after the postback and not when the page is initially rendered. Showing your POST action might help in exploring this possibility further.
UPDATE:
Alright, now that you have shown your POST action things are much more clear:
public ActionResult Delete(DeleteModel model)
{
.... Perform the delete ...
return PartialView("AllItems", new AllItemsModel());
}
you are basically creating a new view model here and passing it to the partial view. But HTML helpers always use the value from the ModelState when binding. And only after that the value from your view model. So if you intend to modify properties on your model inside your POST action make sure that you have removed this value from the ModelState first. In your example since you have completely scratched the entire view model (by creating a new AllItemsModel()) you could clear the entire ModelState:
public ActionResult Delete(DeleteModel model)
{
.... Perform the delete ...
// Clear the modelstate otherwise the view will use the values that were initially posted
// and not the values from your view model
ModelState.Clear();
return PartialView("AllItems", new AllItemsModel());
}
This behavior is by design and applies to all HTML helpers, not only the HiddenFor helper.
I have a view that is used for editing stuff, say Orders. Orders have line items that can be added arbitrarily. So a main view and nested partialviews.
Each partial should have an ajax form for tweaking quantities of each line item or whatever.
Thus:
Html.BeginForm()
{%>
Ship to: blah blah blah
<%
Ajax.BeginForm("EditLineItem", "Order", new { OrderLineItemID = Model.ObjectID }, itemAjaxOptions))
{
Item qty blah blah blah
<--! (ajax form's submit button, etc.)-->
}
%>
<--! (ajax form's submit button, etc.)-->
<%
}
I have a controller that looks like this:
[ActionName("Edit")]
[AcceptVerbs(HttpVerbs.Post)]
[ValidateAntiForgeryToken]
public ActionResult Edit(int orderID)
{
blah, blah
}
[ActionName("EditLineItem")]
[AcceptVerbs(HttpVerbs.Post)]
[ValidateAntiForgeryToken]
public ActionResult EditLineItem(Guid orderLineItemID)
{
blah, blah
}
My trouble is that when I submit the Ajax form, I get the Edit method instead of the EditLineItem methods. Both routes are mapped. Is there some gotcha like "you can't submit an Ajax form inside of an Html form" that I don't know about?
I tried the exact same thing a while ago. No matter what I did, it wouldn't do the AJAX submit. So I think the answer is: yes, you can't put a submit button for an AJAX form inside a regular html form.
But, why would you have partial submits merged with full submits?
The easiest workaround to this imo would be to use JSON requests with jQuery.
for instance, updating a quantity span text when you change a dropdownlist (id=Order):
<script type="text/javascript">
$(document).ready(function() {
$('select#Order').change(function() {
$.getJSON('/Orders/UpdateQty/' + this.value, {},
function(data) {
$('#qty').html(data);
});
});
});
</script>
And the code in the "Orders" controller:
public class OrdersController : Controller
{
public ActionResult UpdateQty(int id)
{
return Json(yourLibrary.getQuantities(id));
}
}
This Link might help.
Regards
Edit:
So.. the link no longer exists. But thanks to the internet wayback machine, we have this copy :)
AFAIA the AjaxForm is still renders as a form tag, so you'd be nesting forms, which as you've found is a no no.
I reckon Francisco is on the right lines (tho I'd suggest implementing a post rather than a get as you are updating something).
Kind regards,
TP