Generate unique ID in inputText on page load - jsf-2

I want to genrate a unique number in <p:inputText> on page load.
I can generate an unique value using java.util.UUID, but how can I set it on the value of the <p:inputText> on page load?
<p:inputText id="ptId" label="PatientId" value="#{addBB.pt.patientId}" />

Just set the value during bean's (post)construction.
#ManagedBean
#ViewScoped
public class AddBB {
private Patient pt;
#PostConstruct
public void init() {
pt = new Patient();
pt.setPatientId(UUID.randomUUID().toString());
}
// ...
}

you can do this just by making userId, the default value for inputText like this -
value="#{beanName.userId}"
so that first use it like u want to use and then u can set the value of userId at any point of time as the unique id, just remember to reRender it.
Hope you got what u wanted....

Related

Vaadin data Binder - ComboBox issues

Later Edit: I noticed that by returning one of the options in ValueProvider's apply method leads to having the check mark present, but appears to show the previous select too. I.e. if the current and previous values are distinct, two check marks are shown.
I am having troubles with ComboBox binding. I cannot get the com.vaadin.flow.data.binder.Binder properly select an option inside the combobox - i.e. tick the check mark in the dropdown.
My binder is a "generic", i.e. I am using it along with a Map, and I provide dynamic getters/setters for various map keys. So, consider Binder<Map>, while one of the properites inside the Map should be holding a Person's id.
ComboBox<Person> combobox = new ComboBox<>("Person");
List<Person> options = fetchPersons();
combobox.setItems(options);
combobox.setItemLabelGenerator(new ItemLabelGenerator<Person>() {
#Override
public String apply(final Person p) {
return p.getName();
}
});
binder.bind(combobox, new ValueProvider<Map, Person>() {
#Override
public Person apply(final Map p) {
return new Person((Long)p.get("id"), (String)p.get("name"));
}
}, new Setter<Map, Person>() {
#Override
public void accept(final Map bean, final Person p) {
bean.put("name", p.getName());
}
});
Wondering what could I possibly do wrong...
Later edit: Adding a screenshot for the Status ComboBox which has a String for caption and Integer for value.
Your problem is that you are creating a new instance in your binding, which is not working. You probably have some other bean, (I say here Bean) where Person is a property. So you want to use Binder of type Bean, to bind ComboBox to the property, which is a Person. And then populate your form with the Bean by using e.g. binder.readBean(bean). Btw. using Java 8 syntax makes your code much less verbose.
Bean bean = fetchBean();
Binder<Bean> binder = new Binder();
ComboBox<Person> combobox = new ComboBox<>("Person");
List<Person> options = fetchPersons();
combobox.setItems(options);
combobox.setItemLabelGenerator(Person::getName);
binder.forField(combobox).bind(Bean::getPerson, Bean::setPerson);
binder.readBean(bean);

JSF SelectOneMenu value cannot be user defined type? [duplicate]

I am creating a web application, where you have to read a list of objects / entities from a DB and populate it in a JSF <h:selectOneMenu>. I am unable to code this. Can someone show me how to do it?
I know how to get a List<User> from the DB. What I need to know is, how to populate this list in a <h:selectOneMenu>.
<h:selectOneMenu value="#{bean.name}">
...?
</h:selectOneMenu>
Based on your question history, you're using JSF 2.x. So, here's a JSF 2.x targeted answer. In JSF 1.x you would be forced to wrap item values/labels in ugly SelectItem instances. This is fortunately not needed anymore in JSF 2.x.
Basic example
To answer your question directly, just use <f:selectItems> whose value points to a List<T> property which you preserve from the DB during bean's (post)construction. Here's a basic kickoff example assuming that T actually represents a String.
<h:selectOneMenu value="#{bean.name}">
<f:selectItems value="#{bean.names}" />
</h:selectOneMenu>
with
#ManagedBean
#RequestScoped
public class Bean {
private String name;
private List<String> names;
#EJB
private NameService nameService;
#PostConstruct
public void init() {
names = nameService.list();
}
// ... (getters, setters, etc)
}
Simple as that. Actually, the T's toString() will be used to represent both the dropdown item label and value. So, when you're instead of List<String> using a list of complex objects like List<SomeEntity> and you haven't overridden the class' toString() method, then you would see com.example.SomeEntity#hashcode as item values. See next section how to solve it properly.
Also note that the bean for <f:selectItems> value does not necessarily need to be the same bean as the bean for <h:selectOneMenu> value. This is useful whenever the values are actually applicationwide constants which you just have to load only once during application's startup. You could then just make it a property of an application scoped bean.
<h:selectOneMenu value="#{bean.name}">
<f:selectItems value="#{data.names}" />
</h:selectOneMenu>
Complex objects as available items
Whenever T concerns a complex object (a javabean), such as User which has a String property of name, then you could use the var attribute to get hold of the iteration variable which you in turn can use in itemValue and/or itemLabel attribtues (if you omit the itemLabel, then the label becomes the same as the value).
Example #1:
<h:selectOneMenu value="#{bean.userName}">
<f:selectItems value="#{bean.users}" var="user" itemValue="#{user.name}" />
</h:selectOneMenu>
with
private String userName;
private List<User> users;
#EJB
private UserService userService;
#PostConstruct
public void init() {
users = userService.list();
}
// ... (getters, setters, etc)
Or when it has a Long property id which you would rather like to set as item value:
Example #2:
<h:selectOneMenu value="#{bean.userId}">
<f:selectItems value="#{bean.users}" var="user" itemValue="#{user.id}" itemLabel="#{user.name}" />
</h:selectOneMenu>
with
private Long userId;
private List<User> users;
// ... (the same as in previous bean example)
Complex object as selected item
Whenever you would like to set it to a T property in the bean as well and T represents an User, then you would need to bake a custom Converter which converts between User and an unique string representation (which can be the id property). Do note that the itemValue must represent the complex object itself, exactly the type which needs to be set as selection component's value.
<h:selectOneMenu value="#{bean.user}" converter="#{userConverter}">
<f:selectItems value="#{bean.users}" var="user" itemValue="#{user}" itemLabel="#{user.name}" />
</h:selectOneMenu>
with
private User user;
private List<User> users;
// ... (the same as in previous bean example)
and
#ManagedBean
#RequestScoped
public class UserConverter implements Converter {
#EJB
private UserService userService;
#Override
public Object getAsObject(FacesContext context, UIComponent component, String submittedValue) {
if (submittedValue == null || submittedValue.isEmpty()) {
return null;
}
try {
return userService.find(Long.valueOf(submittedValue));
} catch (NumberFormatException e) {
throw new ConverterException(new FacesMessage(String.format("%s is not a valid User ID", submittedValue)), e);
}
}
#Override
public String getAsString(FacesContext context, UIComponent component, Object modelValue) {
if (modelValue == null) {
return "";
}
if (modelValue instanceof User) {
return String.valueOf(((User) modelValue).getId());
} else {
throw new ConverterException(new FacesMessage(String.format("%s is not a valid User", modelValue)), e);
}
}
}
(please note that the Converter is a bit hacky in order to be able to inject an #EJB in a JSF converter; normally one would have annotated it as #FacesConverter(forClass=User.class), but that unfortunately doesn't allow #EJB injections)
Don't forget to make sure that the complex object class has equals() and hashCode() properly implemented, otherwise JSF will during render fail to show preselected item(s), and you'll on submit face Validation Error: Value is not valid.
public class User {
private Long id;
#Override
public boolean equals(Object other) {
return (other != null && getClass() == other.getClass() && id != null)
? id.equals(((User) other).id)
: (other == this);
}
#Override
public int hashCode() {
return (id != null)
? (getClass().hashCode() + id.hashCode())
: super.hashCode();
}
}
Complex objects with a generic converter
Head to this answer: Implement converters for entities with Java Generics.
Complex objects without a custom converter
The JSF utility library OmniFaces offers a special converter out the box which allows you to use complex objects in <h:selectOneMenu> without the need to create a custom converter. The SelectItemsConverter will simply do the conversion based on readily available items in <f:selectItem(s)>.
<h:selectOneMenu value="#{bean.user}" converter="omnifaces.SelectItemsConverter">
<f:selectItems value="#{bean.users}" var="user" itemValue="#{user}" itemLabel="#{user.name}" />
</h:selectOneMenu>
See also:
Our <h:selectOneMenu> wiki page
View-Page
<h:selectOneMenu id="selectOneCB" value="#{page.selectedName}">
<f:selectItems value="#{page.names}"/>
</h:selectOneMenu>
Backing-Bean
List<SelectItem> names = new ArrayList<SelectItem>();
//-- Populate list from database
names.add(new SelectItem(valueObject,"label"));
//-- setter/getter accessor methods for list
To display particular selected record, it must be one of the values in the list.
Roll-your-own generic converter for complex objects as selected item
The Balusc gives a very useful overview answer on this subject. But there is one alternative he does not present: The Roll-your-own generic converter that handles complex objects as the selected item. This is very complex to do if you want to handle all cases, but pretty simple for simple cases.
The code below contains an example of such a converter. It works in the same spirit as the OmniFaces SelectItemsConverter as it looks through the children of a component for UISelectItem(s) containing objects. The difference is that it only handles bindings to either simple collections of entity objects, or to strings. It does not handle item groups, collections of SelectItems, arrays and probably a lot of other things.
The entities that the component binds to must implement the IdObject interface. (This could be solved in other way, such as using toString.)
Note that the entities must implement equals in such a way that two entities with the same ID compares equal.
The only thing that you need to do to use it is to specify it as converter on the select component, bind to an entity property and a list of possible entities:
<h:selectOneMenu value="#{bean.user}" converter="selectListConverter">
<f:selectItem itemValue="unselected" itemLabel="Select user..."/>
<f:selectItem itemValue="empty" itemLabel="No user"/>
<f:selectItems value="#{bean.users}" var="user" itemValue="#{user}" itemLabel="#{user.name}" />
</h:selectOneMenu>
Converter:
/**
* A converter for select components (those that have select items as children).
*
* It convertes the selected value string into one of its element entities, thus allowing
* binding to complex objects.
*
* It only handles simple uses of select components, in which the value is a simple list of
* entities. No ItemGroups, arrays or other kinds of values.
*
* Items it binds to can be strings or implementations of the {#link IdObject} interface.
*/
#FacesConverter("selectListConverter")
public class SelectListConverter implements Converter {
public static interface IdObject {
public String getDisplayId();
}
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
if (value == null || value.isEmpty()) {
return null;
}
return component.getChildren().stream()
.flatMap(child -> getEntriesOfItem(child))
.filter(o -> value.equals(o instanceof IdObject ? ((IdObject) o).getDisplayId() : o))
.findAny().orElse(null);
}
/**
* Gets the values stored in a {#link UISelectItem} or a {#link UISelectItems}.
* For other components returns an empty stream.
*/
private Stream<?> getEntriesOfItem(UIComponent child) {
if (child instanceof UISelectItem) {
UISelectItem item = (UISelectItem) child;
if (!item.isNoSelectionOption()) {
return Stream.of(item.getValue());
}
} else if (child instanceof UISelectItems) {
Object value = ((UISelectItems) child).getValue();
if (value instanceof Collection) {
return ((Collection<?>) value).stream();
} else {
throw new IllegalStateException("Unsupported value of UISelectItems: " + value);
}
}
return Stream.empty();
}
#Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
if (value == null) return null;
if (value instanceof String) return (String) value;
if (value instanceof IdObject) return ((IdObject) value).getDisplayId();
throw new IllegalArgumentException("Unexpected value type");
}
}
I'm doing it like this:
Models are ViewScoped
converter:
#Named
#ViewScoped
public class ViewScopedFacesConverter implements Converter, Serializable
{
private static final long serialVersionUID = 1L;
private Map<String, Object> converterMap;
#PostConstruct
void postConstruct(){
converterMap = new HashMap<>();
}
#Override
public String getAsString(FacesContext context, UIComponent component, Object object) {
String selectItemValue = String.valueOf( object.hashCode() );
converterMap.put( selectItemValue, object );
return selectItemValue;
}
#Override
public Object getAsObject(FacesContext context, UIComponent component, String selectItemValue){
return converterMap.get(selectItemValue);
}
}
and bind to component with:
<f:converter binding="#{viewScopedFacesConverter}" />
If you will use entity id rather than hashCode you can hit a collision- if you have few lists on one page for different entities (classes) with the same id
Call me lazy but coding a Converter seems like a lot of unnecessary work. I'm using Primefaces and, not having used a plain vanilla JSF2 listbox or dropdown menu before, I just assumed (being lazy) that the widget could handle complex objects, i.e. pass the selected object as is to its corresponding getter/setter like so many other widgets do. I was disappointed to find (after hours of head scratching) that this capability does not exist for this widget type without a Converter. In fact if you supply a setter for the complex object rather than for a String, it fails silently (simply doesn't call the setter, no Exception, no JS error), and I spent a ton of time going through BalusC's excellent troubleshooting tool to find the cause, to no avail since none of those suggestions applied. My conclusion: listbox/menu widget needs adapting that other JSF2 widgets do not. This seems misleading and prone to leading the uninformed developer like myself down a rabbit hole.
In the end I resisted coding a Converter and found through trial and error that if you set the widget value to a complex object, e.g.:
<p:selectOneListbox id="adminEvents" value="#{testBean.selectedEvent}">
... when the user selects an item, the widget can call a String setter for that object, e.g. setSelectedThing(String thingString) {...}, and the String passed is a JSON String representing the Thing object. I can parse it to determine which object was selected. This feels a little like a hack, but less of a hack than a Converter.

Vaadin Bean validation for table

When I enter edit mode of my Table, I want to have data validation on all fields in that Table.
First, a couple of notes:
I'm using Vaadin 7, so the Bean Validation addon sadly won't work.
I know the implementation of JSR-303 works, because I tried adding a BeanValidator to a TextField without issues.
Now, I have a perfectly working table for which I am using a BeanItemContainer to keep my Person beans inside.
The Person bean looks as follows:
public class Person {
#Size(min = 5, max = 50)
private String firstName;
#Size(min = 5, max = 50)
private String lastName;
#Min(0)
#Max(2000)
private int description;
... getters + setters...
}
Person beans are added to the BeanItemContainer, which in turn is set to the container data source with setContainerDataSource()
The BeanValidator was added to the table like so:
table.addValidator(new BeanValidator(Person.class, "firstName"));
When I run the application, I have two problems:
When I run the application, the table shows up as intended. However, when I edit the fields and set one of the firstName fields to, say, "abc" - no validation error is shown and the value is accepted
How am I supposed to get BeanValidator to work on all of my tables fields?
When I use table.setSelectable(true) or table.setMultiSelect(true), I get this error:
com.vaadin.server.ServiceException:
java.lang.IllegalArgumentException: [] is not a valid value for
property firstName of type class
com.some.path.vaadinpoc.sampleapp.web.Person
How am I supposed to get BeanValidator to work with Selectable/MultiSelect?
Please advice
Thanks!
You'll need to add the validators to the editable fields themselves, not to the table. (Table itself is a field => the Validator from table.addValidator validates the value of the Table => the value of the table is the selected itemId(s) => the BeanValidator fails)
You can add the validators to the fields that by using a custom TableFieldFactory on the table. Here's a very simple one-off example for this scenario - clearly, if you need to do this with a lot of different beans/tables, it'll be worth creating a more generic/customizable factory
table.setTableFieldFactory(new DefaultFieldFactory() {
#Override
public Field<?> createField(Item item, Object propertyId, Component uiContext) {
Field<?> field = super.createField(item, propertyId, uiContext);
if (propertyId.equals("firstName")) {
field.addValidator(new BeanValidator(Person.class, "firstName"));
}
if (propertyId.equals("lastName")) {
field.addValidator(new BeanValidator(Person.class, "lastName"));
}
if (propertyId.equals("description")) {
field.addValidator(new BeanValidator(Person.class, "description"));
}
return field;
}

Update a row in ASP.NET and MVC LINQ to SQL

I have a simple row that has 4 columns:
{ [Primary Key Int]RowID, [text]Title, [text]Text, [datetime]Date }
I would like to allow the user to edit this row on a simple page that has a form with the fields "Title" and "Text".
There is a hidden field to store the RowID.
When the user posts this form to my controller action, I want it to update the row's Title and Text, and keep the Date the same. I don't want to have to explicitly include a hidden field for the Date in the form page.
Here is my action:
[AcceptVerbs(HttpVerb.Post)]
public ActionResult EditRow(Row myRow)
{
RowRepository.SaveRow(myRow)
return View("Success");
}
RowRepository:
public void SaveRow(Row myRow)
{
db.MyRows.Attach(myRow);
db.Refresh(RefreshMode.KeepCurrentValues, myRow);
db.SubmitChanges();
}
This dosen't keep the "Date" value already in the row and tries to insert a value that throws an timespan exception.
How can I just tell it to keep the old values?
I tried doing RefreshMode.KeepChanges and nothing.
I'm not in a position to test this at the moment but try making the datetime column nullable and then ensure that the datetime passed into SaveRow has a null value.
Try
[AcceptVerbs(HttpVerb.Post)]
public ActionResult EditRow([Bind(Exclude="Date")] Row myRow) {
RowRepository.SaveRow(myRow)
return View("Success");
}
Update
Try this approach, where there is no 'Date' field on your page
[AcceptVerbs(HttpVerb.Post)]
public ActionResult EditRow(int RowID) {
Row myRow = RowRepository.GetRow(RowID);
UpdateModel(myRow);
RowRepository.Save();
return View("Success");
}
In your repository
public void Save() {
db.SubmitChanges();
}
This will only save the changes made to 'myRow'
You will have add a method in the partial class / override the code it build.
The class Table does implement "INotifyPropertyChanging|ed" which is used to track which column has been changed.
You can hack it and reset the value "this.PropertyChanged".
But what I do at work is a stupid READ-APPLY-WRITE approach (and I am using WebForm).
public void SaveRow(Row myRow)
{
var obj=db.MyRows.Where(c=>c.id==myRow.id).First();
obj.a=myRow.a;
obj.b=myRow.b;
db.SubmitChanges();
}
You can do a bit simpler.
public void SaveRow(Row myRow)
{
db.MyRows.Attach(new Row(){
Id=myRow.Id,
Title=myRow.Title,
Text=myRow.Text,
});
db.SubmitChanges();
}
PS. I am new to LINQ to SQL. Please let me know if there is a smarter way to do it.
Ok, I set it to nullable and it keeps overwriting the database as a null value. I guess its impossible to do this since technically null is a valid value for the column and if I pass an object to the function, the empty values must contain something or be null.
So I would have to explicitly state to take the database value for that column
Thanks

struts2 - optiontransferselect - pass list of integers to the action

I have an optiontransferselect in a form but i dont know how to get the selected items in the rightlist back in my action.
I need to get a list with all the visited countries' ids. i tried in my action List (Integer) countriesVisitedId; but it returns nullPointerException. then i tried Integer id but it returns null.
this is what i have:
s:optiontransferselect
label="Select visited countries"
name="countriesNotVisitedId"
leftTitle="Not visited countries"
rightTitle="Visited Countries"
list="%{countriesNotVisited}"
listKey="id"
listValue="name"
headerKey="countryNotVisitedId"
headerValue="--- Please Select ---"
doubleName="countriesVisitedId"
doubleList="%{countriesVisited}"
doubleHeaderKey="countryVisitedId"
doubleHeaderValue="--- Please Select ---"
doubleListKey="id"
doubleListValue="name" />
how can I get the list with the Integers ids of the visited countries in my action?
I was banging my head on the wall wondering what I was doing wrong. It is pretty simple
doubleName="fields" is the tag field that is returned
public void setFields(String fields) { this is what needs to be in your action class.
The thing that I didn't realise is the elements need to be selected in order to be sent back. Or simple use ajax with in your header
Here's what I tried, it works fine.
Step 1: JSP to select the country from the left hand side into right hand.
<s:optiontransferselect
label="Favourite Characters"
name="leftSide"
id="left"
leftTitle="Left Title"
rightTitle="Right Title"
list="%{countriesNotVisited)"
multiple="true"
headerKey="headerKey"
doubleList="{}"
doubleId="right"
doubleName="rightSide"
doubleHeaderKey="doubleHeaderKey"
doubleMultiple="true" />
Step 2: Javascript code to auto select all data from the right hand side.
function selectall()
{
var list = document.getElementById("right");
for (var i = 0; i < list.options.length; i++)
{
alert(list.options[i].value)
list.options[i].selected = true;
}
var form = document.getElementById("right");
form.submit();
return true;
}
Step 3: call this function on submit, from the JSP side.
<s:submit id="submitid" value="Submit" action="insert" onclick="selectall()"/>
Step 4: In the action, make the getters and setters of object names of the left and right sides take strings and not string arrays.
private String leftSide;
private String rightSide;
public String getLeftSide() {
return leftSide;
}
public String getRightSide() {
return rightSide;
}
public void setRightSide(String rightSide) {
this.rightSide = rightSide;
}
public void setLeftSide(String leftSide) {
this.leftSide = leftSide;
}
Now if you try to print a value in the action, you will get values:
System.out.println("right side list " + ad.getRightSide());
In your action:
public void setCountriesVisitedId(String[] countriesVisitedId) {
this.countriesVisitedId = countriesVisitedId;
}

Resources