MVC3 Drop Down or ListBox with dynamic check boxes - asp.net-mvc-3

I have an MVC3 C#.Net web app. I have a requirement to display a list of check boxes (either in a drop down or a List Box) dynamically based on a table in our db. The table can contain 1:500 entries. I then need to pass the selected check boxes to the Controller in order to perform an action on each selection. Any ideas on an implementation?

There are many ways to go about this but here is a general demo.
You can pass a list of the checkbox values and descriptions either on the Model (as this example does), ViewData[""] dictionary or ViewBag (MVC3+).
Then in your view loop through them and add them to your form using the name="chxBxGroupName" to group them.
Now create a controller action to post to that takes a List of the value type (in this example int) with the parameter naming matching the name="chxBxGroupName".
It will post a list of checked values.
The post page will just print out:
123
456
// This is your landing page. It gathers the data to display to the user as checkboxes.
public ViewResult MyPageWithTheCheckboxes()
{
// For example: Assume a Dictionary with the checkbox value and description
// Replace with DB call, etc.
return View(new Dictionary<int, string> { { 123, "Foo" }, { 456, "Bar" } });
}
<%# Page Title="" Language="C#" Inherits="System.Web.Mvc.ViewPage<Dictionary<int,string>>" %>
<!-- Rest of HTML page... -->
<form id="frm1" action="<%=Url.Action("MyPost")%>" method="post">
<% foreach (var item in Model) { %>
<input type="checkbox" id="chxBx<%=item.Key%>" name="chxBxGroupName" value="<%=item.Key%>"/>
<label for="chxBx<%=item.Key%>"><%=item.Value%></label>
<br/><br/>
<% } %>
<input type="submit" value="Go!"/>
</form>
<!-- Rest of HTML page... -->
public ContentResult MyPost(List<int> chxBxGroupName)
{
return Content(string.Join(Environment.NewLine, chxBxGroupName ?? new List<int>()), "text/plain");
}

the answer provided by Jay accomplishes exactly what you need. If you want to put the items in a list you can do it by surrounding the markup with a div control lie below
<div style="height:40px;overflow:auto;">
<% foreach (var item in Model) { %>
<input type="checkbox" id="chxBx<%=item.Key%>" name="chxBxGroupName" value="<%=item.Key% >"/>
<label for="chxBx<%=item.Key%>"><%=item.Value%></label>
<br/><br/>
<% } %>
</div>
unfortunately you cant have checkboxes in a <select />, but if you really wanted it to look like a select list you could add some JQuery that processes onclick of a textbox and shows the div. This obviously would require some jQuery and might not be worth it

Related

MVC3: Button action on the same view

i wish to change the inner html of a view on button click but maintain the view. I know how to change the html content of a div in javascript, but how can I have the action of the button not return a different view?
My buton looks like
<input type="submit" value="submit" onchange="myfunc()"/>
where myfunc() is the function in Javascript changing the div content.
Assuming you want a link to render content using ajax (and hopefully using razor) you can do something like the following:
First, setup the action to render the content partially. this can be done a few ways, but I'll keep with the logic in the action (and make it callable directly or by ajax):
[HttpPost]
public ActionResult Save(SomeModel model)
{
/* build view */
return Request.IsAjaxRequest() ? PartialView(model) : Wiew(model);
}
Next, setup a container in your page where the content will be populated along with the form you're looking to submit. If you want the form to disappear on a save, wrap it in the container. Otherwise, keep the container separated. In the below example, the from will submit and on success it'll come back, otherwise the new content will appear in its place:
<div id="ajaxContentPlaceholder">
#using (Ajax.BeginForm("Save", new AjaxOptions { UpdateTargetId = "ajaxContentPlaceholder" })) {
<!-- form elements -->
<input type="submit" value="save" />
}
</div>

Custom display template behavior on page refresh

I am having an issue with my custom template when page is refreshed. My scenario is that I have multiple address records to be displayed, in which I opted to use custom templates so I won't have to use foreach() to display each record. Here's my custom template code:
#model Address
<div>
#Html.LabelFor(model => model.AddressLine)
#Html.DisplayFor(model => model.AddressLine)
<br />
</div>
Let's say I have 2 address records for display. What's happening is that upon initial page load, it will display 2 records correctly but when page is refreshed, it will display the 2 records again in which now I end up with 4 records on screen. Subsequent page refreshes will display even more duplicates on the screen. My question is, do I need to handle that page refresh event? Or am I just doing something very obviously wrong here?
UPDATE
As requested here is my code for the View and the Action,
View:
#model Patient
<div id="editDetails">
#using(Html.BeginForm("Edit", "Patient"))
{
#Html.DisplayFor(m => m.Addresses)
<input type="submit" value="Submit" />
}
</div>
Action:
public ActionResult Details(string id)
{
Patient patient = patientRepository.GetPatientData(id);
if (patient != null)
{
patientData.GetOtherDetails(patient);
return View(patient);
}
else
return View();
}

Add and remove textbox at runtime in mvc3

In my page there is one textbox by default and one add button beside it. I need to add the another textbox when user click Add button. And there should be two buttons Add and Remove beside newly added text box. And same process goes on i.e., user can add Textbox using Add button and remove it using remove button.
I am new to mvc 3 so i am confused how to proceed. Is there any way like placeholder in asp.net so that we can add control at runtime.
Any suggestion and idea will be helpful to me
MVC is a very "hands-off" framework compared to Web Forms, so you're free to add the new textboxes how you like. Note that "controls" don't exist in MVC.
Here's how I'd do it:
Model:
class MyModel {
public Boolean AddNewTextBox { get; set; }
public List<String> MultipleTextBoxes { get; set; } // this stores the values of the textboxes.
}
View (I prefer the Web Forms view engine, I'm not a fan of Razor):
<% for(int i=0;i<Model.MultipleTextBoxes.Count;i++) { %>
<%= Html.TextBoxFor( m => m.MultipleTextBoxes[i] ) /* this might look like magic to you... */ %>
<% } %>
<button type="submit" name="AddNewTextbox" value="true">Add New Textbox</button>
<button type="submit">Submit form</button>
Controller:
[HttpPost]
public ActionResult MyAction(MyModel model) {
if( model.AddNewTextBox ) model.MultipleTextBoxes.Add("Yet another");
else if( ModelState.IsValid ) {
// your regular processing
}
}
You can also add more textboxes with Javascript and it work perfectly fine. All that matters is the HTML input elements. There's no cryptic viewstate. MVC is stateless.
Note that because I used <button type="submit"> my example will not work reliably in Internet Explorer 6-8 (sucks, I know), but you can replace them with <input type="submit"> with no ill-effects.
This requires some Javascript/JQuery... The following is a sketch only, but will hopefully be useful as a general approach.
The remove button
You want to render a button that can target its own container for removal. To do that, use some markup like this:
<div class="item-container">
<input type="button" onclick="removeItem(this)" />
</div>
And the Javascript for removeItem:
<script>
function removeItem(element) {
// get the parent element with class "item-container" and remove it from the DOM
$(element).find(".item-container").remove();
}
</script>
The add button
You could either use a partial view with Ajax, or use straight Javascript; which one is best likely depends on whether you need a round-trip to the server to create a new item. Let's say you need to go the the server to generate a new ID or something.
First, create a partial view and corresponding controller action; this should contain the remove button as above, as well as the text box and add button.
Now, create an Ajax form on your main page that gets invoked when you click Add:
<script src="#Url.Content("~/Scripts/jquery.unobtrusive-ajax.min.js")" type="text/javascript"></script>
#using (Ajax.BeginForm("New", new AjaxOptions() { UpdateTargetId="ajaxTarget", HttpMethod = "GET" })) {
<input type='submit' value='Add New' />
}
<div id="ajaxTarget"></div>
This code fetches your partial view (from the action New in the current controller) and adds the result to the ajaxTarget element.
Note The Ajax form requires Unobtrusive Ajax, which you can install via Nuget: Install-Package JQuery.Ajax.Unobtrusive.

passing data from view to controller on asp.net mvc 3

i have problem to pass data from view to controller , i have view that is strongly typed with my viewmodel "TimeLineModel", in the first i passed to this view my viewmodel from action on my controller
public ActionResult confirmation(long socialbuzzCompaignId)
{
return View(new TimeLineModel() { socialBuzzCompaignId = socialbuzzCompaignId, BuzzMessages = model });
}
with this i can get info from my action and display it on view , but i have other action POST which i won't get my view model to do some traitement
[HttpPost]
public ActionResult confirmation(TimeLineModel model)
{
}
i can get some propretie of the model but in others no , for example i can get the properti "socialBuzzCompaignId" of model , but other propertie like "IEnumerable BuzzMessages" i can't get it , i dont now why !!
this is the content of my view
#model Maya.Web.Models.TimeLineModel
#{
ViewBag.Title = "confirmation";
}
#using (Html.BeginForm())
{
<h2>confirmation</h2>
<fieldset>
#foreach (var msg in Model.BuzzMessages)
{
<div class="editor-label">
#msg.LongMessage
</div>
<br />
}
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
You need to include BuzzMessages properties within a form element. Since it's not editable, you'd probably want to use hiddens. There are two ways to do this. Easiest is instead of doing a foreach loop, do a for loop and insert them by index.
#for (int i =0; i<Model.BuzzMessages.Count(); i++v)
{
<div class="editor-label">
#Model.BuzzMessages[i].LongMessage
#Html.HiddenFor(m => m.BuzzMessages[i].LongMessage);
</div>
<br />
}
but to do this you'd need to use an IList instead of an IEnumerable in your view model to access by index.
Alternatively, you could create an Editor Template named after your BuzzMessages class (whatever its name is).
#model BuzzMessagesClass
#Html.HiddenFor(m => m.LongMessages)
<!-- Include other properties here if any -->
and then in your main page
#Html.EditorFor(m => m.BuzzMessages)
Check out http://coding-in.net/asp-net-mvc-3-how-to-use-editortemplates/ or search stack overflow if the details of editor templates confuse you.
Just like any HTML POST method, you have to get the data back to the Controller somehow. Just simply "showing" the data on the page doesn't rebind it.
You have to put the data in an input (or a control that will post back) to the appropriate model property name.
So, if you have a model property with name FirstName and you want this data to be rebound to the model on POST, you have to supply it back to the model by placing an "input hidden" (or similar control that postbacks) with the ID of FirstName will rebind that property to the model on POST.
Hope that explains it.
#foreach (var msg in Model.BuzzMessages)
{
<div class="editor-label">
#msg.LongMessage
<input type="hidden" name="BuzzMessages.LongMessage" value="#msg.LongMessage" />
</div>
}
It will post array of LongMessages. Get values like this:
[HttpPost]
public ActionResult confirmation(TimeLineModel model, FormCollection collection)
{
var longMessages = collection["BuzzMessages.LongMessage"];
}

Partial View - >> How to REFRESH the HTML content without having to redirect to the view

My site has a concept like Skype that allow users to go "Online" and "Offline". I created a partial view that allows the user to switch mode:
#if (Convert.ToBoolean(ViewData["IsLogged"].ToString()))
{
<div id="onlineStatus">
You are currently <strong>ONLINE</strong> >>
#Html.ActionLink("Go OFFLINE", "GoOffline", "Account")
</div>
}
else
{
<div id="offlineStatus">
Ready for business >>
#Html.ActionLink("Go ONLINE", "GoOnline", "Account")
</div>
}
This is how we load the Partial View:
public ActionResult OnlineStatusCtrl()
{
if (SiteUser.IsAuthenticated)
ViewData["IsLogged"] = SiteUser.IsOnline.ToString();
return PartialView("OnlineStatusCtrl");
}
When a user clicks on the link "Go ONLINE" or "Go OFFLINE", the Controller respond as:
public ActionResult GoOnline()
{
if (SiteUser.IsAuthenticated)
SiteUser.GoOnline();
ViewData["IsLogged"] = "True";
return RedirectToAction("Index", "Home");
//return PartialView("OnlineStatusCtrl");
//return EmptyResult();
}
public ActionResult GoOffline()
{
if (SiteUser.IsAuthenticated)
SiteUser.GoOffline(true);
ViewData["IsLogged"] = "False";
return RedirectToAction("Index", "Home");
}
This works well ...but the ONLY problem is that if I am on View XXXX, and I click on "Go Online", the controller redirects me to the Index View.
I tried "return EmptyResult()" or "return PartialView("OnlineStatusCtrl") but it does just not work.
From the code, you can see that the only thing the PartialView cares about is the "ViewData['IsLogged'] value"
QUESTION:
What is the way to REFRESH a partial view without having to refresh the entire page or redirect to the main page?
Is it maybe a matter of putting an Html.Beginform() ?
Is it maybe a matter of the Controller returning something that just refresh the content of the PartialView independently from what view is holding the PV itself?
Aiaiaiaia
I still can't figure out how MVC works with PartialViews/
UPDATE
I have updated the code as x suggested and the HTML output is as follow:
<div id="divStatus">
<form action="/" data-ajax="true" data-ajax-mode="replace" data-ajax-update="#divStatus" id="form0" method="post">
<div id="offlineStatus">
Ready for business >>
Go Online
</div>
</form>
</div>
When I click on the LINK, the Controller return PartialView("_OnlineStatusCtrl"); which is hte name of the calling PV ...and the ENTIRE PAGE gets replaced.
You're going to have to use an ajax call of some sort (Microsoft ajax helpers built into MVC, or jquery/javascript ajax call.
To use Microsoft's Ajax, you can use Ajax.BeginForm or Ajax.ActionLink. Both take an AjaxOptions parameter that will allow you to set javascript functions for OnSuccess, and an UpdateTargetId to display the returned data (usually a partial view). Using this will call your action which should return a partial view. Your partial view then replaces the html element (usually a div) identified by the UpdateTargetId parameter. If you decide to go this route, make sure you reference all the proper Microsoft ajax/mvc scripts. You'll pretty much need each script with any combinations of Microsoft, Ajax, Mvc, and even unobtrusive in the name.
Here's an example of one of my ajax forms (modified slightly for simplicity)
<% using(Ajax.BeginForm("addAttribute", new { id = Model.PersonId, attributeId = item.AttributeId }, new AjaxOptions { UpdateTargetId = "myTargetId", OnSuccess = "initForm" })) { %>
<input type="submit" value="Ok" class="editMode okButton" disabled="disabled" />
<input type="button" class="editMode cancelButton" value="Cancel" />
<br />
<input type="button" value="Add" class="addButton" />
<% } %>
I have a div with an id of "myTargetId" (for this example) that will be updated with the returned partial view.

Resources