Change value of checkbox using ajax in JSF - ajax

I try to solve the following problem: i have a group of h:selectBooleanCheckbox that generates using ui:repeat:
<h:form>
<ui:repeat value="#{uiCheckboxList.list}" var="boxElement" varStatus="i">
<h:selectBooleanCheckbox id="a">
<f:attribute name="value" value="#{boxElement.enabled}"/>
</h:selectBooleanCheckbox>
<h:outputLabel value="#{boxElement.val}" for="a"/>
</ui:repeat>
</h:form>
Values and label's text stored in array list and controls by servlet:
#ManagedBean(name="uiCheckboxList")
#ApplicationScoped
public class CheckBoxListBean implements Serializable {
private ArrayList<BoxTuple> list;
// BoxTyple is class with 2 fields - val (double) and enabled (boolean)
public CheckBoxListBean() {
list = new ArrayList<>();
for(double i = -2.0; i <= 2.0; i += 0.5) {
list.add(new BoxTuple(i, false));
}
// Set first element to true
list.get(0).setEnabled(true);
}
public ArrayList<BoxTuple> getList() {
return list;
}
public void setList(ArrayList<BoxTuple> list) {
this.list = list;
}
And my problem is this: when you click on one of the h:selectBooleanCheckbox server asynchronously sent request with information about the changed box, and then change the values of the another boxes without reloading page. In other words, I need to get the behavior of radio boxes. Maybe it sounds silly, but I need to solve this problem. How can i implement this?

You can do something like this:
<h:form id="form">
<ui:repeat value="#{uiCheckboxList.list}" var="boxElement"
varStatus="i">
<h:selectBooleanCheckbox id="a">
<f:attribute name="value" value="#{boxElement.enabled}" />
<f:ajax render="form"
listener="#{uiCheckboxList.listen(boxElement)}" />
</h:selectBooleanCheckbox>
<h:outputLabel value="#{boxElement.val}" for="a" />
</ui:repeat>
</h:form>
(get rid of the varStatus if you don't use it)
public void listen(BoxTuple tuple) {
if (tuple.enabled)
for (BoxTuple t : list)
if (!t.equals(tuple))
t.setEnabled(false);
}

Related

JSF/PrimeFaces: Selection based visibility

I want to show / now show (for example) a text, based on a radio selection.
In an ajax style, no roundtrip to server.
How do I have to do this with JSF/PrimeFaces?
<h:outputText value="Show some stupid Text." id="testShowText" />
<p:selectOneRadio id="testRadio" widgetVar="testRadio" value="True" layout="grid" columns="1">
<f:selectItem itemLabel="Show Text" itemValue="True"/>
<f:selectItem itemLabel="Do NOT show Text" itemValue="False"/>
</p:selectOneRadio>
UPDATE
I managed it in my test this way, but I am not sure, if this is the "best practice", I have some doubts; do I really need a managed bean for this?:
First I created a Bean to store the selected value:
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
#ManagedBean
#ViewScoped
public class ShowTextBean {
private boolean showBool = false;
private String showString = "False";
public ShowTextBean() {
}
public boolean isShowBool() {
return showBool;
}
public void setShowBool(boolean showBool) {
this.showBool = showBool;
}
public String getShowString() {
return showString;
}
public void setShowString(String showString) {
this.showString = showString;
}
}
Then I changed the Facelets Code to:
<p:panel id="testShowTextPanel" style="display: #{showTextBean.showString eq 'False' ? 'none' : 'block'} ">
<h:outputText value="Show some stupid Text." id="testShowText"/>
</p:panel>
<p:selectOneRadio id="testRadio" widgetVar="testRadio" value="#{showTextBean.showString}" layout="grid" columns="1">
<f:selectItem itemLabel="Show Text" itemValue="True"/>
<f:selectItem itemLabel="Do NOT show Text" itemValue="False"/>
<p:ajax update="testShowTextPanel" />
</p:selectOneRadio>

JSF 1.2 empty <h:selectManyListbox /> validation issue

I'm kind of new to JSF and I'm having trouble to understand what values JSF renders in a form after its validation fails. Im using WebSphere 7 and its default implementation of JSF, MyFaces (I think 2.0).
My xhtml looks like this:
<h:form id="form">
<h:inputText id="text" value="#{backing.text}" required="true"/>
<h:message for="text" />
<h:selectManyListbox id="options" value="#{backing.options}" required="true">
<f:selectItem itemLabel="1" itemValue="1" />
<f:selectItem itemLabel="2" itemValue="2" />
<f:selectItem itemLabel="3" itemValue="3" />
</h:selectManyListbox>
<h:message for="options" />
<h:commandButton value="Save" />
</h:form>
And my backing bean like this:
public class Backing {
private String text;
private String[] options;
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public String[] getOptions() {
return options;
}
public void setOptions(String[] options) {
this.options = options;
}
}
I fill the <h:inputText /> with some text.
I select two options from the <h:selectManyListbox />
I press the 'Save' button
The form is rendered with the value I entered for <h:inputText /> and with the options I selected on the <h:selectManyListbox /> (no validation messages are shown, as expected)
Now ...
I empty the <h:inputText />
I deselect the two options from the <h:selectManyListbox />
I press the 'Save' button
The form renders the <h:inputText /> empty and the <h:selectManyListbox /> with the previous options I had selected (both validation messages are shown, as expected)
As you can see, the behaviour when rendering the <h:inputText /> and the <h:selectManyListbox /> is different:
<h:inputText /> renders component's submitted value
<h:selectManyListbox /> renders bean's value
I've been trying to render <h:selectManyListbox /> with no options selected without hacking or messing my code, but had no luck.
¿Is this some bug? ¿Am I missing something?
The less hacky solution I found is to copy and re-implement the method renderOption, overriding the default MenuRenderer.
The original source is something like this as I had to decompile (version 1.2_13).
Notice that I'm pasting only the lines that actually need to be changed. If you need to use this solution you will have to copy the full contents of the method:
public class MenuRenderer extends HtmlBasicInputRenderer {
protected void renderOption(FacesContext context, UIComponent component, Converter converter, SelectItem curItem, Object currentSelections, Object[] submittedValues, HtmlBasicRenderer.OptionComponentInfo optionInfo) throws IOException {
(...)
Object valuesArray;
Object itemValue;
if (submittedValues != null) {
boolean containsValue = containsaValue(submittedValues);
if (containsValue) {
valuesArray = submittedValues;
itemValue = valueString;
} else {
valuesArray = currentSelections;
itemValue = curItem.getValue();
}
} else {
valuesArray = currentSelections;
itemValue = curItem.getValue();
}
(...)
}
}
I created CustomListboxRenderer (ListboxRenderer extends MenuRenderer) like this:
public class CustomListboxRenderer extends ListboxRenderer {
#Override
protected void renderOption(FacesContext context, UIComponent component, Converter converter, SelectItem curItem, Object currentSelections, Object[] submittedValues, HtmlBasicRenderer.OptionComponentInfo optionInfo) throws IOException {
(...)
Object valuesArray;
Object itemValue;
if (submittedValues != null) {
valuesArray = submittedValues;
itemValue = valueString;
} else {
valuesArray = currentSelections;
itemValue = curItem.getValue();
}
(...)
}
}
and then added in faces-config the next lines:
<render-kit>
<renderer>
<component-family>javax.faces.SelectMany</component-family>
<renderer-type>javax.faces.Listbox</renderer-type>
<renderer-class>CustomListboxRenderer</renderer-class>
</renderer>
</render-kit>

Table disappears after cell edit in primefaces (also data not saved)

I have an input field and a table on page. Whenever a number in a field changes (ajax listener to change event) - I want number of rows to change accordingly.
I pointed the table to an Arraylist in a Backing bean, and play with its size.
But then when I edit a value in the table - and press enter, the table disappears, and reappears only when I change field value again.
As a bonus, in debug mode, I see that backing arraylist always have empty values.
Here goes the Bean code:
#ManagedBean(name = "bean")
#ViewScoped
public class TestBean {
private List<String> hostnames = new ArrayList<String>();
private int copiesQuantityJustCopy;
public int getCopiesQuantityJustCopy() {
return copiesQuantityJustCopy;
}
public void setCopiesQuantityJustCopy(int copiesQuantityJustCopy) {
this.copiesQuantityJustCopy = copiesQuantityJustCopy;
}
public List<String> getHostnames() {
return hostnames;
}
public void setHostnames(List<String> hostnames) {
this.hostnames = hostnames;
}
public void onUpdateCount() {
int hostnamesCount = hostnames.size();
System.out.println("delta = " + hostnamesCount + " - " + copiesQuantityJustCopy);
int delta = hostnamesCount - copiesQuantityJustCopy;
if (delta > 0)
for (int i = 1; i < delta; i++)
hostnames.remove(delta);
if (delta < 0)
for (int i = 0; i < -delta; i++)
hostnames.add("");
}
}
and the view code:
<h:form id="form1">
<p:inputMask mask="9?99" maxlength="3" placeHolder=" " value="#{bean.copiesQuantityJustCopy}">
<p:ajax event="change" listener="#{bean.onUpdateCount()}" update=":form1:hostnamesTable" />
</p:inputMask>
<p:outputPanel id="hostnamesTable" rendered="true">
<p:dataTable value="#{bean.hostnames}" var="hostname"
id="hostnames" editable="true" editMode="cell">
<p:ajax event="cellEdit" update=":form1:hostnamesTable" process="#this" />
<p:column>
<p:cellEditor>
<f:facet name="output">
<h:outputText value="#{hostname}" />
</f:facet>
<f:facet name="input">
<p:inputText value="#{hostname}" style="width:96%" />
</f:facet>
</p:cellEditor>
</p:column>
</p:dataTable>
</p:outputPanel>
</h:form>
I think my answer won't help #Anton, but it may be helpful to another "stackers" facing same problem.
My problem is similar (dataTable dissapears when cellEdit event is completed). In my case the cause was the table update performed by ajax. Since I realy don't need table update after listener firied I simply removed update attribute and now everything works good to me.

Validate if new value of <h:inputText> is not higher than old value

I want to control the value in an <h:inputText> ..I want that once I leave the input fieldsif I have a higher value than the old value an error message is displayed and I can not validate fields after entering a value lower (the older value is loaded from the database)
I have done somthing like this :
<p:column headerText="Qte" >
<h:inputText value="#{ligne.qte}" styleClass="span12" required="true" valueChangeListener="#{myBean.changeQte}" >
<h:message id="message"></h:message>
<p:ajax event="keyup" listener="#{myBean.onQteChange}" update="message" />
</h:inputText>
</p:column>
in myBean I have this two methods :
public void onQteChange(){
String message =null;
int newqte = getQte();
if (newqte > previousQTE ){
message="invalid qte";
}
}
public void onQteChange(){
String message =null;
int newqte = getQte();
if (newqte > previousQTE ){
message="invalid qte";
}
}
Can someone tells me how can I do this because even if I try to make ajax call into my inputtext I have no result ?
You can use :
public void onQteChange(){
String message =null;
int newqte = getQte();
if (newqte > previousQTE ){
message="invalid qte";
FacesContext.getCurrentInstance().addMessage(
"message",new FacesMessage(FacesMessage.SEVERITY_ERROR, message,message));
}
}
<p:column headerText="Qte" >
<h:inputText value="#{ligne.qte}" id="x" styleClass="span12" required="true" valueChangeListener="#{myBean.changeQte}" >
<p:ajax event="keyup" listener="#{myBean.onQteChange}" update="message" />
</h:inputText>
<h:message id="message" for="x" />
</p:column>

Problems with ajax in jsf updating an output text field

I'm new to JSF and in class we should just set up a little "Pizza-Service" with logins etc. On the Page where i want to prepare my Order as a user I've a data table (primeface data table) with 4 columns. The last one is for the number of pizza of the type in the current cell.
What I want: If I am typing in a Number i want to set up a current Order (works fine so far with ajax) in the same moment i just want to show the user the current price. This is the little thing that is not working.
When I am using the tag there is just nothing happening and if I am taking the tag I'm getting this mistake:
<f:ajax> contains an unknown id 'ausgabe' - cannot locate it in the context of the component menge
What I thought was take the ajax tag set up a function (take the current order) and render an output text where the calculated price is shown directly. I called those function in german so bestellungAufnehmen = takeOrder and preisBerechnen = calculatePrice.
Thanks if someone could help me!
Here is the xhtml:
<h:head>
<title>Facelet Title</title>
</h:head>
<h:body>
<h:form>
<p:dataTable id="table" var="pizza" value="#{model.getPizzen()}">
<p:column headerText="Nr">
<h:outputText value="#{pizza.nr}"/>
</p:column>
<p:column headerText="Artikel">
<h:outputText value="#{pizza.name}"/>
</p:column>
<p:column headerText="Preis">
<h:outputText value="#{pizza.preis}"/>
</p:column>
<p:column headerText ="Menge">
<h:inputText id="menge" value="#{bestellung.anzahl}">
<f:ajax event="keyup" render="ausgabe" listener="#{bestellung.bestellungAufnehmen(pizza)}"/>
</h:inputText>
</p:column>
</p:dataTable>
<h:outputLabel value="Zu Zahlen: "/>
<h:outputText id="ausgabe" value="#{bestellung.preisBerechnen()} €"/>
</h:form>
</h:body>
and here is the the Bean with those functions.
#Named
#SessionScoped
public class Bestellung implements Serializable {
private static int bstzaehler=0;
private int bstnr;
private Map<String,Bestellposten> posten;
private int anzahl;
public Bestellung(){
this.bstnr=++bstzaehler;
this.posten = new HashMap<>();
}
/**
* #return the bstnr
*/
public int getBstnr() {
return bstnr;
}
/**
* #param bstnr the bstnr to set
*/
public void setBstnr(int bstnr) {
this.bstnr = bstnr;
}
public void bestellungAufnehmen(Pizza pizza){
if(this.posten.containsKey(pizza.getName()) == false){
Bestellposten b = new Bestellposten(this.getAnzahl(), pizza);
this.posten.put(pizza.getName(),b);
} else {
if(this.getAnzahl() > 0 ){
Bestellposten tmp = this.posten.get(pizza.getName());
tmp.setMenge(this.getAnzahl());
} else {
this.posten.remove(pizza.getName());
}
}
System.out.println("groesse: "+posten.size());
System.out.println("akt preis: "+this.preisBerechnen());
}
/**
* #return the anzahl
*/
public int getAnzahl() {
return anzahl;
}
/**
* #param anzahl the anzahl to set
*/
public void setAnzahl(int anzahl) {
this.anzahl = anzahl;
}
public double preisBerechnen(){
double sum = 0.0;
for(String key : this.posten.keySet()){
Pizza tmp = this.posten.get(key).getPizza();
sum += tmp.getPreis() * this.posten.get(key).getMenge();
}
return sum;
}
}
Try giving the full qualified id for the component:
<h:form id="frmPizza">
<p:dataTable id="table" var="pizza" value="#{model.getPizzen()}">
<p:column headerText="Nr">
<h:outputText value="#{pizza.nr}"/>
</p:column>
<p:column headerText="Artikel">
<h:outputText value="#{pizza.name}"/>
</p:column>
<p:column headerText="Preis">
<h:outputText value="#{pizza.preis}"/>
</p:column>
<p:column headerText ="Menge">
<h:inputText id="menge" value="#{bestellung.anzahl}">
<f:ajax event="keyup" render=":frmPizza:ausgabe" listener="#{bestellung.bestellungAufnehmen(pizza)}"/>
</h:inputText>
</p:column>
</p:dataTable>
<h:outputLabel value="Zu Zahlen: "/>
<h:outputText id="ausgabe" value="#{bestellung.preisBerechnen()} €"/>
</h:form>
I think, you should use update attribute to update that outputText, like update=":FormId:ausgabe"
<f:ajax event="keyup"
render=":frmPizza:ausgabe"
listener="#{bestellung.bestellungAufnehmen(pizza)}"
update=":frmPizza:ausgabe" />
The solution of luiggi worked but i couldnt answer directly because of my "low-level" here.
Iam not on my computer right now but isnt "update" an attribute of p:ajax and not of f:ajax and is the same as render? but i will try it aswell later on.
thx!

Resources