Submitting twitter bootstrapper tabs, with asp.net mvc 3 partial view - asp.net-mvc

I am having a twitter bootstraper tab, with 3 simples tabs (Caracteristiques, Certificat and Contrats)
the tabs are ajax load with asp.net mvc partialviews, they are tied with modelViews:
the partials views strongly tied to the type ViewModel:
// Load Certificat
public ActionResult Certificat()
{
var modelStaffs = _twitterTabsModel.GetStaffs();
return PartialView("_Certificat", modelStaffs);
}
// load Contrats
public ActionResult Contrats()
{
var modelJoueur = _twitterTabsModel.GetFirstJoueur();
return PartialView("_Contrats", modelJoueur );
}
the models:
public class TwitterTabModel
{
public ModelJoueur JoueurVM { get; set; }
public IEnumerable<ModelStaff> StaffVM { get; set; }
}
public class ModelStaff
{
public string NomStaff { get; set; }
public string FonctionStaff { get; set; }
}
public class ModelJoueur
{
public string NomJoueur { get; set; }
public string PrenomJoueur { get; set; }
}
the Caracteristiques Tab views:
#model Controls.Models.ViewModel.TwitterTabModel
<h2>Caracteristiques</h2>
#using (Html.BeginForm())
{
.... the tabs code ...
<p>
<input type="submit" value="Save" />
</p>
}
The tabs load fines, what I want to do is to include a submit button on the first razor view tab, it submit all the other models if loaded, however, when I get the post call, all the others models, JoueurVM and StaffVM are empty even though they are loaded. Why is it according to you ?
edit: This is the controller post code, nothing special, just trying to get the twitterTabModel:
[HttpPost]
public ActionResult Tabs(TwitterTabModel model)
{
return View();
}
Thanks

I figure a workaround, I pass the input values back as formcollection, instead of the overall model, well it it' s not clean, but well, it works as i can get all the values posted

Related

MVC sending a form to a page for testing

I am using MVC and have a view (test.cshtml) that contains a form. Is there a way to send it to another View page.cshtml for testing instead of same [http] controller ActionResult test()?
I am trying to validate that all the form field values are correct before updating db. Is there an easier way to do this?
In your view
#using (Html.BeginForm("Add", "Weight", FormMethod.Post))
//where "Add" is the Action name and Weight is the controller (WeightController) -> http://foo/Weight
{
......
}
With a model
public class WeightModel
{
[Required] public string Description { get; set; }
[Required] public int Weight { get; set; }
public string Notes { get; set; }
}
In your Controller
[HttpPost]
public ActionResult Add(WeightModel model)
{
if (!ModelState.IsValid) //framwork will validate based on attributes on model
{
return View("Index", model);
}
else
{
//save to db
return RedirectToAction("Added");
}
}

asp.net mvc rendering partial view on-demand

I'm a newbie to asp.net mvc and I'd like to know if what I do is correct.
I want to create a view for searching people. Here's what I have so far:
The business model class:
public class Person
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public Address Address { get; set; }
public DateTime DOB { get; set; }
public List<Telephone> Telephones { get; set; }
}
The ViewModel class:
public class SearchPersonViewModel
{
public int Id { get; set; }
public string FullName { get; set; }
public string LicencePlate { get; set; }
public string CarMake { get; set; }
public string CarModel { get; set; }
}
The partial view :
#model IEnumerable<MvcApplication2.Models.SearchPersonViewModel>
#foreach (var item in Model)
{
#Html.DisplayFor(m => item.Id)
#Html.DisplayFor(m => item.FullName)
}
The view from which the partial view is called:
#Html.Action("Search", "Person");
*The controller method in the PersonController:
[ChildActionOnly]
public ActionResult Search()
{
List<SearchPersonViewModel> model = new List<SearchPersonViewModel>();
model.Add(new SearchPersonViewModel() { FullName = "test", Id = 3 });
return PartialView("_SearchPerson", model);
}
Now the problem is that the Search method is called whenever the main View is loaded. What I want is to add a search textbox on the mainview for filtering the collection rendered in the partial view. How could I do that ?
This way your partial will render on click only
<script>
(function($){
$('#btn').click(function(){
$('#searchresult').load('#Url.Content("~/Person/Search")');
}
</script>
Make an ajax request to /search and append the data to your page.
<div id = 'searchresult'>
#Html.Action("Search", "Person");
</div>
whenever your want to filter call something like $('#searchresult').load('/search?q=xxx');
You could use 2 ways:
microsoft ajax helpers
jquery
For both of them you need to remove [ChildActionOnly] and #Html.Action("Search", "Person");
Look at this example: Using Ajax.BeginForm with ASP.NET MVC 3 Razor

bind attribute include and exclude property with complex type nested objects

Ok, this is weird. I cannot use BindAttribute's Include and Exclude properties with complex type nested objects on ASP.NET MVC.
Here is what I did:
Model:
public class FooViewModel {
public Enquiry Enquiry { get; set; }
}
public class Enquiry {
public int EnquiryId { get; set; }
public string Latitude { get; set; }
}
HTTP POST action:
[ActionName("Foo"), HttpPost]
public ActionResult Foo_post(
[Bind(Include = "Enquiry.EnquiryId")]
FooViewModel foo) {
return View(foo);
}
View:
#using (Html.BeginForm()) {
#Html.TextBoxFor(m => m.Enquiry.EnquiryId)
#Html.TextBoxFor(m => m.Enquiry.Latitude)
<input type="submit" value="push" />
}
Does not work at all. Can I only make this work if I define the BindAttribute for Enquiry class as it is stated here:
How do I use the [Bind(Include="")] attribute on complex nested objects?
Yes, you can make it work like that:
[Bind(Include = "EnquiryId")]
public class Enquiry
{
public int EnquiryId { get; set; }
public string Latitude { get; set; }
}
and your action:
[ActionName("Foo"), HttpPost]
public ActionResult Foo_post(FooViewModel foo)
{
return View(foo);
}
This will include only the EnquiryId in the binding and leave the Latitude null.
This being said, using the Bind attribute is not something that I would recommend you. My recommendation is to use view models. Inside those view models you include only the properties that make sense for this particular view.
So simply readapt your view models:
public class FooViewModel
{
public EnquiryViewModel Enquiry { get; set; }
}
public class EnquiryViewModel
{
public int EnquiryId { get; set; }
}
There you go. No longer need to worry about binding.
IMHO there is a better way to do this.
Essentially if you have multiple models in the view model the post controller's signature would contain the same models, as opposed to the view model.
I.E.
public class FooViewModel {
public Bar BarV { get; set; }
public Enquiry EnquiryV { get; set; }
public int ThisNumber { get; set; }
}
public class Bar {
public int BarId { get; set; }
}
public class Enquiry {
public int EnquiryId { get; set; }
public string Latitude { get; set; }
}
And the post action in the controller would look like this.
[ActionName("Foo"), HttpPost]
public ActionResult Foo_post(
[Bind(Include = "EnquiryId")]
Enquiry EnquiryV,
[Bind(Include = "BarId"])]
Bar BarV,
int ThisNumber
{
return View(new FooViewModel { Bar = BarV, Enquiry = EnquiryV, ThisNumber = ThisNumber });
}
All while the view still looks like this
#using (Html.BeginForm()) {
#Html.TextBoxFor(m => m.EnquiryV.EnquiryId)
#Html.TextBoxFor(m => m.EnquiryV.Latitude)
#Html.TextBoxFor(m => m.BarV.BarId)
#Html.TextBoxFor(m => m.ThisNumber)
<input type="submit" value="push" />
}
Keep in mind, this form will still post Latitude back (the way you had it set up), however since it is not included in the Bind Include string for Enquiry on the post action, the action will not accept the new value in the resultant Enquiry. I'd suggest making latitude either disabled or not a form element to prevent additional posting data.
In any other scenario you can use bind just fine, but for some reason it dislikes the dot notation for complex models.
As a side note, I wouldn't put the bind attribute on the class directly as it can cause other issues like code replication, and doesn't account for certain scenarios where you may want to have a different binding.
(I modified the variable names for some clarity. I am also aware your question is rather dated, however in searching for the answer myself this is the first SO I stumbled upon before trying my own solutions and coming to the one I posted. I hope it can help out other people seeking a solution to the same issue.)

MVC 3 Webapp - Model Binder

I am creating my first MVC app and one of the pages need to list a series of questions from a table in a database. I have set-up the Model:
public class Audit
{
public DateTime InspectionDate { get; set; }
public string Engineer { get; set; }
public List<AuditGroup> AuditGroups { get; set; }
}
public class AuditGroup
{
public string GroupName { get; set; }
public List<AuditQuestion> AuditQuestions { get; set; }
}
public class AuditQuestion
{
public string Group { get; set; }
public string Question { get; set; }
public string Answer { get; set; }
public string Comments { get; set; }
}
The models contains Lists, I created a page called Create and populated the model with the groups and questions in the groups and these displayed on the page fine. When I answer the questions (fill in a textbox) and press the submit button it calls the controller:
[HttpPost]
public ActionResult Create(Audit newAudit)
{
try
{
// TODO: Add insert logic here
return RedirectToAction("Index");
}
catch
{
return View();
}
}
The newAudit has data in the Engineer and Inspection Date but the binder is not picking up the Lists on the page. This is a cut down version I have trying to work it out:
#{
ViewBag.Title = "Audit";
Layout = "~/Views/Shared/_Layout.cshtml";
}
#model test.Models.Audit
<h2>
Audit</h2>
#using (Html.BeginForm())
{
<fieldset>
#foreach (var AuditGroups in Model.AuditGroups)
{
#Html.EditorFor(x=> AuditGroups.GroupName)
}
</fieldset>
<p>
<input type="submit" value="Create" />
</p>
}
So here I am going through the list and putting them on the page but on submit the list is null. Does anyone know where I am going wrong?
In summary what I am doing is sending a list of question to page, user to fill in and submit the answers but im not getting the answers for any of the Lists.
please have a look at my answer to this question. it contains some blog posts that addressed this issue. Furthermore, read Yarx's comment on the answer in which he provided the link to a post which helped him solve the problem.

How to send and retrieve in the controller

I have the folowing code in my view, however, I can see that I don`t have the values in the controller. What is wrong?
In the view I have,
<%
using (Html.BeginForm())
{%>
<%=Html.TextBox("Addresses[0].Line1") %>
<%=Html.TextBox("Addresses[0].Line2")%>
<%=Html.TextBox("Addresses[1].Line1")%>
<%=Html.TextBox("Addresses[1].Line2")%>
<input type="submit" name="submitForm" value="Save products" />
<%
}
%>
My classes are as follows:
public class Customer
{
public string FirstName { get; set; }
public string Lastname { get; set; }
public List<Address> Addresses { get; set; }
public Customer()
{
Addresses = new List<Address>();
}
}
public class Address
{
public int Line1 { get; set; }
public int Line2 { get; set; }
}
My controller as follows:
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult Index(Customer customer)
{
return View();
}
The parameter for your ActionResult is named customer, so the default model binder will be looking for that name in the form by default. I believe if you modify your code to the following it should pick it up:
<%=Html.TextBox("customer.Addresses[0].Line1") %>
<%=Html.TextBox("customer.Addresses[0].Line2")%>
<%=Html.TextBox("customer.Addresses[1].Line1")%>
<%=Html.TextBox("customer.Addresses[1].Line2")%>
Check to ensure your View is bound to the Customer model.
Also, when viewing the web page containing the form, view the source generated by the View to see if the fields are being properly named.
Finally, if none of the above helps, change the parameter in your Index action like so:
public ActionResult Index(FormCollection form)
then you can use the debugger to inspect the FormCollection object that is passed in to see exactly what the View is sending you.

Resources