I want to know how spring's multiple form:select works for following scenario:
I have a class UniSection has many students(Student class) and Students can selected zero or more selected course(SelectedCourse class) out of a list of courses(Course class)
public class UniSection{
private List<Student> students;
}
public class Student{
private List<SelectedCourse> selectedCourses;
}
public class SelectedCourses{
private String courseName;
}
In my jsp page, for a UniSection, then first select a student and then select some courses.
My command object is uniSection, how can I do a multiSelect for a selectedCourse?
I would like to do something like this
<form:select multiple="true" path="???">
<form:options items="courses" itemValue="???" itemLabel="???"/>
<form:select>
where courses is a list of all available courses. But what would come under path?
I dont think i can give path=students.selectedCourses as we need to assign course to particular student
I'm aware that i need a SelectedCoursePropertyEditor, but i don't know about the path expression.
In order to show a multiple-select with courses I think you need something like that:
<form:select multiple="true" path="students[i].selectedCourses">
<form:options items="${courses}" itemValue="courseName" itemLabel="courseName"/>
<form:select>
Where i, is a student from UniSection's list, and courses is a list containing all courses. When you submit this data, property Student.selectedCourses will be filled with selected rows.
Related
I have a drop down box in my jsp with a search button. On the click of search button on the same jsp below this drop down and search button i am displaying a data table which took the selected value from the drop down and displays all the results matching the key.
Jsp:
<form:form action="/search" modelAttribute="myModel" method="post">
<form:select path="categorySearched">
<form:option option="0" label="--Select--">
<form:options items="${myModel.categoryList}" itemLabel="name" itemValue="id"/>
</form:select>
<button type="submit">Search</button>
</form:form>
<form:form action="/edit" modelAttribute="myModel" method="post">
<c:forEach var=""... -------------------------->>>>> data table displayed properly
</form:form>
Controller:
#RequestMapping(value = "/showSearchPage", method = RequestMethod.GET)
public String showSearch(#ModelAttribute("myModel") MyModel myModel){
//call from db to get list of category type objects
myModel.setCategoryList(categories);
return "SearchPage";
}
#RequestMapping(value = "/search", method = RequestMethod.POST)
public String searchGoals(#ModelAttribute("myModel") MyModel myModel) throws Exception {
System.out.println(goalModel.getCategoryList());------------>> null; want this to have all objects in the list
..................
return "SearchPage";
}
MyModel:
private List<Category> categoryList;
private String categorySearched;
Catgory:
private String id;
private String name;
As you can see on search i am returning "SearchPage" and displaying same page.
i want to re-populate drop down on Search without calling the db again. It is because i can change the search criteria again from different selection in drop down.
Please help me bind the category objects from drop down to the model. Everything else is working as expected. only when i click on search button and page reloads the drop down is not getting populated.
When you are processing a /search request, the list of all categories is nowhere : you do not want to fetch it from the db and it did not come from the request parameters. Because when you write :
#RequestMapping(value = "/search", method = RequestMethod.POST)
public String searchGoals(#ModelAttribute("myModel") MyModel myModel)
Spring creates a new MyModel and populates it with request parameters.
If the request is simple enough, the more straightforward solution would be to cache the getCategories(xxx) method at service level. That way, you can call it as many times you want without reloading it from db. EhCache for example integrates nicely in Spring. Advantage : you just write in your code that you want the date and the framework deals with the caching
An alternative is to use a #SessionAttribute. If you add
#SessionAttributes("myModel")
above you controller class declaration, you ask Spring to store the model attribute myModel in session and take it from there instead of re-creating a new one on each request. It should meet your requirement but has drawbacks : there is no simple and reliable way to purge the attribute from the request when it is no longer needed. It is up to you to decide whether you can waste some session memory for that or not, depending on the number of expected simultaneous sessions, the server memory, ...
I'm still new to SpringMVC (and jstl for that matter). I'm trying to populate options in a select from a list of objects. I've found a way to do it using c:forEach, but I keep thinking there HAS to be a way to make the form:options method work.
I've browsed around, and about the closest thing I can find to official documentation on the items attribute is here >> http://static.springsource.org/spring/docs/2.0.x/reference/spring-form.tld.html#spring-form.tld.options
It says the items attribute is for
"The Collection, Map or array of objects used to generate the inner 'option' tags"
My confusion is what kind of Collection, Map, or array of objects it's looking for. What format do they need to be in? Is it looking for a Collection or array of type String specifically? Can I use
List<MyObject>
and if so, what would MyObject have to have in it in order for this to be valid (i.e. methods, variables)?
Currently, when I try to use MyObject, I get an exception that says -
ConverterNotFoundException: No converter found capable of converting from type com.example.MyObject to type java.lang.String
Do I need to make a converter? Where would that go? How would that work? I've googled that error message and haven't really turned up anything specific to what I'm trying to do... (Most are results about Roo)
the MyObject class looks like this:
public class MyObject{
private String company;
private Customer customer;
private Address customerAddress;
public String getCompany() {
return company;
}
public void setCompany(String company) {
this.company = company;
}
public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
public Address getCustomerAddress() {
return customerAddress;
}
public void setCustomerAddress(Address customerAddress) {
this.customerAddress = customerAddress;
}
}
and I'm trying to use it as such:
<form:select path="myObjectList">
<form:option value="0"/>
<form:options items="myObjectList" />
</form:select>
Does anyone know specifically what is incorrect about this method? Or, should I be using a
List<String>
to accomplish what I'm doing?
EDIT here's the stack trace >> http://pastebin.com/2c5XBCmG
The Spring Documentation says this about the items attribute of the form:options tag:
The items attribute is typically populated with a collection or array
of item objects. itemValue and itemLabel simply refer to bean
properties of those item objects, if specified; otherwise, the item
objects themselves will be stringified. Alternatively, you may specify
a Map of items, in which case the map keys are interpreted as option
values and the map values correspond to option labels. If itemValue
and/or itemLabel happen to be specified as well, the item value
property will apply to the map key and the item label property will
apply to the map value.
In a nutshell, if you need to use a List of your Custom Beans as the items attribute you need to use also the itemValue and itemLabel attributes. Personally, I'll prefer using Maps -LinkedHashMap instances speciffically- for populating my select tags, but that's a matter of taste.
Adapting an example from the Spring Documentation, your code should look like this:
<form:select path="commandAttribute">
<form:option value="-" label="--Please Select"/>
<form:options items="${countryList}" itemValue="company" itemLabel="company"/>
</form:select>
I'm using the company attribute as both itemValue and itemLabel, but you're free to choose the attributes that fit your requirements.
Usualy I am doing it with spring tag like this :
<springform:select path="myObjectList" id="selected_company">
<springform:option value="0" label="--- Select One ---"></springform:option>
<springform:options items="${myObjectList}" itemValue="company" itemLabel="company"></springform:options>
</springform:select>
don't forget including the namespace declaration :
xmlns:springform="http://www.springframework.org/tags/form"
I am new to ASP.NET MVC 3.0 and trying to build an application using the MVC ViewModel design..
I was wondering what the best practices are regrading controllers for ViewModels and have a few questions below.. This is my understanding so far (which might be wrong)..
We create Models.
Create ViewModels by making a new class and declairing attributes with the same name and type as the base model classes (including ID fields of the base models you want to update later.. and the classes are not linked in any way).
Create a Repository for each of the base models (to find and save data ect.).
Create a Controller action for each of the ViewModels (which access the repositories of the base classes to retrieve values and put these values into the ViewModel, then pass the ViewModel to the ViewModels View).
Create Views from the ViewModels (ViewModel Views)
In the ViewModel controller Update (POST) method recieve the updated ViewModel object and convert it into base model objects (Maybe use Automapper?) and next save the base model objects back using their repositories and apply binding like this? "TryUpdate<'IPerson>(person)", "TryUpdate<'IPlace>(place);" (this looks wrong, the aim is to put the values back into the base classes from the ViewModel, apply binding, save base models back using the repositories!.. This doesnt appear to use the repositories.. Instead of TryUpdate<'IPerson>(person); I would expect to see something like this: person.Save(IPerson).. where "person contains the values", ".Save is the repository", and "IPerson contains the binding attributes to use for binding"?.. Not sure if this is right..
So far I have created ViewModels by making a new class and adding attributes from different base models using the same names. At this point i have the following questions:
Q1: Does each ViewModel have its own controller and access each of the base models repository classes to get its values?
Q2: in the ViewModel should you include the ID field of all of the base models that you are using attributes from, considering that you might want to POST an Update back through the ViewModels Controller to the base Models repository (needing the ID values)?
Q3: How would you bind attributes using an interface for binding the model in the controller using the repository to save.
I have been unable to find a tutorial or resource that explains everything in a step by step example, A complete answer would be the following example:
2x simple models, 1x simple viewModel, 1x interface for binding, 1x simple controller using an interface class for binding on update, 1x repository.. i.e.
//Model1
public class Person
{
int PersonID {get;set;}
string FirstName {get;set;}
string LastName {get;set;}
DateTime DOB {get;set}
}
//Model2
public class Place
{
int PlaceID {get;set;}
string Description {get;set;}
string AreaType {get;set;}
string PostCode {get;set;}
}
//ViewModel (containing attributes from models)
publc class ViewModel
{
//Person attributes
int PersonID {get;set;}
string FirstName {get;set;}
string LastName {get;set;}
//Place attributes
int PlaceID {get;set;}
string Description {get;set;}
string AreaType {get;set;}
//other attributes
string someOtherAttributeForDisplay {get;set}
}
//Model1 interface (for binding on model)
public interface IPerson
{
string FirstName {get;set;}
}
//Model2 interface (for binding on model)
public interface IPlace
{
string Description {get;set;}
string AreaType {get;set}
}
//ViewModelController?
{
//What goes here?
}
//Repository?
{
//what goes here?
}
I think you may have overcomplicated a very simple concept.
First off some general rules:
Don't use TryUpdateModel. Just don't.
For the same reasons, don't use any "auto" mapping mappers to map from your view model to your entities. Auto mapping the other way round (from entity to view model) is fine.
Your use of interfaces is unnecessary.
View models are supposed to be very simple classes that contain just the information you need for your view. If your view POSTs different information from what it displays, then just create a different view model for POST.
We use a naming convention of {Controller}{Action}Model for our view models. So for an action named "List" on a "Post" controller we will have a model called "PostListModel".
Finally, check out my response here Real example of TryUpdateModel, ASP .NET MVC 3
It seems weird that I couldn't find an explanation of the difference between those two helpers, so I would assume that is something obvious but I missed.
Basically I am trying to decide which one I should use for my case, with the following simple Model:
public class Booking
{
public int ID { get; set; }
public Room Room { get; set; }
public DateTime StartTime { get; set; }
public DateTime EndTime { get; set; }
public ICollection<Equipment> Equipments { get; set; }
public string Who { get; set; }
}
and I want display a simple Room DropDownlist for Adding and Editing Booking record.
After doing a lots of Google around, it seems that I probably need a DropDopwListFor, but not sure why and how?
Take the following two examples:
#Html.DropDownListFor(
x => x.EquipmentId,
new SelectList(Model.Equipments, "Id", "Text")
)
and:
#Html.DropDownList(
"EquipmentId",
new SelectList(Model.Equipments, "Id", "Text")
)
It is obvious that with the second example the name of the property you are binding the dropdown to is hardcoded as a magic string. This means that if you decide to refactor your model and rename this property Tooling support that you might be using has no way of detecting this change and automatically modifying the magic string you hardcoded in potentially many views. So you will have to manually search & replace everywhere this weakly typed helper is used.
With the first example on the other hand we are using a strongly typed lambda expression tied to the given model property so tools are able to automatically rename it everywhere it is used if you decide to refactor your code. Also if you decide to precompile your views you will get a compiler time error immediately pointing to the view that needs to be fixed. With the second example you (ideally) or users of your site (worst case scenario) will get a runtime error when they visit this particular view.
Strongly typed helpers were first introduced in ASP.NET MVC 2 and the last time I used a weakly typed helper was in an ASP.NET MVC 1 application long time ago.
DropDownListFor will automatically select the selected value by using the specified property:
// Will select the item in model.Equipments that matches Model.EquipmentId
#Html.DropdownListFor(m => m.EquipmentId, Model.Equipments);
Another comment:
Don't have ICollection<Equipment> Equipments in your view model. You should have a property that returns an IEnumerable<SelectListItem>.
When you want to add a view (aspx file) where this DropDownList or DropDownListFor will be inside, rightclick->add view then select "Create a strongly typed view" then in list select Booking class. After that add this page.
You can write in it as follows:
#Html.DropdownListFor(m => m.Equipments , Model.Equipments);
because we add strongly typed view as Booking, you can have:
m => m.ID, m => m.Room, m => m.StartTime
... etc.
In your services you can have methods to take data from database, then use this service's method in your controller to pass data from database to view. You can use ViewData in your controller:
ViewData["Equipments"] = new servicename().getdatalistfromdatabase().AsEnumarable();
Putting AsEnumarable() at the end of your list taken from database makes it IEnumarable.
Then in your view, you can also have :
#Html.DropdownList("MyEquipments" , ViewData["Equipments"]);
A link on ViewData usage:
http://msdn.microsoft.com/en-us/library/dd410596.aspx
I hope that helps you.
DropdownListFor is support strongly type and it name assign by lambda Expression so it shows compile time error if have any error.
DropdownList not support this.
I Have 21 entities with the same structure.
Same Attribute too.
Every entity contains these Attributes :
AreaType
ID
IsActive
LangID
TXT
ModuleType
ID
IsActive
LangID
TXT
...
What I Need to perform a generic Crud. I already know that I need to create a generic repository. My problem is to perform a kind of generic ViewModel.
How can I create a generic View for the Create Form.
I Dont know what I need to pass in the Inherits of the view to be Generic.
... Inherits="System.Web.Mvc.ViewPage<...Dont know>"
Any Idea ?
A common approach this problem is to use ViewModels. This is where you create specific classes to be used as the models in your strongly typed views. These classes would not be the ones created by EF. The ViewModel classes can have a common base that encapulate your common fields. In your data access layer you would need to move data between your ViewModel classes and your EF classes. Things like AutoMapper (from CodePlex) work really well to reduce, if not eliminate, all of the the tedious "left-hand right-hand" coding.
Not too familiar with MVC, but (assuming it fits in with your hierarchy), I think you could create an abstract class which contains the properties you need, e.g.
public abstract class ViewableObject {
public abstract int ID {get; set;}
public abstract bool IsActive {get; set;}
// etc
}
Then implement that with your normal classes (AreaType and so on), e.g:
public class AreaType: ViewableObject{
public override int ID { get; set; }
public override bool IsActive{ get; set; }
}
and make the view use the abstract class.
... Inherits="System.Web.Mvc.ViewPage<ViewableObject>"
One idea is to simply change your underlying tables. Combine AreaType and ModuleType into a single "WhateverType" table that contains a field identifying exactly what type it is. Then when you codegen your classes you'll have exactly one class to deal with.
However, there are other concerns and you should only do this if it makes sense in your application.