I have something like this
[HttpPost]
public ActionResult CreatePost(Post post)
{
var categoryList = Request["CategoryList"].Split(',');
//I want to set my Category Name in here
foreach (var category in categoryList)
{
post.Categories.Add(new Category { Name = category });
}
post.CreatedDate = DateTime.Now;
post.CreatedBy = _userService.GetCurrentUser().Id;
_postService.CreatePost(post);
return View();
}
I want to set public virtual ICollection<Category> Categories { get; set; }this is in my Post Model. It has two properties Id and Name. I want to set my property in my CreatePost method like above. How should I do that?
Here it is how i solved my problem without create a instance in my ActionResult method
I just created instance in Model constructor.
public Post()
{
this.Categories = new HashSet<Category>();
}
And this is the right solution for do that.
Related
I am fairly new to MVC, and I've been reading a bit about ViewModels, but how do I go about sending two models to my View, where the queries are like so
public ActionResult Index(int Id)
{
var People = from a in db.Person
select a;
var Data = from a in db.Member
where a.Person.PersonId.Equals(Id)
select new
{
a.Project.ProjectId,
a.Project.Name,
a.Project.Customer,
a.Project.TechProfile.Select(x => new
{
x.TechId,
x.Name,
x.Elements
}),
a.MemberId,
a.Role,
a.Start,
a.End
};
return View(People);
}
I was using #model IQueryable<GeoCV.Models.Person> before so I could use a #foreach in my View but I don't know how to get my other query to the View so I can get data from it too.
Update
And I'm making a custom class for my Data query, but I don't know how to set the property of TechProfile
Right now I have
public IEnumerable<TechProfile> ProjectTechProfile { get; set; }
In my custom class, but it doesn't work, so I guess I have to specify TechId, Name and Elements?
But how?
A ViewModel wraps around the 2 models you are getting with your 2 queries, so you can return it as a single object to your view. In your case we need to adress another issue first. You are returning an anonymous object in your data query.
This means, your data query needs to return a strongly typed object instead of an anonymous object.
Create a class for your data query:
public class MyCustomDataObject
{
public int ProjectId { get; set; }
//... map all properties as needed
}
then edit your data query to return this object:
var Data = from a in db.Member
where a.Person.PersonId.Equals(Id)
select new MyCustomDataObject
{
ProjectId = a.Project.ProjectId,
//assign all properties
};
Now you need to create the actual ViewModel class:
public class MyViewModel
{
public IEnumerable<Person> Persons { get; set; }
public IEnumerable<MyCustomDataObject> Data { get; set; }
}
And after this you just need to assign the values to it in your Actionmethod:
public ActionResult Index(int Id)
{
var People = from a in db.Person
select a;
var Data = from a in db.Member
where a.Person.PersonId.Equals(Id)
select new MyCustomDataObject
{
ProjectId = a.Project.ProjectId,
//...
};
//store data of both queries in your ViewModel class here:
var vm = new MyCustomDataObject();
vm.Persons = People;
vm.Data = Data
//return ViewModel to View.
return View(vm);
}
And then declare it in your view: #model Namespace.Subfolder.MyCustomDataObject
You can use #Html.Action("actionName","controllerName") method in view. You can divide your original view into multiple partial view and then you can render that partial view with dynamic model binding using #Html.Action("actionName","controllerName") method.
For more details with sample code http://devproconnections.com/development/how-use-aspnet-mvc-render-action-helpers
You can have methods like below to get multiple model in single view
private IList<People> GetPeople()
{
return from a in db.Person
select a;
}
private IList<Data> GetData()
{
return from a in db.Member
where a.Person.PersonId.Equals(Id)
select new
{
a.Project.ProjectId,
a.Project.Name,
a.Project.Customer,
a.Project.TechProfile.Select(x => new
{
x.TechId,
x.Name,
x.Elements
}),
a.MemberId,
a.Role,
a.Start,
a.End
};
}
public ActionResult Index(int Id)
{
var MultipleModel = new Tuple<IList<People>,IList<Data>>(GetPeople(),GetData()) { };
return View(MultipleModel);
}
Here's a codeproject tutorial on the subject.
I am new in mvc 4 but getting progress. I'm getting crazy with something which how i can select an item in select list in view model.
here is my controller code;
ViewBag.DepartmanListesi = new SelectList(VeriTabani.UnvanDepartmanlaris, "UDepId", "Departman");
and in my view model I am listing a diffirent database but in this list one field includes an id of the UnvanDepartmanlaris.instead of showing the id, I want to show name of the id. but what I have tried is not worked. can you please help me.
I searched many things but most of them was about how to set dropdownlist. I couldnt find any answer of my question.
Thank you in advance. I will be waiting for any response
Try this,
Controller
public List<CustomerModel> GetCustomerName()
{
// Customer DropDown
using (dataDataContext _context = new dataDataContext())
{
return (from c in _context.Customers
select new CustomerModel
{
CustomerId = c.CID,
customerName = c.CustomerName
}).ToList<CustomerModel>();
}
}
[HttpGet]
public ActionResult CustomerInfo()
{
var List = GetCustomerName();
ViewBag.CustomerNameID = new SelectList(List, "CustomerId", "customerName");
return View();
}
View
#Html.DropDownList("CustomerId", (SelectList)ViewBag.CustomerNameID, "--Select--")
Model
public class CustomerModel
{
public int CustomerId { get; set; }
public string customerName { get; set; }
public List<SelectListItem> customerNameList { get; set; }
}
I'm using following approach. Hope it helps:
Create helper class (I'm having here all my selectlists)
Public static class Helper
{
public static List<SelectListItem> GetList()
{
var result = new List<SelectListItem>();
var ctx = new YourContext();
var items = from n in ctx.Clients
select new SelectListItem
{
Text = n.Client.Name,
Value = n.ClientID.ToString()
};
foreach (var item in items)
result.Add(item);
return result;
}
}
Than in your View:
#Html.DropDownList("GetClients", Helper.GetList())
Works for me.
I can't seem to get the edit function of my view to work..i have a page that lists, a page that shows specific detail and on that page, i should be able to edit the information of the form..PROBLEM: when i run the application it says:No parameterless constructor defined for this object. What am i doing wrong...?
In the Home Controller i have:
Edit Functions:
[HttpGet]
public ViewResult EditSchoolDetails(int id)
{
var institution = _educationRepository.GetInstititionById(id);
var model = (Mapper.Map<Institution, InstitutionModel>(institution));
return View(model);
}
post
[HttpPost]
public ActionResult EditSchoolDetails( InstitutionModel institutionModel, int id)
{
if (ModelState.IsValid) {
//_get from repository and add to instituion
var institution = _educationRepository.GetInstititionById(institutionModel.Id);
// Map from the view model back to the domain model
var model = Mapper.Map<Institution, InstitutionModel>(institution);
//UpdateModel(model);
SaveChanges();
return RedirectToAction("ViewSchoolDetails", new {institutionModel = institutionModel, id = id});
}
return View(institutionModel);
}
InstitutionModel
public class InstitutionModel {
public InstitutionModel() {
NAABAccreditations = new List<AccreditationModel>();
}
public int Id { get; set; }
public string Name { get; set; }
public bool IsNAAB { get { return NAABAccreditations.Any(); } }
public string Website { get; set; }
public AddressModel Address { get; set; }
public IEnumerable<AccreditationModel> NAABAccreditations { get; set; }
}
Does the Institution class have a parameterless constructor? If not, that will be the problem. You are passing an InstitutionModel to the the edit view, so the post action should probably take an InstitutionModel too, then you can map back to the original Institution model:
public ActionResult EditSchoolDetails(int id, InstitutionModel institutionModel)
{
if (ModelState.IsValid)
{
//add to database and save changes
Institution institutionEntity = _educationRepository.GetInstititionById(institution.Id);
// Map from the view model back to the domain model
Mapper.Map<InstitutionModel, Institution>(institutionModel, institutionEntity);
SaveChanges();
return RedirectToAction("ViewSchoolDetails",);
}
return View(institutionModel);
}
Notice also how it returns the view model back to the view if the model state isn't valid, otherwise you will lose all your form values!
Here's a similar question too which might help: ASP.NET MVC: No parameterless constructor defined for this object
Is it possible you need to pass a parameter to ViewSchoolDetails? I notice in the return statement you commented out that you were passing it an id, but in the return statement you're using, you're not passing in anything.
EDIT
This (from your comment below):
parameters dictionary contains a null entry for parameter 'id' of non-nullable type 'System.Int32' for method 'System.Web.Mvc.ActionResult ViewSchoolDetails(Int32)
...tells me you need to pass a parameter to ViewSchoolDetails
EDIT 2
I saw your edit, and would say this: if the method you are calling is
public ActionResult ViewSchoolDetails(InstitutionModel institutionModel, int id)
Then you MUST pass it an object of type InstitutionModel and an int as parameters or you will get an exception. Meaning, you need
RedirectToAction("ViewSchoolDetails", new {institutionModel = institutionModel, id = id});
Whenever i get this, i have forgotten to create a parameter-less constructor on my view-model. I always add one now just in case it's needed and i forget.
Does InstitutionModel have one?
I've read many articles which they state that querying should not be placed in the Controller, but I can't seem to see where else I would place it.
My Current Code:
public class AddUserViewModel
{
public UserRoleType UserRoleType { get; set; }
public IEnumerable<SelectListItem> UserRoleTypes { get; set; }
}
public ActionResult AddUser()
{
AddUserViewModel model = new AddUserViewModel()
{
UserRoleTypes = db.UserRoleTypes.Select(userRoleType => new SelectListItem
{
Value = SqlFunctions.StringConvert((double)userRoleType.UserRoleTypeID).Trim(),
Text = userRoleType.UserRoleTypeName
})
};
return View(model);
}
The View:
<li>#Html.Label("User Role")#Html.DropDownListFor(x => Model.UserRoleType.UserRoleTypeID, Model.UserRoleTypes)</li>
How do I retain the View Model and Query and exclude the User Type that should not show up?
I think that you are doing it just fine.
Any way... all you can do to remove the querying logic from controller is having a ServiceLayer where you do the query and return the result.
The MVC pattern here is used correctly... what your are lacking is the other 2 layers (BusinessLayer and DataAccessLayer)... since ASP.NET MVC is the UI Layer.
UPDATE, due to comment:
Using var userroletypes = db.UserRoleTypes.Where(u=> u.UserRoleType != 1);
is OK, it will return a list of UserRoleType that satisfy the query.
Then, just create a new SelectList object using the userroletypes collection... and asign it to the corresponding viewmodel property. Then pass that ViewModel to the View.
BTW, I never used the db.XXXX.Select() method before, not really sure what it does... I always use Where clause.
SECOND UPDATE:
A DropDownList is loaded from a SelectList that is a collection of SelectItems.
So you need to convert the collection resulting of your query to a SelectList object.
var userroletypes = new SelectList(db.UserRoleTypes.Where(u=> u.UserRoleType != 1), "idRoleType", "Name");
then you create your ViewModel
var addUserVM = new AddUserViewModel();
addUserVM.UserRoleTypes = userroletypes;
and pass addUserVM to your view:
return View(addUserVM );
Note: I'm assuming your ViewModel has a property of type SelectList... but yours is public IEnumerable<SelectListItem> UserRoleTypes { get; set; } so you could change it or adapt my answer.
I don't see anything wrong with your code other than this db instance that I suppose is some concrete EF context that you have hardcoded in the controller making it impossible to unit test in isolation. Your controller action does exactly what a common GET controller action does:
query the DAL to fetch a domain model
map the domain model to a view model
pass the view model to the view
A further improvement would be to get rid of the UserRoleType domain model type from your view model making it a real view model:
public class AddUserViewModel
{
[DisplayName("User Role")]
public string UserRoleTypeId { get; set; }
public IEnumerable<SelectListItem> UserRoleTypes { get; set; }
}
and then:
public ActionResult AddUser()
{
var model = new AddUserViewModel()
{
UserRoleTypes = db.UserRoleTypes.Select(userRoleType => new SelectListItem
{
Value = SqlFunctions.StringConvert((double)userRoleType.UserRoleTypeID).Trim(),
Text = userRoleType.UserRoleTypeName
})
};
return View(model);
}
and in the view:
#model AddUserViewModel
<li>
#Html.LabelFor(x => x.UserRoleTypeId)
#Html.DropDownListFor(x => x.UserRoleTypeId, Model.UserRoleTypes)
</li>
I using MVC-Viewmodel in my project, my problem is that even if i CTRL-click two values in my listbox It only grabs one value. I want users to be able to select two values but I dont know why it doesnt happen any tips is appreciated!
Here is my GET n POST action inside my controller:
public ActionResult Create()
{
CreateViewModel model = new CreateViewModel();
List<CoreValue> corevalues = Arep.getallC();
model.CoreValuess = new MultiSelectList(corevalues, "CID", "Cname");
return View(model);
}
[HttpPost]
public ActionResult Create(CreateViewModel model)
{
if (ModelState.IsValid)
{
Question q = new Question();
var CoreValueID = int.Parse(model.Cname);
var getallC = Arep.getbycid(CoreValueID);
q.CoreValue.Add(getallC);
q.QuestionText = model.QuestionText;
Arep.addquestion(q);
Arep.save();
return RedirectToAction("Index");
}
return View(model);
This is inside my CreateViewModel:
public MultiSelectList CoreValues { get; set; }
And this is inside my View:
#Html.ListBoxFor(model => model.Cname,Model.Corevaluess)
What seem to be the problem?
Thanks in Advance!
Best Regards
Spelling errors aside, I believe the following is why this is failing:
In your ListBoxFor method, you are using model.Cname. By this, I believe you mean "choose the cName of selected CoreValues". However (and I'm guessing because I can't see your model), the Cname property on the CreateViewModel is of type string. Because of this, you are only ever going to have one value at a time. You need a property that is of type IEnumerable in order to hold multiple selections.
Update your model to the following:
public class CreateViewModel
{
public IEnumerable<string> SelectedValues { get; set; }
public IEnumerable<CoreValue> CoreValues { get; set; }
}
SelectedValues will be used to contain the selected values on the post. We can also add items to it to signify what should be automatically selected when the view is created.
In your controller do the following:
public ActionResult Create()
{
CreateViewModel model = new CreateViewModel();
model.CoreValues = Arep.getallC();
return View(model);
}
Lastly, update the view:
#Html.ListBoxFor(m => m.SelectedValues, new MultiSelectList(Model.CoreValues, "CID", "Cname"))
Now, whenever you post, you should be able to see the values that a user selected.
EDIT: I'm not completely sure what some of your methods do so I'm taking a guess.
The POST method for Create:
[HttpPost]
public ActionResult Create(CreateViewModel model)
{
if (ModelState.IsValid)
{
foreach(var CoreValueID in model.SelectedValues)
{
Question q = new Question();
var getallC = Arep.getbycid(CoreValueID);
q.CoreValue.Add(getallC);
q.QuestionText = model.QuestionText;
Arep.addquestion(q);
}
Arep.save();
return RedirectToAction("Index");
}
return View(model);
}
you would need to pass selectedvalues as below
List<CoreValue> selectedvalues = Null;
model.CoreValuess = new MultiSelectList(corevalues, "CID", "Cname",selectedvalues);
return View(model);
Refer MSDN link and this helpful Article
As stated above, the ASP.Net Mvc wants to have a list of string, but the same thing can be achieved by using the classic ASP style
Request.Form["CoreValues"]
this will provide as comma separated values.