I've been playing around with different aspects of MVC for some time now, and I've reached a situation where I'm not sure what would be the best way to solve a problem. I'm hoping that the SO community will help me out here :P
I've seen a number of examples of Ajax.BeginForm on the internet, and it seems like a very nifty idea. E.g. you have a dropdown where you select a customer - and on selecting one it will load this client's details in some placeholder on the page. This works perfectly fine.
But what to do if you want to tie in some validation in the box?
Just hypothetically, imagine an article page, and user comments in the bottom. Below the comments area there's an ajax-y "Add comment" box. When a user adds a comment, it will appear in the comments area, below the last comment there.
If I set the Ajax.BeginForm to Append the result of the call to the Comments area, it will work fine. But what if the data posted is not valid? Instead of appending a "successful" comment to the comments area I have to show the user validation errors.
At this point I decided that the area INSIDE the Ajax.BeginForm will be inside a partial, and the form's submits will return this partial. Validation works fine. On each submit we reload the contents inside the form element. But how to add the successful comment to the top?
Other things to consider: The comment form also has a "Preview" button. When the user clicks on Preview, I should load the rendered comment into a preview box. This will probably be inside the form area as well.
I was thinking of using Json results instead. When the user submits the form, the server code will generate a Json object with a Success value, and html rendered partials as some properties. Something like
{ "success": true, "form": "<html form data>", "comment": "successful comment html to inject into the page" }
This would be a perfect solution, except there's no way in MVC to render a partial into a string, inside the controller (separation of context, remember?).
UPD: Seems like nobody knows an answer to this one.. Does it mean that there's no way to do this, or you just don't know, guys?
Here is an example how to post using jQuery and how to deal with error in the validation.
http://jvance.com/blog/2010/02/20/MakingAnAjaxFormWithJQueryInASPdotNETMVC.xhtml
After giving it more consideration + getting more experience with MVC, I decided to break down the problem, and came to the following conclusion. Not sure if anyone will find it useful
With an Ajax.BeginForm that requires field validation, the return from the submit should return the form's html. This way, if the validation failed- the response will contain the error messages, and the interface will look seamless.
The result will also most likely contain the whole form, including the declaration of it.
The preview in this case is a simple issue. When the user clicks on the preview button, the form can be posted, and the result will contain the populated form + the preview box. Alternatively, the Preview button can be an Ajax.LinkButton that will serialize the form, post the data to the server, that will render it into a comment. The js on the client side will then put this preview in the required container.
On successful submit, there are a couple options, depending on the requirements and the layout.
a) The result of the form submit can return the comment + the blank form (ready for a new comment)
e.g. when the comment form is below all the comments, this will look as if the comment has been added to the bottom of the form
b) The result can contain the blank form + a small js script that will update the comments area / load the latest comment to the page
c) It can also force a refresh of the parent page, to ensure the newly posted comment will be immediately visible to the user.
Basically, this choice depends on the requirements of the particular case.
Related
I am trying to show/hide Tabs depending on a user access level that I pass to my View that contains a Telerik tabStrip as shown below:
#{ Html.Telerik().TabStrip()
.Name("Main_Tabstrip")
.Items(tabstrip =>
{
tabstrip.Add()
.Visible((int)ViewData["UserLevel"] < 2)
.Text("Topic A")
.LoadContentFrom("_TopicATab", "TopicA");
tabstrip.Add()
.Visible((int)ViewData["UserLevel"] < 2)
.Text("Topic B")
.LoadContentFrom("_TopicBTab", "TopicB");
tabstrip.Add()
.Visible((int)ViewData["UserLevel"] < 2)
.Text("Topic C")
.LoadContentFrom("_TopicCTab", "TopicC");
})
However, when I call the Action that generates the View after a change in user status, although the View appears to update (I can step through it and see the UserLevel change) the Tab visibility remains as it was on the first rendering of the view.
If I subsequently refresh the Page either in the browser or via a JavaScript location.reload() call then the Tab Visibility works fine.
Additional information:
The Action referred to above calls View() to Render the full page that contains the above View.
Although I was able to work around the problem on this occasion by doing a page reload in JavaScript, I would really like to know why this was necessary and would appreciate any suggestions or solutions.
(I am posting this as an answer, since it is too long for a comment.)
Sorry, I should have been more specific. I meant from where in the page are you calling the action?
Your action returns some html (generated from the view) that is returned to the browser and one of two things happen depending on how the action was called:
(1) The whole page is replaced (and the browser might change the displayed address depending on the request verb)
(2) A part of the page, for example the content of a div, is replaced.
To accomplish (1) you will probably use a call to Html.ActionLink or an old fashioned anchor tag.
I would however advise you to use (2) instead, since it can give better UX, but it is harder to do. You would make an Ajax call, either via jQuery's ajax method, or an Ajax.ActionLink call.
So basically my counter-question was about which of these you are using. My suspicion is that you are requesting the action, but not writing the response anywhere. Can you perhaps show code for the action and the rest of the view, or reduce it to a minimal example to paste here?
More to the point of your question though, I have looked around a little and you are right that showing/hiding the tabs with javascript is not supported out-of-the-box. I did however find these two posts which might still help you
http://www.aspnetwiki.com/page:extending-the-telerik-mvc-client-api
http://www.aspnetwiki.com/telerik-mvc:dynamically-add-a-tab-to-the-tabstrip
I'm trying to describe it in as few steps as possible:
I have Page1.aspx with lot of controls, and Preview and Save button among those. I also have Page2.aspx that is the redirection target of a Preview Button click.
Since I need all the controls selections from Page1 to draw a preview on Page2 the redirection is done with setting Preview's PostBackUrl.
I also must have preview shown on a new tab or window so I used onClientClick="aspnetForm.target='_blank'" for Preview button definition.
Save button-click callback, after storing data to a database does redirection to some Page0.aspx (initial list of reports - the subject of the code)
Preview button works fine - a preview renders in a new tab, but when I go to the old tab and click on Save, I see from debugger, that firstly Page2.aspx(?) and secondly Page1.aspx are loaded. Then all the data is stored in the db, but though Page0 redirection is executed Page1.aspx stays loaded in the browser.
I have no idea what processes are behind this. Could one who knows give me an insight? Or if you consider my approach impossible to implement give some idea how to do the same?
If it's of importance, everything on the Page1 is located in an update panel.
Thank you very much for replying
In ASP.NET there are basically zero (0) circumstances in which you will ever send form data from one page to another. Although what exactly you are trying to accomplish is vague, you can consider some of the following:
Isolate unique operations/systems to a single page. If you have something like a User Profile, don't have three different aspx pages; just use a single page for the user or admin to manage that data / functions. Postback events are your friend.
Understand the difference between ViewState and traditional form data. I'm guessing that if you're trying to post form data from one page to another, you probably don't understand the point of ViewState. Using a single page to maintain temporary data that the user is currently working with is a great use for ViewState. If you want the data to appear on another page then you need to consider the data from the previous page as final and thus should be saved to a database or some other medium.
These are just some general guidelines because there is no exact answer to your problem without saying something generic like "You're doing it wrong." I would recommend starting by never again trying to post form data from one aspx page to another.
I have this flow but don't know how to deal with it. I think "Forward" button should use GET because it is safe and idempotent but the textarea contains a large amount of text so I think can't put in in URI. I changed to POST.
The OK button on confirmCreateAlbum surely POST.
The flow says When click "Cancel" on confirmCreateAlbum, it returns to nameAlbum with the fields were filled for editing. I put OK button in a form with action="confirmCreateAlbum". The problem is how to back to nameAlbum?
Note: nameAlbum will show errors if the required fields are not provided.
Although there is no specific length limitation for GET requests in the RFC, browsers impose limits on URI lengths. There are also considerations with some server implementations.
You said the textarea "contains a large amount of text" so it is recommended to use POST in this situation because it won't be subjected to URI limitations.
On to your original question, "The problem is how to back to nameAlbum?"
In your confirmCreateAlbum form, you can actually use two separate forms. A form for the "OK" which the action calls your specified script for confirming, and a form for the "Cancel" which has an action calling your nameAlbum form.
Anther option is getting clever with hidden input fields and passing the data around but that can get messy.
Personally, if it were up to me, I'd be using jQuery/Javascript for confirming form submission. It's a simple client side solution that doesn't require you to leave your original form if "Cancel" is pressed. But that's just me...
I don't think post or get is the problem here.
You can create two form: one with the ok button, post/get to further step; one with the cancel button, post/get to nameAlbum.
Or you can create one form with two button with same name and two different value and post/get to some page. On that page you check the value and redirect to further step or to nameAlbum.
After posting to confirmCreateAlbum, where do you store the data from the textarea?
I assume you store it in the session so in nameAlbum you can fill the data (if there's any) to the field.
And if you can use javascript, you can just handler the next, cancel button with some javascript and avoid some round trip.
I have a form with a drop-down 'select' element that the user will sometimes need to add to. So, I added a link to open a Modal Frame form, created the Modal Frame form, and made its _submit() function add the new data to the table that holds options for the select element. Then it "returns" the new ID and name to the Javascript callback (the way Modal Frames do), and the JS callback adds the new element to the dropdown, and makes it the currently selected element in the browser, with JQuery. This all works great.
Finally, the user submits the original form, and gets the error "An illegal choice has been detected. Please contact the site administrator."
The form building function creates the option list from the database, which (I checked) DOES include the new option, so I'm guessing Drupal is using a cached version of the form rather than re-building it before it does the automatic validation. If you go back one page, then forward, the newly-added choice is there in the list.
I tried adding:
global $GLOBALS;
$GLOBALS['conf']['cache'] = FALSE;
to the function that builds the page with the problem, but it made no difference.
FYI: this is part of a multi-page form, if it matters.
I also thought about trying to add the option to the cached version of the "parent" form in the "child" form _submit() function, but don't know how to get the form_build_id of the "parent" form. Besides, that seems like way too much of a kludge (though I could be wrong about that).
Ideas?
You are submitting the form which is different then the time of form render so Drupal consider it as malicious input. If you want to skip that malicious check then add below line as property of your form in your_module_form() function.
'#DANGEROUS_SKIP_CHECK' => TRUE,
This will solve your problem but make sure that you are adding manual validation to protect from malicious inputs :). Hope this will help you.
I think you'd be better off using Drupal's AHAH functions to request an updated select element from a callback function. This way the cached form is rebuilt on the server side and you don't need to add the dreaded DANGEROUS_SKIP_CHECK. Here's a tutorial for Drupal 6:
http://randyfay.com/ahah
An outside vendor did some html work for us, and I'm filling in the actual functionality. I have an issue that I need help with.
He created a simple html page that is opened as a modal pop-up. It contains a form with a few input fields and a submit button. On submitting, an email should be sent using info from the input fields.
I turned his simple html page into a simple aspx page, added runat=server to the form, and added the c# code inside script tags to create and send the email.
It technically works but has a big issue. After the information is submitted and the email is sent, the page (which is supposed to just be a modal pop-up type thing) gets reloaded, but it is now no longer a pop-up. It's reloaded as a standalone page.
So I'm trying to find out if there is a way to get the form to just execute those few lines of c# code on submission without reloading the form. I'm somewhat aware of cgi scripts, but from what I've read, that can be buggy with IIS and all. Plus I'd like to think I could get these few lines of code to run without creating a separate executable.
Any help is greatly appreciated.
If you don't want the page to reload after submission, you will need to use AJAX. that is alot more complicated. you would still need the submit.aspx, you cannot send email with javascript.
Code a redirect after the form submission, so instead of getting the same form back in the main document/page, you could get something like a blank page saying "Thanks for your submission!" or something of that nature.
Might be more simple to redirect the user to a result page using Respone.Redirect that displays some sort of "Your email has been sent" message, or even just redirect back to the base page.