I want to do the following:
1: Add two dropdown list in the register.aspx [Say ddlRole,ddlGender]
2: Fill the dropdown list [ ddlRole should be filled from the database, and ddlRole should have two static field]
3: On submit I want to get the selected value of the two dropdown list.
Please help.
Thanks in advance.
Well, your question is kind of "Can you tell me how to build a shuttle?". But i will try to show you the small example that will help you (I really hope)
First of all,if you want to get dropdowns on the page, you need to create it.
In terms of MVC you need to create a View.
That View is MVC styled aspx page
below is an example:
<%# Page Title="" Language="C#" Inherits="System.Web.Mvc.ViewPage" %>
<h2>Register</h2>
This is a plain empty page.
Let's fill it up with dropdowns.
<h2>Register</h2>
<%= Html.DropDownList("ddlRole") %>
<%= Html.DropDownList("ddlGender") %>
Okay. Now, time to make the system to show our View.
To do that we need a motor. In terms of MVC it calling a Controller.
Create a class with the method:
public class SetupController : Controller
{
public ActionResult Register( )
{
return View();
}
}
If you now will try to launch the page you should see your two dropdowns.
Unfortunately they will be empty.
Obviously they are empty because you did not tell how to fill them.
The main purpose of controllers is to connect model that contains all the data that should be processed and shown with the view side. In other words, the controller takes the data from the model (M), prepares it and sends to the View (V).
So, first of all we need to adjust our controller, so it will tell the view an information about the content for dropdowns.
The easiest way is to use ViewData collection:
public ActionResult Register( )
{
ViewData["ddlRole"] = new[] {
new SelectListItem() {Text = "Customer", Value = "Customer"},
new SelectListItem() {Text = "Supervisor", Value = "Supervisor"},
new SelectListItem() {Text = "Admin", Value = "Admin"},
};
ViewData["ddlGender"] = new[]{
new SelectListItem() {Text = "Male", Value = "Male"},
new SelectListItem() {Text = "Female", Value = "Female"}
};
return View();
}
As you can see from this example i created the content for the dropdowns dynamically.
In your case you can use your database to fill dropdowns as you want.
If you try to open your page now, you will see that your dropdowns are filled with the data now!
Great!
If you ask, how the view knows what content to use for the dropdown, i will answer that MVC is using a lot of conventions. One of that conventions is that when the View is generating its controls its looking for the content for that controls by the key that equals to the name of the control (i.e. "ddlRole", "ddlGender")
Since you put the values for that keys to the ViewData, its easy for MVC to fill your dropdowns with the text!
Cool!
Going forward.
Now, we need to gather the data from the page and send it back to the server.
What we need for that?
Of course, first of all we need a submit button:
<%# Page Title="" Language="C#" Inherits="System.Web.Mvc.ViewPage" %>
<h2>Register</h2>
<%= Html.DropDownList("ddlRole") %>
<%= Html.DropDownList("ddlGender") %>
<input type="submit" value="Register Me" />
Open the page in the broser again.
Cool! We have the button, but, if we try to click on it, nothing will happen.
If you are thinking in terms of classic ASP.NET, you will tell that we forgot to assign an event on the button submit, write codebehind code and bla...bla..bla...
In MVC its a bit different. We just need to send the content to the server.
To do that, normally you should have a "form" tag on your page :
<%# Page Title="" Language="C#" Inherits="System.Web.Mvc.ViewPage" %>
<% using (Html.BeginForm("DoRegister", null)) { %>
<h2>Register</h2>
<%= Html.DropDownList("ddlRole") %>
<%= Html.DropDownList("ddlGender") %>
<input type="submit" value="Register Me" />
<% } %>
This using code block will just wrap our tags with begin and end "form" tags.
This make the browser to gather an information from all inputs inside the form (in our case its our dropdows) and send them back from the point where they were opened.
Try to open it in the browser and click the button
Oops, we got an exception. The reason of it is that we forgot the rules.
What we intended to do ? We want to send the data to our business model.
Who should be responsible for that ? Of course it should be a controller (C), because its a main and only connector between Model (M) and View (V)
Let's add new action to the same controller :
public ActionResult DoRegister(string ddlRole, string ddlGender)
{
////store our ddlRole and ddlGender in the database
/// ......
/// .....
return RedirectToAction("Welcome");
}
In this example it redirecting to the "Welcome" action once registration has finished.
To finish an example and avoid errors, we need to implement Welcome action and view:
Add this to the controller:
public ActionResult Welcome( )
{
return View();
}
And create new View for the Welcome action (Right click on "Welcome" code and select "Add View..."):
<%# Page Title="" Language="C#" Inherits="System.Web.Mvc.ViewPage" %>
<h2>Welcome!</h2>
Now you will see that once you click the button it will show you the result of Welcome action execution - Welcome page.
Last trick - let's send selected dropdown values to the welcome page.
To do that, we firstly need to store that values somewhere at the moment when we got it from the server.
In your case you may use the Database, but to make it simpler, i will use special TempData collection:
public ActionResult DoRegister(string ddlRole, string ddlGender)
{
////store our ddlRole and ddlGender in the database
/// ......
/// .....
TempData["SelectedRole"] = ddlRole;
TempData["SelectedGender"] = ddlGender;
return RedirectToAction("Welcome");
}
Next, let make our welcome page to show the values from TempData collection:
<%# Page Title="" Language="C#" Inherits="System.Web.Mvc.ViewPage" %>
<h2>Welcome you, the <%= TempData["SelectedRole"]%> of <%= TempData["SelectedGender"] %>!</h2>
Run it!
Do you see the values ?
Yeah, You made it!
Simple and easy.
I hope this article will help you to start realize how great ASP.NET MVC is.
But the code above is just a top of the iceberg.
Actually the MVC is MUCH MUCH MUCH more fun then this.
If you are interesting in getting more knowledge about it, I would really recommend you to read APress "ASP.NET MVC Framework" by Steven Sanderson.
Really great book that contain everything to start writing your own MVC applications on MVC.
Have a good luck!
Related
I am building an mvc app for reporting. I have a page that has a form on it which contains multiple dropdownlist to choose some criteria for a report. I then have an input button to create the report. This button call a new view from the same controller. The new view gets the values from the page where the criteria is chosen from parameters and uses that to populate it's own view model. This is all working fine.
I would like to open the reports in a new window. When I look at the controller, all of the parameters that are supposed to be coming from the selection page are null. I assume I will have to pass these in via the querystring to be picked up by the controller. Is there a way that I can get the values of the dropdownlists from within my viewpage to construct the querystring?
Is this a good way to accomplish what I am trying to do? Would I be better of using an ActionLink instead of an input button? does it make any difference?
I hope this all makes sense. Thanks for any thoughts.
Just set a target attribute on your form to _blank and it should open the request in a new page/tab depending on the browser being used.
<% using (Html.BeginForm(myAction, myController, FormMethod.Post, new { target = "_blank" })
{ %>
<%-- ... --%>
<% } %>
As NickLarsen says...
You could use the target="_blank" attribute of the form element to display the results in a new window.
<form action="/controller/action" method="post" target="_blank">
Or
<% Html.BeginForm("action", "controller", FormMethod.Post, new { target="_blank" }); %>
//...
<% Html.EndForm(); %>
I have an ascx control for fruits that contains following code:
<div id = "fruits">
....
Ajax stuff1 UpdateTargetId = "fruits"
Ajax stuff2 UpdateTargetId = "fruits"
<%Html.RenderPartial("PagerAjax", (Pager)ViewData["pager"]); %>
</div>
now this fruit control can appear on a number of webpages and the pager would need to know what page the user is on so that it can pull next set of fruits accordingly. For example, if I am on red-fruit page, then PagerAjax should know I am only pulling out red fruits. So, basically I would need to know ControllerName (assume it's home) and actionName (assume it's redFruits()). (Example may seem inefficient but it makes sense for the real purpose.) Now, I could do something like this:
<%Html.RenderAction("PagerAjax", (Pager)ViewData["pager"], ViewContext.RouteData.Values["action"], controllerFilter = ViewContext.RouteData.Values["controller"] }); %>
However, as you noticed, the above RenderAction is inside the div that is being updated by Ajax callback, which means it will contain action and controller of the Ajax stuff rather than the original URL's.
What should be an efficient workaround?
You could pass the original ViewContext.RouteData.Values["action"] as parameter when calling your AJAX action. This way the action knows what was the original action and store it in the model (or ViewData as in your case I see that your views are not strongly typed). Now your markup could become:
<% Html.RenderPartial(
"PagerAjax",
(Pager)ViewData["pager"],
new ViewDataDictionary() { { "originalAction", ViewData["originalAction"] } }
); %>
Ok, i can use jeditable to edit-in-place some content on a page and the content will be saved to a database. But whats the best way to re get that text-content from db to show into a place holder?
p id="paraNo34" class="editable"
-->What i will write here so that it will get content from a
db's table: [Content], where id=="paraNo34".
/p
The problem is if i will use some hard coded text like
p id="paraNo34" class="editable"
-->Some text here
/p
I will able to edit-in-place using jeditable but when i will refresh page it will show the same "Some text here" as its not getting data from db.
Your pseudocode implies that you want the view to be responsible for fetching the required data, which is an anti-pattern in MVC. You need to retrieve the text in your controllers action and pass it to the view, either using ViewData or a custom view model, e.g.:
public ActionResult Index(string id)
{
// call some method to fetch data from db
ViewData["ID"] = id;
ViewData["Content"] = content;
return View();
}
And the view looks something like:
<p id='<%= ViewData["ID"] %>' class="editable">
<%= Html.Encode(ViewData["Content"]) %>
</p>
A better approach would be to create a strong-typed view model (Stephen Walther has a blog post about view models here), but the above example should illustrate how data can be passed from the controller to the view.
I am wondering if it is possible to wrap up an ascx file so that it can be used in different views, without having to type it to a specific Model.
This would mean you could use one ascx file for many pages, as long as the relevant model data was passed in.
Currently I'm duplicating my ascx files for different parts of the site, but this feels very un DRY.
ps this is th kind of model I'm passing in.
public class DinnerPage {
public Dinner dinner {get; set;} //main page data
public List<Dinner> Random6Dinners {get; set;} // ascx content
}
The problem is if I want to use the ascx file that renders the 6 random dinners, but for a different main page, then I have to type it differently.
Basically, can you have an untyped ascx page (or a view)
Thanks all.
I believe what you are asking is if you could re-use many views like a control on a single view? If so, you can indeed. Use the Html.RenderPartial action in your view. This will render an existing "aspx" page on your current view:
Example:
Assuming Model.Dinners is a List/Enumrable of some sort.
Dinners.aspx
<!--html-->
<%foreach(var dinner in Model.Dinners){%>
<% Html.RenderPartial("~/DinnersFolder/Dinner.ascx", new { Dinner = dinner}); %>
<%}%>
<!--html-->
Dinner.aspx
<%
var dinner = ViewData.Eval("Dinner");
%>
<!--html-->
Something like this would work for an individual dinner:
<% Html.RenderPartial("Dinner", Model.Dinner); %> //Dinner being Dinner.ascx
This way your ("MyPartialView" / MyPartialView.aspx), will take in a type of Dinner. You can then pull out that Dinner via ViewData.Eval, and display your "Dinner" accordingly.
In your main page you can: then do something like foreach Dinner in my Dinners, render a PartialControl.
A detailed example of this:
http://highoncoding.com/Articles/638_Understanding_Partial_Views_in_ASP_NET_MVC_Application.aspx
You could aslo use RenderAction, this has the same exact idea. However, it will post to your Controllers action, which in turn returns a view:
<% Html.RenderAction(...); %>
This is a great article about the difference between each, and which you should use:
http://blogs.intesoft.net/post/2009/02/renderaction-versus-renderpartial-aspnet-mvc.aspx
Have you tried having a base Dinner model in which the 6 random dinner classes derive from and then just use the user control as such:
<%= Html.RenderPartial("DinnerControl",
Model.RandomDinnerThatDerivesFromBaseDinner); %>
And then the first line of your control should be something like:
<%# Control Language="C#"
Inherits="System.Web.Mvc.ViewUserControl<BaseDinner>" %>
I'm new to MVC, so please bear with me. :-)
I've got a strongly typed "Story" View. This View (story) can have Comments.
I've created two Views (not partials) for my Comments controller "ListStoryComments" and "CreateStoryComment", which do what their names imply. These Views are included in the Story View using RenderAction, e.g.:
<!-- List comments -->
<h2>All Comments</h2>
<% Html.RenderAction("ListStoryComments", "Comments", new { id = Model.Story.Id }); %>
<!-- Create new comment -->
<% Html.RenderAction("CreateStoryComment", "Comments", new { id = Model.Story.Id }); %>
(I pass in the Story id in order to list related comments).
All works as I hoped, except, when I post a new comment using the form, it returns the current (parent) View, but the Comments form field is still showing the last content I typed in and the ListStoryComments View isn’t updated to show the new story.
Basically, the page is being loaded from cache, as if I had pressed the browser’s back button. If I press f5 it will try to repost the form. If I reload the page manually (reenter the URL in the browser's address bar), and then press f5, I will see my new content and the empty form field, which is my desired result.
For completeness, my CreateStoryComment action looks like this:
[HttpPost]
public ActionResult CreateStoryComment([Bind(Exclude = "Id, Timestamp, ByUserId, ForUserId")]Comment commentToCreate)
{
try
{
commentToCreate.ByUserId = userGuid;
commentToCreate.ForUserId = userGuid;
commentToCreate.StoryId = 2; // hard-coded for testing
_repository.CreateComment(commentToCreate);
return View();
}
catch
{
return View();
}
}
The answer is to use return RedirectToAction(). Using this enforces the PRG pattern and achieves my goal.
My earlier comment to my original post did cause an error, that I guess I'm still confused about, but this works:
return RedirectToAction("Details", "Steps", new { id = "2" });
I, and this is a personal opinion, think you've tackled this the wrong way.
Personally I would;
Create a view called ListStories.
Create a partial view that lists the
stories.
Create a partial view to create a
story.
When you want to add a story, simply
show the add story html.
Then when the user presses a button
you do a jQuery postback, add the
new story and return a PartialView
of either the new story or all the
stories.
If you return a partial view of all
stories then replace the bounding
div that contains all the stories
with the new data.
If you return only a single story
then append it to the end of the div
containing the stories.
I know this means a lot of re-work and it sounds complex and like a lot of work but doing it like this means greater flexibility later on because you can re-use the partial views or you can make a change once and all views using that partial view are now updated.
also, using jQuery means that the adding of stories looks seemless w/out any obvious post back which is nice.
Since the problem seems to be caching, you can simply disable/limit caching.
Add the following attribute to your actions:
[OutputCache(Duration = 0, VaryByParam = "none")]
This will tell the browser to cache the page, but for 0 seconds. When the post reloads the page, you should see the desired results.
The answer is to make sure your form action is properly set. If you have used renderaction and not set the form controller and action manually then the action will be the current URL.
Try:
<% using (Html.BeginForm("ActionName", "ControllerName")) {%>
Instead of:
<% using (Html.BeginForm()) {%>