I have a simple question (may not be a simple answer!) with the WebGrid in MVC4.
I have a functional Grid like so
<div id="Submitted">
#Html.Grid(
Model.Submitted, displayHeader: false, fieldNamePrefix: "Submitted_", ajaxUpdateContainerId: "Submitted",
columns: new WebGridColumn[]{
new WebGridColumn(){ ColumnName = "Date",Header = "Date",Style = "",CanSort = false,Format = x => x.Date.ToString(Globals.Default.DATEFORMAT) },
new WebGridColumn(){ ColumnName = "ID",Header = "Review",Style = "", CanSort = false, Format = x=>#Html.ActionLink("Review","Review","Company",new{ID = x.ID },new{}) }
})
</div>
When reloading the "Submitted" div with Ajax when the next page button is clicked, it generates the next page fine - but it's going to the original action on the controller, which should be a full page.
How does it filter out everything other than the grid itself? with some clever C# code or jQuery?
EDIT:
To clarify, I'm not asking how to do the paging better, or myself, as far as I'm concerned the default paging with the webgrid is working perfectly as it should - I'm asking how the WebGrid does it's ajax paging when posting back to an action which is returning a FULL page.
It does this using jquery load() and functionality that allows it to select just the relevant incoming nodes. This is taken from http://msdn.microsoft.com/en-us/magazine/hh288075.aspx
To allow the script to be applied just to a WebGrid, it uses jQuery selectors to identify elements with the ajaxGrid class set. The script establishes click handlers for the sorting and paging links (identified via the table header or footer inside the grid container) using the jQuery live method (api.jquery.com/live). This sets up the event handler for existing and future elements that match the selector, which is handy given the script will be replacing the content.
You should put your grid in a partialview and update it by Ajax. In controller you should find the request's type. If it is a ajax request(by Request.IsAjaxRequest() ) you must return the partialview, otherwise you must return the original view.
If you are using ajax.beginform you must do something like this:
#using (Ajax.BeginForm("Index", new AjaxOptions { OnFailure = "searchFailed", HttpMethod = "POST", UpdateTargetId = "Submitted" }))
{
...
}
<div id="Submitted">
#Html.Partial("_partialviewname", Model)
</div>
rn
and in controller:
public ActionResult Index(int? page)
{
...
if (Request.IsAjaxRequest())
{
return PartialView("_partialviewname", db.model)
}
return View(db.model)
}
Related
I have something like this:
#using (Ajax.BeginForm("Validate", "Basket", new AjaxOptions
{
UpdateTargetId = "panelId",
HttpMethod = "Post",
InsertionMode = InsertionMode.Replace,
OnSuccess = "SuccessMethod"
}))
{
#if(Model != null)
{
my action...
}
else
{
Response.Redirect(Url.Action("Index", "Home"))
}
}
It works perfect when I use submit button, because partial is refreshing, and layout stay the same.
I have a problem, when my Model became null, because user make a remove action on my page. Then I want to make redirect to my home page (different layout), but when I do that (like in my code), I get two layounts on my page, because of InsertionMode.Replace mode.
How can I omit the Ajax.BeginForm in my view?
Because you're using an ajax form (Ajax.BeginForm) the framework overwrites just the form, giving you the two layouts when you redirect from within the ajax form (as only the html within the form is redirected, the rest of the page outside the form is not redirected).
You can get around this with some javascript/jquery:
First, remove the Response.Redirect
This can be replaced by a placeholder div to indicate no results, or the code can check if there were no results - without more code, it can't be determined if/how this would be done in your specific case, so in the general case, add a placeholder, eg:
#if (Model == null)
{
<div class='nomodel'></div>
}
Second, update the OnSuccess code inside SuccessMethod() to check if there's no model (or check if there are no order rows), then redirect the entire page, eg:
if ($(".nomodel").length > 0) {
location.href = '#Url.Action("Index", "Home"))'
}
I'm stuck with a very basic detail in a view.
I want to be able to let the user filter the results in the Index view.
To do this I've created a dropdown list, which gets populated thourgh my viewmodel:
#using (Html.BeginForm("Index", "Captains", FormMethod.Get)) {
<div class="row">
<div class="dropdown">
#Html.DropDownList("Name", new SelectList(Model.SomeProperty), new { id = "FilterList" })
</div>
</div>
#* ... *#
}
Additionally I have a small jQuery snippet to submit the form on the change event:
$('#FilterList').on('change', function () {
var form = $(this).parents('form');
form.submit();
});
The route I have created for this looks like this:
routes.MapRoute(
name: "IndexFilter",
url: "{controller}/{action}/{Name}",
defaults: new { Name = UrlParameter.Optional}
);
After the submit event I get redirected to the url /Index?Name=ChosenValue
This is filtering totally correct. However I'd like to get rid of the querystring and transform the route to /Index/ChosenValue.
Note: "Name", "ChosenValue" & "SomeProperty" are just dummy replacements for the actual property names.
Instead of submitting the form, you can concatenate /Captains/Index/ with the selected value of the dropdown and redirect to the url using window.location.href as below
$('#FilterList').on('change', function () {
window.location.href = '/Captains/Index/' + $(this).val();
});
I think you're looking for the wrong routing behavior out of a form submit. The type of route resolution that you're hoping to see really only happens on the server side, where the MVC routing knows all about the available route definitions. But the form submission process that happens in the browser only knows about form inputs and their values. It doesn't know that "Name" is a special route parameter... it just tacks on all the form values as querystring parameters.
So if you want to send the browser to /Index/ChosenValue, but you don't want to construct the URL from scratch on the client, you need to construct the URL on the server when the view is rendering. You could take this approach:
<div class="row">
<div class="dropdown">
#Html.DropDownList("Name", new SelectList(Model.SomeProperty),
new {
id = "FilterList",
data_redirect_url = #Url.Action("Index", "Captains", new { Name = "DUMMY_PLACEHOLDER" })
})
</div>
</div>
Above you're setting the URL with a dummy "Name" value that you can replace later, then you'll do the replacement with the selection and redirect in javascript:
$('#FilterList').on('change', function () {
var redirectUrl = $(this).data('redirect-url');
window.location.href = redirectUrl.replace("DUMMY_PLACEHOLDER", $(this).val());
});
If you are wanting to drop the query string off the url because it looks weird, then change your FormMethod.Post.
However, to really answer your question, I've tried the following successfully (Note: this might be considered a hack by some)
In short: update the action url on the form element when the list changes, client side.
$('#FilterList').on('change', function () {
var form = $(this).parents('form');
var originalActionUrl = form.attr("action");
var newActionUrl = originalActionUrl + "/" + $(this).val();
form.attr("action", newActionUrl);
console.log(form.attr("action"));
form.submit();
});
You will need to change your controller's signature to match whatever optional param value you specify in your route config. In your example, "Name".
I am using MVC to create part of a website. In one of my Views I have a DropDownList. When a new drop down list option is selected, or in other words onchange, I want my page to be redirected to a specific Controller ActionResult. I am able to get to MyAction ActionResult if there are no parameters, however I can't figure out how to send in the needed parameters.
My Controller Action:
public virtual ActionResult MyAction(int param1, int param2)
{
return View();
}
My DropDownList in View:
#Html.DropDownList(
"viewDataItem", Model.MyEnumerableList as SelectList,
new { onchange = #"
var form = document.forms[0];
form.action='MyAction';
form.submit();"
} )
The above code calls MyAction, however it does not send in the parameters. Is there a way to somehow add the parameters to this code?
Another thought was to somehow use #{Response.Redirect(#Url.Action("MyAction", "myController", new { param1 = 2, param2= 3 }));} as my DropDownList action since Response.Redirect allows me to redirect to MyAction with parameters. Is there a way to somehow make onchanged = Response.Redirect?
The tried making onchange equal the response, but the nothing happens when I change my option:
#Html.DropDownList(
"name", Model.MyEnumerableList as SelectList,
new
{
onchange = {Response.Redirect(#Url.Action("MyAction", "controllerName", new { param1 = 5, param2 = 3 }));}
})
In short, how do I call an ActionResult with parameters whenever my DropDownList option is changed?
Similar questions were asked here and here, but the answers provide in those links all use JavaScript and I don't know how to use JS with cshtml. I tried some of those answers, but none of them solved my problems.
You can specify on the onchange event a javascript function and inside that function:
var url = '#Html.Raw(Url.Action("MyAction", "controllerName", new { param1=5, param2=2 }))';
and then:
window.location = url;
Finally the code should be:
#Html.DropDownList(
"viewDataItem", Model.MyEnumerableList as SelectList,
new { onchange = "SelectionChanged()"
} )
<script>
function SelectionChanged()
{
var url = '#Html.Raw(Url.Action("MyAction", "controllerName", new { param1=5, param2=2 }))';
window.location = url;
}
</script>
Is there a way to somehow add the parameters to this code?
Sure, there are many ways. One of them would be:
#Html.DropDownList(
"viewDataItem", Model.MyEnumerableList as SelectList,
new { onchange = #"
var form = document.forms[0];
form.action='MyAction?param1=5¶m2=3';
form.submit(); /*Just make sure that form 'method' attribute is set to 'post'*/"
} )
But a much better way is described in the answer you mentioned.
Is there a way to somehow make onchanged = Response.Redirect?
Not the way you're trying to use it. onchanged is a javascript event, and javascript knows nothing about Response property or other MVC server-side stuff.
I have a page, that should update a "process" kinda window when an action is aplied. Kinda like a visible log. Click "start upload" and the div tag underneath will be updated with information.
The problem is, that when i click the "start upload" link it just jumps to that page and don't do a ajax call and update the div.
Controller
public ActionResult ProcessWindow(decimal id)
{
IMG_SETTINGS_FOLDERS img_settings_folders = db.IMG_SETTINGS_FOLDERS.
Single(i => i.SETTINGS_FOLDER_ID == id);
return PartialView("ProcessWindow", img_settings_folders);
}
View
#Ajax.ActionLink("Start upload", "ProcessWindow",
new { id = Model.SETTINGS_FOLDER_ID },
new AjaxOptions { UpdateTargetId = "processWindowssssss" })
<div id="processWindowssssss"></div>
Solved...
When you use unobtrusive ajax, you need to include "jquery.unobtrusive-ajax.min.js"...
If people who write toturials were to read this, please extend your "js" include info to contain this information too.
Answer found from Brad Wilson on Unobtrusive Ajax. http://bradwilson.typepad.com/blog/2010/10/mvc3-unobtrusive-ajax.html
\T
I have a list of Payees in a drop down box on my form. I would like to populate a different drop down, based on the selected item of the Payee drop down, without post backs and all that.
So, I created a method in my controller that does the work:
private JsonResult GetCategories(int payeeId)
{
List<CategoryDto> cats = Services.CategoryServices.GetCategoriesByPayeeId(payeeId);
List<SelectListItem> items = new List<SelectListItem>();
foreach(var cat in cats)
{
items.Add(new SelectListItem {Text = cat.Description, Value = cat.CategoryId.ToString()});
}
return Json(items);
}
Now, I am unsure what to add to my view to get this to work.
At the moment, all I have is this:
<% using (Html.BeginForm())
{%>
<p>
<%=Html.DropDownList("SelectedAccountId", Model.Accounts, "Select One..", null) %>
</p>
<p>
<%=Html.DropDownList("SelectedPayeeId", Model.Payees, "Select One...", null) %>
</p>
<input type="submit" value="Save" />
<%
}%>
they populate fine... so when the user selects the SelectedPayeeId drop down, it should then populate a new (Yet to be created?) drop down which holds categories, based on the SelectedPayeeId.
So, I think I need to create a JQuery function (Never done JQuery.. so not even sure where it goes) which monitors the Payee drop down for an onChange event? And then call the method I created above. Does this sound right, and if so, can you guide me in how to achieve this?
Your reasoning so far is totally sound. First you are going to want to include the jquery library in your View / Master. You can download a copy of jquery from http://jquery.com/. Add the file to you project and include a <script src="/path/to/jquery.js"> to the <head> of your document. You are going to want to add another dropdown to your View (and probably another property to your model). We'll call this 'SelectedCategoryId:'
<%=Html.DropDownList("SelectedCategoryId", null, "Select One...", new { style = "display:none;"}) %>
We've set the style of this Drop Down to not be visible initially because there is nothing to select inside of it. We'll show it later after we generate some content for it. Now, somewhere on your page you will want to include a <script> block that will look something like this:
$(document).ready(function() { $('#SelectedPayeeId').change(function() {
$.ajax({
type: 'POST',
url: urlToYourControllerAction,
data: { payeeId: $(this).val() },
success: function(data) {
var markup = '';
for (var x = 0; x < data.length; x++ ) {
markup += '<option value="' + data[x].Value + '">'+data[x].Text+'</option>';
}
$('#SelectedCategoryId').html(markup).show();
}
}); }); });
This code binds the anonymous function written above to the DOM element with the ID of 'SelectedPayeeId' (in this case your dropdown). The function performs an AJAX call to the url of your method. When it receives the results of the request (your JSON you returned) we iterate over the array and build a string of the html we want to inject into our document. Finally we insert the html into the 'SelectedCategoryId' element, and change the style of the element so it is visible to the user.
Note that I haven't run this code, but it should be (almost) what you need. jQuery's documentation is available at http://docs.jquery.com/Main_Page and the functions I used above are referenced here:
.ready()
.change()
jQuery.ajax()
.html()
.show()
You'd need to make the GetCategories as a public method as it would correspond to an action handler in your controller.
Your jquery code can look like:
<script type="text/javascript">
$(function() {
$('#SelectedPayeeId').change(function() {
$.get('<%= Url.Action("GetCategories", "YourControllerName") %>',
{payeeId: $(this).val()},
function(data) {
populateSelectWith($("#Category"), data);
});
});
//Place populateSelectWith method here
});
</script>
The populateSelectWith can fill your dropdown with data like:
function populateSelectWith($select, data) {
$select.html('');
$select.append($('<option></option>').val('').html("MYDEFAULT VALUE"));
for (var index = 0; index < data.length; index++) {
var option = data[index];
$select.append($('<option></option>').html(option));
}
}
I have not tested this code, but I am hoping it runs okay.
You can find syntax for the jquery ajax get here
Since you are not posting any data to the server, you can might as well decorate your controller action with a [HttpGet] attribute