I'm building a grid in ASP.NET MVC and I have the following issue:
Above the grid i have a column selector which lets people customize the columns being shown. This is a form with a submit button so that people can add/remove multiple columns at once without going trough multiple postbacks.
Below the grid I have paging. This is paging trough actionlinks (a href's).
alt text http://thomasstock.net/mvcget.jpg
What happens when a user add/removes columns is that the form gets submitted to http://localhost:56156/?columnsToDisplay=EmployeeId and ofcourse the grid jumps back to page 1. I'd like to keep the grid on the page the user was currently on. So I need a way to include the current querystring parameters into the form's action attribute.
The other way around too: I need a way to do the same with actionlinks. But this is less necessary as I could always replace the a href's with buttons and put them in a form. But I'd rather not do that.
I'm looking for a solution without javascript! I can do it myself in javascript, but I'd like my grid to work perfectly on javascript-disabled browsers.
Any help is appreciated.
Edit:
Oh yeah, to make it a bit harder, I'm also looking for a solution without cookies/session variables. :-)
You need to add the line below into your column selector form
<input type="hidden" name="page" value="<%=Request.QueryString["page"]%>" />
Related
I have about 20 forms, each with 15-20 textbox inputs each.
Once the user submits the form, all their values need to be confirmed, this is done by replacing each textbox with a label control that shows the entered value.
The user may click on a back button to edit the data, in which case the textboxes re-appear, or they can confirm their data submission.
What would be the best way to handle this in MVC?
Thanks
I would recommend having different views for editing and showing data. This could be useful if you would like to omit or add some extra of the fields, keeping your view logic simple. You could store the form data in the database with some flag indicating that it is not confirmed yet. After confirmation you would only change the flag of the record. Another option is to store form data in tempData or Session and save it after confirmation.
The quickest way would probably be to have both on the page and bound to the same Model properties but wrap them in some simple render logic. an example off the top of my head in razor could be something like
#if (is in edit state){
<field markup>
#}
else{#
<label markup>
#}
Its been a while since I've worked on an MVC app but that's how i would have done it back then i think.
Before I start work I would like to get some ideas. What I have is an MVC3 page that I currently use to display rows of data. There are many rows so I would like to filter them. Ideally at the top of my page I would like to have a select drop down box and a refresh button with rows of data appearing below when the refresh button is clicked.
I can imagine doing this with Ajax and then having the data from my controller populate new HTML text between a DIV.
Does this sound like the best approach? I am not looking for a person to write code for me. Just want to be sure my solution sounds like a good way to go.
thank you
i recommend this approach:
http://geekswithblogs.net/michelotti/archive/2008/06/28/mvc-json---jsonresult-and-jquery.aspx
You can 'enchance' it with AJAX of course, but do not forget about users with disabled javascript. Make it work without client scripting, then enchance it, when its working.
I also think that you can simply create controller action, that is accepting parameters like pageNumber and amountOfItems. Then in your controls at page, you can just change values (number of page etc..) and use them in call for your controller action at form submit.
What is a good approach in ASP.NET MVC for implementing a complex form where sections of the form are shown and hidden based on a user's inputs?
My background is in Webforms. I am frequently asked to build forms where a user selects an option from a dropdown list, triggering a handful of new fields to appear. A different selection might cause a different set of fields to appear.
In the past, I would handle this scenario via an UpdatePanel and a wrapper Panel around the fields that I want to show or hide. Validation is automatically disabled when the fields are hidden.
Going forward, I'd like to make use of MVC's attribute-based model validation, but is it possible to make the validation conditional on the values of other properties?
Also, how can I handle the toggling of blocks of form fields? I know how to do it manually in jQuery, but I'm hoping there's an approach that ties in with validation and server-side code.
I am liking MVC much better overall, but I haven't figured out how to handle this type of scenario very well. Likely I just need to shift my thinking to fit better with the MVC approach.
Josh,
The first thing I's suggest is to make sure you use ViewModels for the pages that are mode complicated. A ViewModel is basically a Model you create for a specific View; for example, a ViewModel could be a composition of other classes.
As for dynamically changing the fields on your View, the best way is to use jQuery (or any other javascript library) to do it.
I also migrated from a web form environment and I know is difficult to change gears at the begining, but trust me, doing a simple jQuery even handler is much simpler than having to put in place a control panel and then the event handlers.
Not to mention that is much more efficient; update panels are after all making partial posts to the page, sometimes, with jQuery you don't even need to do that.
After a few projects with MVC, I actually now find it time consuming to go and do the Update Panels on web forms ;)
Hope this helps,
-Covo
I know this might not be the answer you're looking for, but I personally don't think complex forms are very user friendly in the first place and I always try to split them up into simpler forms where possible, or to simplify the form. I've come across many forms in websites where there are a raft of "fields" where there should really be a few questions for the user to answer. Simple stuff which gets to the point of what they want to achieve rather than the field values, along with a lot of application specific knowledge needed to set those fields to the right values.
If you still want to go ahead with a complex form, then as the other answers have already stated there are facilities provided by MVC to do that, but there isn't any set way. So, it's down to you to figure out what will work best for your users.
Traditional asp.net webforms did alot of "magic" for you whereas you have to be aware of the work that goes into creating the "magic" in asp.net MVC. The benefit is that with MVC you have more control over what is happening which can also enhance performance.
In asp.net webforms an UpdatePanel is used for ajax calls. If you need to got to the server asynchronously(without doing a full post back) then use ajax via JQuery. See below for example:
$.ajax({
type: "get",
url: "/YourController/YourAction",
success: function (obj) {
//any logic you want to do upon success
}
});
The above example will do an ajax HTTP GET call to /YourController/YourAction.
In order to handle "toggling of blocks", if you don't need to go to the server for data and you simply want to do it on the client, then use simple jquery. JQuery has a function for toggling items.
http://api.jquery.com/toggle-event/
Because of the way MVC works in contrast to Webforms you're stuck with the responsibility of really thinking about what happens on the client and what happens on the server separately as not a lot of meta-data is being passed back to give us that happy Webforms feeling.
However, there is a notion when using the built-in AJAX libraries when you render a form that you can have it auto do an update once it is posted. In a sense, it's saving you the JavaScript/JQuery because it "auto-wires" it up similar-ish to a Panel. In this way you could potentially look at progressively rendering your complex forms from the server as each section is edited, etc.
See MSDN: http://msdn.microsoft.com/en-us/library/system.web.mvc.ajax.ajaxoptions.updatetargetid.aspx
The relevant code example to give you an idea (unfortunately, it's not in the more readable Razor syntax):
The relevant line is the Ajax.BeginForm where the form tag is rendered. Once the form is posted, the MS AJAX library will auto update the element specified in "UpdateTargetId" specified in the form's AjaxOptions. In this case, the response will be placed into the SPAN element "textEntered" upon reply from the server. Here, you could progressively render more content to the user to fill out, perhaps another form, etc.
<h2><%= Html.Encode(ViewData["Message"]) %></h2>
<p>
Page Rendered: <%= DateTime.Now.ToLongTimeString() %>
</p>
<span id="status">No Status</span>
<br />
<%= Ajax.ActionLink("Update Status", "GetStatus", new AjaxOptions{UpdateTargetId="status" }) %>
<br /><br />
<% using(Ajax.BeginForm("UpdateForm", new AjaxOptions{UpdateTargetId="textEntered"})) { %>
<%= Html.TextBox("textBox1","Enter text")%>
<input type="submit" value="Submit"/><br />
<span id="textEntered">Nothing Entered</span>
<% } %>
Before starting, I do have a very particular question and if you want to answer it go straight to the end. But I do welcome comments and advices hence the lengthy post.
OK, we deal with a lot of forms and some of these forms are quite lengthy and have many fields. We also have a requirement - in addition to top level fields - to be able to have variable number of repating rows - as we call them. For example, let's think of a customer which has name, surname and age while it can have zero or many addresses (say 0 to 10) so the user must be able to add or remove contacts from the form while filling it in. So typically user gets and "Add" button to add more addresses and next to each address, a delete button. Potentially there could be more than one repeating section in the same form but I am not going there. The point is, because of legal and historical reasons, all the forms must be saved at once so while the forms can be edited, we cannot accept a half-filled form and have another page for users to add and remove addresses, e.g.
I am using ASP NET MVC 2 (strongly typed views with a single generic controller) with client side validation and heavy jquery scripting for flashy features. We are probably going to migrate to ASP NET MVC 3 very soon and I am already playing with 3 for finding a good solution. These addresses are defined on the Model as List<Address>, e.g.
I currently have a working solution for this issue but I am not satisfied with it: I have an HTML Helper that names the add or delete buttons and a bit of JavaScript to disable validation and allow the form to be posted back (even invalid) and since I can find out the name of the button that was clicked, I have all the necessary logic to handle add or delete and works really well.
But I am posting back and the form is reloaded and I am looking for an aletrnative solution. Here are what I can do:
Do everything in the client side. "Add" button will clone one of such addresses and "Delete" button will remove() the element. I only have to rename the indexes which I have done. We were using jquery calendar and it was breaking on the new elements which I have also fixed. But the validation is not working which can probably work with ASP NET MVC but this solution looks like a very brittle one - a house of card which looks great before you add another card.
Post the whole page usin Ajax and then load it back again: This is probably better than my current solution but only slightly.
Use ajax to post the form and get back JSON and use the data to build the elements or remove them: Again a house of card because of extensive client side scripting
Serialize the form and post using Ajax to a particular action and get back only the repating section (as a partial view). The action on the controller can be reused and called from the view itself to return the partial view
OK last one is the one I am working on but there is an issue. ASP NET MVC 3 with unobtrusive validation works only if the form is engulfed in a BeginForm() while my top level view has a BeginForm() but not my partial view. It works well when I call it from the view but not on the ajax call to get just the repeating section.
(Question)
So is there a way to tell ASP NET MVC 3 to spit out validation data atttributes regardless being in a BeginForm() block?? To be honest if this is not a bug, this is definitely an important feature request. I have in fact used reflector to disassemble the code and the condition seems to be there.
Short Answer:
Add this to the partial view:
if (ViewContext.FormContext == null)
{
ViewContext.FormContext = new FormContext();
}
I don't think it is possible using the default unobtrusive libraries supplied. If you look at jquery.validate.js and jquery.validate.unobtrusive.js it looks like it only validates what is inside the form.
There's a few posts about it if Googled and a few work arounds.
I had a similar issue (although much simpler) where I had a validation summary at the top of the page and multiple forms but the unobtrusive javascript would only populate the view summary if its inside the form (jquery.validate.unobtrusive.js line 39 if interested...).
I'm not sure if the validation library is extendible but most things in jquery are so that might be an option if you want to go down that road.
As far a possible solution to your problem I'll put in my 2 cents for whats its worth.
You could have two actions that are posted to. The first action is you post your model with no js validation and all validation is handled in the code - this will catch all user with javascript turned off.
Your second action is you serialized the model. In mvc 3 using the Ajax.BeginForm has an AjaxOption for Url where you can specify an action for the jquery to call (where it serializes the form form you and you can decorate your action with your strongly typed model). Here you can check the model and return a json result and handle this in the javascript.
I'm working with ASP.NET MVC 2 and building a simple business app. Here are some of the details:
The app deals with work orders and
has a work order index view. The
view has a table listing the work
orders, and several controls (text
boxes, check boxes, and drop down
lists) to select the criteria for
which work orders to display.
I'm using viewmodels. The work order
index view has a viewmodel with
properties for each and every
control.
I've implemented paging similar to
what is being done in the answer to
this question:
How do I do pagination in ASP.NET MVC?
I'm using LINQ's Skip() and Take() as
demonstrated, and ActionLinks for the
navigation.
If I load the page and don't
manipulate any of the controls, I can
click on the page number ActionLinks
and move around just fine between
pages of work orders. However, if I
change something, my changes are lost
when I navigate to another page.
For example, if I'm on page 1 and
click an unchecked check box, and
then click on the link for page 2,
the second page of results will load
but the check box will revert to its
previous state.
I understand why this happens, but I'm wondering what is the best thing to do from a design standpoint.
Potential solutions I can think of:
Set all the control values as route
values in the ActionLinks. This
seems really nasty, and could result
in very long URLs or query strings. Actually, now that I think of it this wouldn't work without a way to capture the control values.
Since ActionLinks don't post
anything, replace them with buttons.
Again, this seems like a bad idea.
Change the ActionLinks to links that
fire off a jQuery script that does a
POST. I think this is the most
promising option so far. Do many
developers do it this way?
This seems like a common enough problem, but none of these options feel quite right. I wonder if I'm missing something.
Can't you just save the changes back to the database when the user toggles the checkboxes (using jQuery):
$("input[type=checkbox]").click(function() {
$.ajax({
type: "POST",
url: "/ControllerName/SaveInfo?id=" + {id},
success: function(){
alert("Data Saved: " + msg);
}
});
});
In the end, I wound up getting rid of the ActionLinks for the paging, and replaced them with regular anchor tags. The current page index is now stored in a hidden form value:
<input id="page" name="page" type="hidden" value="" />
<p>
<% for (var i = 1; i <= (int)Math.Ceiling(Model.RowsMatchingCriteria / (double)Model.PageSize); i++) { %>
<%--
If the page number link being rendered is the current page, don't add the href attribute.
That makes the link non-clickable.
--%>
<a class="pageLink" <%= i != Model.Page ? #"href=""javascript:void(0);""" : string.Empty %>><%: i %></a>
<% } %>
</p>
Then I added the following jQuery script, which sets the hidden page value and submits the form when a link is clicked:
$(document).ready(function () {
$('.pageLink:[href]').click(function () {
$('#page').val($(this).text()); // Set hidden field value to the text of the page link, which is the page number.
$('form:first').submit();
});
});
Problem solved.
Best bet is to effectively simulate viewstate by "logging" the changes to a hidden field when a user paginates. To do so:
1) Figure out what data you need to capture and a data format to do so in {ie -- an array of json objects}
2) Setup the link that handles the prev/next to fire off a method to collect the "changed" things and stuff them into objects and into a hidden field.
3) When posting the form, parse the hidden field, extract data and profit.