It's difficult for me for developping an functionality without JavaScript..
I have a ViewModel :
public class AccountRegisterViewModel
{
#region Properties
public User User { get; set; }
public ExternalAccounts ExtAccounts { get; set; }
public LocalPassword Password { get; set; }
public Company CompanyARegister { get; set; }
public Company CompanyBRegister { get; set; }
public bool SameCompanies { get; set; }
public int NbCompanies { get; set; }
...
}
In view, i have a link with checkbox for copying the first company with the second
But I don't know how pass this viewModel (View to Controller) for keeping my data and return the same View with the copie of company..
i try this, in view :
#Html.ActionLink("Click", "CopyCompanies","Account", new { model = Model })
#Html.CheckBoxFor(model => model.SameCompanies)
In Controller :
[AllowAnonymous]
public ActionResult CopyCompanies(AccountRegisterViewModel model)
{
...
if (model.SameCompanies)
{
// copie
}else //clear
...
return View("Step2Register", model);
}
Any idea ?? Thank you for your help
If the CopyCompanies action method requires the AccountRegisterViewModel object, then you will need to provide it. Unfortunately, you will not be able to provide the value using the approach you are following when creating the link.
Your two options would be to have a hidden field for each property in AccountRegisterViewModel and then let the model binding create the object, but even this would not be ideal, since the viewModel is composed of complex objects, so you would have way too many hidden fields.
Your second option, which I think is a better approach, would be to pass in some kind of Id that corresponds to the AccountRegisterViewModel that CopyCompany can use to look up the values it would need.
Related
I'm trying to add an object using a PartialView inside a popup. It's a simple Rental application for which the data model was generated Model First through Entity Framework. The Controllers and Views have mostly been Scaffolded by EF. The relationship between RentalApplication and RentalObject is 1 to many, meaning a RentalObject always has to have 1 RentalApplication.
My controller looks like this:
// GET: /Calendar/Add/1
// Create a PartialView using a RentalObject as the model.
// Use the provided ID to lock in the RentalApplication.
[HttpGet]
public PartialViewResult Add(int id)
{
return PartialView(
new RentalObject(db.RentalApplicationSet.FirstOrDefault(x => x.Id == id)));
}
// POST: /Calendar/Add
// Save the submitted RentalObject to the db
[HttpPost]
public ActionResult Add(RentalObject rentalobject)
{
if (ModelState.IsValid)
{
try
{
db.RentalObjectSet.Add(rentalobject);
db.SaveChanges();
return RedirectToAction("Index");
}
catch
{
return View();
}
}
return View();
}
My object looks like this:
public partial class RentalObject
{
public RentalObject()
{
this.Lease = new HashSet<Lease>();
}
public RentalObject(RentalApplication rentapp)
{
this.Lease = new HashSet<Lease>();
RentalApplication = rentapp;
PricePerHour = RentalApplication.DefaultPricePerHour;
Currency = RentalApplication.DefaultCurrency;
}
public int Id { get; set; }
public string Name { get; set; }
public bool IsAvailable { get; set; }
public string Illustration { get; set; }
public string Description { get; set; }
public decimal PricePerHour { get; set; }
public string Currency { get; set; }
public virtual ICollection<Lease> Lease { get; set; }
public virtual RentalApplication RentalApplication { get; set; }
}
So when I'm opening the popup (using #Ajax.ActionLink to GET the first controller Add action) I'm creating a RentalObject WITH a RentalApplication (2nd constructor) to use as the model. This works so far, the popup dialog shows the values PricePerHour and Currency from the RentalApplication.
However, when I submit the form in my PartialView popup everything gets copied over BUT the RentalApplication object. It somehow ends up creating a new RentalObject object using the PricePerHour and Currency from the original RentalApplication, but doesn't include the object itself under the RentalApplication property. My debugger even goes to the first constructor for RentalObject.
So I guess it's having trouble keeping a complex object inside another object when submitted from controller to view (GET) and back to controller (POST). Is this just poor practice on my part? Should I be using a ViewModel?
In the past I've had to use #Html.HiddenFor(m=>m.yourObjectHere) on objects that were not changed in the form to keep them from getting new-ed up again. I did this for every object I didn't use in the form (about 2 or 3).
Hope this helps.
I would like to fill 2 divs in View with data from 2 ViewModels, but I have a problem.
My 2 viewModels:
public class ChatLogsNameTimeViewModel
{
public UserProfile UserProfile { get; set; }
public string Message { get; set; }
public DateTime Time { get; set; }
}
public class UserProfile
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
public string UserName { get; set; }
public string Email { get; set; }
public bool IsOnline { get; set; }
public virtual ICollection<ChatLogs> ChatLogs { get; set; }
}
Which means I want to show data from ChatLogsNameTimeViewModel in one div in View and data from UserProfile in other div in View.
This is my ViewModel that uses both viewModels above:
public class ChatLogsUsersViewModel
{
public IEnumerable<ChatLogsNameTimeViewModel> ChatLogs { get; set; }
public IEnumerable<UserProfile> Users { get; set; }
}
And this is my Index() action in controller:
var chatLogs = db.getChatLog().ToList();
var users = dba.getOnlineUsers().ToList();
var view = new ChatLogsUsersViewModel(chatLogs, users);
return View(view);
My problem is that I can not access to ViewModel attributes at all.
When I create foreach loop in view all I can access is this:
Which means I cannot access attributes at all to print them in foreach.
I have this in View:
#model IEnumerable<Chat.Models.ChatLogsUsersViewModel>
I assume that I am not doing something right in my controller. I have methods getChatLog() and getOnlineUsers() implemented in Model, they work alone no problem. I just don't know how to make them work together in one view.
You need to update the type of you view.
You are not passing the view a list of Chat.Models.ChatLogsUsersViewModel, you only have one and this model has two lists.
So update it to:
#model Chat.Models.ChatLogsUsersViewModel
Your model is strongly typed towards the wrong model. As Queti put it, your model should be typed #model Chat.Models.ChatLogsUsersViewModel.
As is, your model is attempting to access a collection of these models. You should find that if you do:
#for each (var x in Model) {
x.
}
x is then a single ChatLogsUsersViewModel and should display its properties in your dev environment. But again, this is not how you want to strongly type your model here.
If I'm not mistaken, this is what you are trying to do, and you can still access your data using a for each loop:
#model Chat.Models.ChatLogsUsersViewModel
for each (var log in Model._chatLogs) {
#<div>#log.Message</div>
}
...
for each (var user in Model._users) {
#<div>#user.UserName</div>
}
I have an ASP.NET MVC4 application in which at a certain point there is a page (Index) where a user can select an item from a DropDownList. After submitting this, the controller will return a different PartialView-name to another View (Create), based on the selected item from the list. Each partial has its own ViewModel and when the PartialView is sent from the Controller to Create-View it is rendered correctly. To achieve this I made a general ViewModel and several other viewmodels which derive from this general ViewModel. The Create-view has the general ViewModel as Model and the Partials, which will be rendered in the Create-view, have the matching derived types as Model.
But here's the problem, when I submit the form on the PartialView I have to retrieve the right ViewModel back in the Controller. Accepting the general ViewModel as a parameter won't work as I won't be able to down-cast it to the right ViewModel then. Here's some example code that I have:
ViewModels:
public class PropertyViewModel
{
public string ViewName { get; set; }
public String Name { get; set; }
public String Description { get; set; }
}
public class IntegerViewModel : PropertyViewModel
{
public int MinValue { get; set; }
public int MaxValue { get; set; }
}
public class TextViewModel : PropertyViewModel
{
public int MaxLength { get; set; }
}
Controller:
public ActionResult Create(String partialName)
{
var model = GetViewModelFromName(partialName);
return View(model);
}
[HttpPost]
public ActionResult Create(???)
{
//What to do here and what kind of parameter should I expect?
}
Is there a 'clean' way to do this? And does anyone know how to achieve this?
Update:
I have a solution that seems to work. In the PartialView I set the actionName and the controllerName of the form, like this:
#using (Html.BeginForm("CreateIntegerProperty", "Property")) {
//Formstuff...
}
#using (Html.BeginForm("CreateTextProperty", "Property")) {
//Formstuff...
}
And in my Controller I have all the different Actions (one for each of the PartialViews). This seems to work. Now is this a clean way to do this? If anyone comes up with a better idea, please do let me know!
If your solution works then go with it. It seems fine to me. The only issue would arise if you were bothered about having the same URL for each action.
You could enhance it a tiny bit by adding the Action and Controller names to the base ViewModel if you wanted to, like this:
public class PropertyViewModel
{
public string ViewName { get; set; }
public String Name { get; set; }
public String Description { get; set; }
public String Controller { get; set; }
public String Action { get; set; }
}
And then doing this:
#using (Html.BeginForm(Model.Action, Model.Controller)) {
//Formstuff...
}
This would be worth doing if it meant you could now use the same View (or partial view, or whatever) for the form.
If you DO want the same URL for each action, then one way is to override OnModelBinding, but I probably wouldn't bother personally.
I have a class that requires another class to be specified, but I don't want the MVC ModelState validator to check whether the secondary model is valid. Is this possible?
Here's a brief overview:
My entities look something like this:
public class WidgetType
{
public long Id { get; private set; }
[Required]
public string Name { get; set; }
...
}
public class Widget
{
public long Id { get; private set; }
[Required]
public string Name { get; set; }
[Required]
public WidgetType WidgetType { get; set; }
...
}
I have them encapsulated in a WidgetViewModel class that I'm passing to/from the View like this:
public class WidgetViewModel
{
public Widget Widget { get; set; }
public ICollection<WidgetType> WidgetTypes
{
get
{
return _repository.GetWidgets();
}
}
...
}
My view looks something like this:
...
#Html.DropDownListFor( m => m.Widget.WidgetType.Id, new SelectList( new EquipmentViewModel().EquipmentTypes, "Id", "Name" ) )
...
All of this works except for validation. ModelState.IsValid is always false because "Widget.WidgetType.Name" is required. I need the user to select a WidgetType, but I don't want ModelState to be validated deeper than "Widget.WidgetType.Id" (which should be all that Widget needs for its foreign key?).
Is there a better way to do this? I feel like there should be some way to validate without recursively inspecting deeper into the properties, but I can't find it. What am I missing...?
public class WidgetViewModel
{
[Required]
public string Name { get; set; }
[Required]
public WidgetType WidgetTypeId { get; set; }
public SelectList WidgetTypes
{
get
{
//This should be popuplated in your controller or factory not in the view model
retun new SelectList{ _repository.GetWidgets(),"Id","Name");
}
}
}
In your view
#Html.DropDownListFor( m => m.WidgetTypeId, Model.WidgetTypes)
And in your controller
public ActionResult Create(WidgetViewModel model)
{
Widget widget = new Widget{
Name = model.Name,
WidgetType = yourManager.GetWidgetTypeByID(model.WigetTypeId);
};
yourManager.Create(widget);
//...
}
If all you need in your view is the WidgetID then you don't need to include the entire Widget in the WidgetViewModel. Just have property called WidgetID. View model classes should have only the data the is necessary for the view.
In the controller action method that is called when you submit the form, you can use the WidgetID to fetch the Widget object from the database if it is needed.
http://blog.stevensanderson.com/2010/02/19/partial-validation-in-aspnet-mvc-2/ gives an example of partial validation
I am coverting my app from webforms to mvc, at the moment i am at a design issue (well i just dont know how to do it in mvc).
Basically my model would be something like this:
public class DamagedItem
{
public Int32 LoanId {get;set;}
public String IdentityCode {get;set;}
public virtual ICollection<DamagedItems> DamagedItems {get;set;}
}
In my controller i would like to do:
public ActionResult Add(DamagedItem damagedItem)
{
//Do update logic here
}
Then in my view i can add to the ICollection as needed.
But, i can't do this because if i try and access the ICollection from my controller it is null.
Here is an image of when i want to do:
I just dont know how to lay it out in my view, how to i add such items to my ICollection, update the view then when i need to save i have access to what i have added from my controller?
Thanks,
Nick
Edit:
I was thinking of using a partial in the view and doing all the logic for the bottom half using ajax and storing it in a session variable, but i would prefer NOT to make it reliant on ajax.
It is better to separate: you shoud have 2 actions, which produce 2 view.
You should have LoadInformationModel classe:
public class LoadInformationModel
{
public string StudentCode { get; set; }
public string FirstName { get; set; }
// etc..
public ICollection<Damage> Type { get; set; }
}
corresponding action
[HttpGet]
public ActionResult LoanInformation(int id)
{
var loanInfo = // get data by given id..
var model = new LoadInformationModel {
StudentCode = loanInfo.StudentCode,
// etc
Type = new List<Damage> { new Damage { Value = "Damaged"}, new Damage { Value = "Damaged Again" }
}
return View(model);
}
As well as RepairDataModel class
public class RepairDataModel
{
public bool CoveredByWarranty { get; set; }
public ICollection Status { get; set; }
}
And corresponding action
[HttpGet]
public ActionResult Repair(int id)
{
// logic
return View(model);
}
Your task is to create Post handler, that would save data to DB then form submitted
[HttpPost]
public ActionResult(RepairDataModel model)
{
// save to db
return View();
}
The view returned by Index() method, could be created like
#Html.RenderAction("LoanInformation")
#Html.RenderAction("Repair")
The rest depends on your desing and imagination. I hope that would give you direction.
What I can see is only the DamagedItem lacks a contructor with values for Collection;
public class DamagedItem
{
public DamagedItem()
{
DamagedItems = new List<DamagedItems>();
DamagedItems.Add(new DamagedItem { Description = "Damaged" } );
}
public Int32 LoanId {get;set;}
public String IdentityCode {get;set;}
public virtual ICollection<DamagedItems> DamagedItems {get;set;}
}