Copying value of a textbox to a nother using ajax in jsf - ajax

I am very new to ajax and trying to copy the value of one box to another. Here is my code:
<h:form>
<h:inputText value="#{ajaxBean.name}">
<f:ajax render="otherbox" execute="#this" event="keyup"></f:ajax>
</h:inputText>
<h:inputText id="otherbox" value="#{ajaxBean.name}"></h:inputText>
</h:form>
And the bean
#Named(value = "ajaxBean")
#Dependent
public class AjaxBean {
public AjaxBean() {
}
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
That code does not work. Can anyone help me?
Thanks

Your question is not about Ajax or JSF. It is a JavaScript question.
You can access and modify items with JavaScript.
Add this JavaScript codes between <h:head></h:head>
<script>
function copyField()
{
document.getElementById("field2").value = document.getElementById("field1").value;
}
</script>
And your page:
<h:form id="myform" prependId="false">
<h:inputText id="field1" value="#{myBean.name}" onkeyup="copyField();" />
<h:inputText id="field2" value="#{myBean.name}"></h:inputText>
</h:form>
Take attention to prependId="false" to avoid mixing ids.
See also:
JSF: Why prependId = false in a form?

I think you are mixing up JSF and CDI. #Dependent says that the bean is in the dependent pseudo-scope (which is anyways the default-scope for CDI-beans), so every time you make a request the bean will be reinstanciated and the bean can not hold any state. Look here for an explanation of the scopes and especially for what the dependent scope is used for.
So first of all you have to use some different scope, #RequestScoped should be enough for your task. And as I do not see any use of CDI here, use #ManagedBean instead of #Named - so the default scope for the bean will be the request scope.
Try this:
#ManagedBean
public class AjaxBean {
...
}

Related

h:form inside ui:repeat doesn't work as expected

For a huge project, I need to build multiple forms on a web page. Can't go into details, but assume to have the requested structure of a list of forms; using mojarra jsf 2.2.5
given Managed Bean:
#ManagedBean
#SessionScoped
public class Debug {
private final List<DebugBean> list;
public Debug() {
super();
this.list = new ArrayList<DebugBean>();
this.list.add(new DebugBean("label 1", "value 1"));
this.list.add(new DebugBean("label 2", "value 2"));
}
public String submit() {
LOGGER.info("list = " + this.list.toString());
return "";
}
public List<DebugBean> getList() {
return this.list;
}
}
The bean DebugBean is simple, just contains two variables label and value, both String, and its setter and getter.
Now the xhtml page:
<h:body style="height: 100%">
<ui:repeat value="#{debug.list}" var="x">
<h:form>
<h:panelGrid columns="2">
<h:outputText value="#{x.label}" />
<h:inputTextarea value="#{x.value}" />
</h:panelGrid>
<h:commandButton action="#{debug.submit}" value="ok" />
</h:form>
</ui:repeat>
</h:body>
The problem is in changing the first value. When I change the second one, the logger gives me the new value as expected. But changing the first one, the logger gives me the old list, as if I would have reloaded the complete form without any changes. What's the problem here, and more important: what can I do to make it work?
The solution is simple, but worse. I don't know why, but ui:repeat does not behave as h:dataTable does. So replacing ui:repeat by h:dataTable solves the problem, but means page layout rework (which is a bigger problem, but can be done by me).

Dynamic ajax navigation with <ui:include>

Suppose I want to navigate in my application, and include different facelet pages dynamically. I have a commandLink like this:
<h:commandLink value="Link" action="#{navigation.goTo('someTest')}">
<f:ajax render=":content" />
</h:commandLink>
And this is where I include the facelet:
<h:form id="content">
<ui:include src="#{navigation.includePath}" />
</h:form>
The Navigation class:
public class Navigation {
private String viewName;
public void goTo(String viewName) {
this.viewName = viewName;
}
public String getIncludePath() {
return resolvePath(viewName);
}
}
I have seen similar examples, but this doesn't work of course. As ui:include is a taghandler, the include happens long before my navigation listener is invoked. The old facelet is included, instead of the new. So far I get it.
Now to the headache part: How can I dynamically include a facelet, based on an actionListener? I tried to include the facelet in a preRender event, and a phaseListener before RENDER_RESPONSE. Both work, but in the event listener I can't include a facelet which contains an other preRender event, and in the phaseListener I get duplicate Id's after some clicks in the included facelet. However, inspecting the component tree tells me, there are no duplicate components at all. Maybe these two ideas were not to good at all..
I need a solution, where the page with the ui:include, or the Java class which includes the facelet, doesn't have to know the pages, which will be included, nor the exact path. Did anybody solve this problem before? How can I do it?
I am using JSF 2.1 and Mojarra 2.1.15
All you need to reproduce the Problem is this bean:
#Named
public class Some implements Serializable {
private static final long serialVersionUID = 1L;
private final List<String> values = new ArrayList<String>();
public Some() {
values.add("test");
}
public void setInclude(String include) {
}
public List<String> getValues() {
return values;
}
}
This in your index file:
<h:head>
<h:outputScript library="javax.faces" name="jsf.js" />
</h:head>
<h:body>
<h:form id="topform">
<h:panelGroup id="container">
<my:include src="/test.xhtml" />
</h:panelGroup>
</h:form>
</h:body>
And this in text.xhtml
<ui:repeat value="#{some.values}" var="val">
<h:commandLink value="#{val}" action="#{some.setInclude(val)}">
<f:ajax render=":topform:container" />
</h:commandLink>
</ui:repeat>
That's enough to produce an error like this:
javax.faces.FacesException: Cannot add the same component twice: topform:j_id-549384541_7e08d92c
For OmniFaces, I've also ever experimented with this by creating an <o:include> as UIComponent instead of a TagHandler which does a FaceletContext#includeFacelet() in the encodeChildren() method. This way the right included facelet is remembered during restore view phase and the included component tree only changes during render response phase, which is exactly what we want to achieve this construct.
Here's a basic kickoff example:
#FacesComponent("com.example.Include")
public class Include extends UIComponentBase {
#Override
public String getFamily() {
return "com.example.Include";
}
#Override
public boolean getRendersChildren() {
return true;
}
#Override
public void encodeChildren(FacesContext context) throws IOException {
getChildren().clear();
((FaceletContext) context.getAttributes().get(FaceletContext.FACELET_CONTEXT_KEY)).includeFacelet(this, getSrc());
super.encodeChildren(context);
}
public String getSrc() {
return (String) getStateHelper().eval("src");
}
public void setSrc(String src) {
getStateHelper().put("src", src);
}
}
Which is registered in .taglib.xml as follows:
<tag>
<tag-name>include</tag-name>
<component>
<component-type>com.example.Include</component-type>
</component>
<attribute>
<name>src</name>
<required>true</required>
<type>java.lang.String</type>
</attribute>
</tag>
This works fine with the following view:
<h:outputScript name="fixViewState.js" />
<h:form>
<ui:repeat value="#{includeBean.includes}" var="include">
<h:commandButton value="Include #{include}" action="#{includeBean.setInclude(include)}">
<f:ajax render=":include" />
</h:commandButton>
</ui:repeat>
</h:form>
<h:panelGroup id="include">
<my:include src="#{includeBean.include}.xhtml" />
</h:panelGroup>
And the following backing bean:
#ManagedBean
#ViewScoped
public class IncludeBean implements Serializable {
private List<String> includes = Arrays.asList("include1", "include2", "include3");
private String include = includes.get(0);
private List<String> getIncludes() {
return includes;
}
public void setInclude(String include) {
return this.include = include;
}
public String getInclude() {
return include;
}
}
(this example expects include files include1.xhtml, include2.xhtml and include3.xhtml in the same base folder as the main file)
The fixViewState.js can be found in this answer: h:commandButton/h:commandLink does not work on first click, works only on second click. This script is mandatory in order to fix JSF issue 790 whereby the view state get lost when there are multiple ajax forms which update each other's parent.
Also note that this way each include file can have its own <h:form> when necessary, so you don't necessarily need to put it around the include.
This approach works fine in Mojarra, even with postback requests coming from forms inside the include, however it fails hard in MyFaces with the following exception during initial request already:
java.lang.NullPointerException
at org.apache.myfaces.view.facelets.impl.FaceletCompositionContextImpl.generateUniqueId(FaceletCompositionContextImpl.java:910)
at org.apache.myfaces.view.facelets.impl.DefaultFaceletContext.generateUniqueId(DefaultFaceletContext.java:321)
at org.apache.myfaces.view.facelets.compiler.UIInstructionHandler.apply(UIInstructionHandler.java:87)
at javax.faces.view.facelets.CompositeFaceletHandler.apply(CompositeFaceletHandler.java:49)
at org.apache.myfaces.view.facelets.tag.ui.CompositionHandler.apply(CompositionHandler.java:158)
at org.apache.myfaces.view.facelets.compiler.NamespaceHandler.apply(NamespaceHandler.java:57)
at org.apache.myfaces.view.facelets.compiler.EncodingHandler.apply(EncodingHandler.java:48)
at org.apache.myfaces.view.facelets.impl.DefaultFacelet.include(DefaultFacelet.java:394)
at org.apache.myfaces.view.facelets.impl.DefaultFacelet.include(DefaultFacelet.java:448)
at org.apache.myfaces.view.facelets.impl.DefaultFacelet.include(DefaultFacelet.java:426)
at org.apache.myfaces.view.facelets.impl.DefaultFaceletContext.includeFacelet(DefaultFaceletContext.java:244)
at com.example.Include.encodeChildren(Include.java:54)
MyFaces basically releases the Facelet context during end of view build time, making it unavailable during view render time, resulting in NPEs because the internal state has several nulled-out properties. It's however possible to add individual components instead of a Facelet file during render time. I didn't really have had the time to investigate if this is my fault or MyFaces' fault. That's also why it didn't end up in OmniFaces yet.
If you're using Mojarra anyway, feel free to use it. I however strongly recommend to test it thoroughly with all possible use cases on the very same page. Mojarra has some state saving related quirks which might fail when using this construct.

AJAX onSubmit validation in JSF 2.0

I've started learning JSF2.0, and have come across a problem. Any advice on how to proceed would be welcome.
I have renamed form elements and classes for simplicity sake.
I have a form, for example:
<h:form id="frmSearch">
<h:inputText id="dataPoint1" value="#{bean.dataPoint1}"/>
<div id="dataPoint1Error" class="msgError">Value not found in database.</div>
<h:inputText id="dataPoint2" value="#{bean.dataPoint2}"/>
<div id="dataPoint2Error" class="msgError">Value not found in database.</div>
<h:commandButton action="#{bean.validate}" type="submit" value="Search"/>
</h:form>
The CSS class "msgError" keeps the element hidden by default.
I would like to basically have a method in the "bean" class that validates the input by checking against the database, then if the value isn't found, unhide the error message, or if it is found, then execute another method which performs the actual functionality.
In my head, it would work sort of like this in the Java (forgive any syntax errors, just typing as I think):
#ManagedBean
public class Bean {
private String dataPoint1 = "";
private String dataPoint2 = "";
public boolean validate() {
if(dao.fieldExists(this.dataPoint1) && dao.fieldExists(this.dataPoint2)) { //check the database
performFunctionality();
return true;
}
else {
return false; //and show error div on screen
}
}
public void performFunctionality() {
//do whatever
}
//getters and setters
}
Any advice would be very welcome!
Thanks!
You're not utilizing JSF builtin validation facilities. Make use of it.
Here's how it can look like:
<h:form id="frmSearch">
<h:inputText id="dataPoint1" value="#{bean.dataPoint1}" validator="#{bean.validateDataPoint}" />
<h:message for="dataPoint1" />
<h:inputText id="dataPoint2" value="#{bean.dataPoint2}" validator="#{bean.validateDataPoint}" />
<h:message for="dataPoint2" />
<h:commandButton action="#{bean.performFunctionality}" value="Search">
<f:ajax execute="#form" render="#form" />
</h:commandButton>
</h:form>
with
public void validateDataPoint(FacesContext context, UIComponent component, Object convertedValue) {
if (!dao.fieldExists((String) convertedValue)) {
throw new ValidatorException(new FacesMessage("Value not found in database."));
}
}
That performFunctionality() must be executed by the command button's action method.
When validation fails (i.e. ValidatorException is been thrown), then the message will be displayed in the <h:message> associated with the input component and the action method won't be invoked. The validator attribute can alternatively also point to a fullworthy class which implements javax.faces.validator.Validator. The <f:ajax> is been added to make it an ajax submit.
See also:
How to perform validation in JSF, how to create a custom validator in JSF
Wherever you've learnt JSF, make sure that you've also read the chapters about conversion and validation. Don't think too much the PHP/ASP/JSP/jQuery way. JSF is a full fledged component based MVC framework.

JSF - Pass a parameter on ajax call - What's wrong on this code?

I need to pass a parameter to a bean when i do an ajax call.
My bean is this :
#ManagedBean
#RequestScoped
public class Selector {
#ManagedProperty(value="#{param.page}")
private String page;
#PostConstruct
public void init() {
if(page==null || page.trim().isEmpty()) {
this.page="homepage";
}
System.out.println(this.page);
}
public String getPage() { return page; }
public void setPage(String page) { this.page=page; }
}
And, when i do the ajax call, i need (due to the fact that i want to render a different context) the page parameter. So i've done this :
// in this moment selector.page = articles
<h:inputHidden value="#{selector.page}" id="page" />
<h:commandLink>
<f:setPropertyActionListener target="#{articlesSelector.order}" value="1" />
<f:ajax event="click" render=":articlesContent"/>
<h:graphicImage value="img/arrow_up.png" alt="Arrow Up"/>
</h:commandLink>
But, on the Apply request phase, the page still "homepage". It should get the page-parameter from the request, apply it to the Component tree and render the "articles" context. Why doesnt happens?
Cheers
Because the value of <h:inputHidden> is only set during update model values phase. This is indeed an unintuitive behaviour which existed for long in JSF. I've ever reported an issue about this, but this was closed as "by design".
There are several ways to fix this, among others the view scope. In your particular case, you can use <f:param> instead of <h:inputHidden>:
<h:commandLink>
<f:param name="page" value="#{selector.page}" />
<f:setPropertyActionListener target="#{articlesSelector.order}" value="1" />
<f:ajax event="click" render=":articlesContent"/>
<h:graphicImage value="img/arrow_up.png" alt="Arrow Up"/>
</h:commandLink>
It will then be available as request parameter #{param.page} and in your request scoped bean thus be set as #ManagedProperty.

JSF2 - what scope for f:ajax elements?

I have this form:
<h:form>
<h:outputText value="Tag:" />
<h:inputText value="#{entryRecorder.tag}">
<f:ajax render="category" />
</h:inputText>
<h:outputText value="Category:" />
<h:inputText value="#{entryRecorder.category}" id="category" />
</h:form>
What I'm trying to achieve: When you type in the "tag" field, the entryRecorder.tag field is updated with what was typed. By some logic upon this action the bean also updates its category field. This change should be reflected in the form.
Questions:
What scope shall I use for EntryRecorder? Request may not be satisfactory for multiple AJAX requests, while session will not work with multiple browser windows per one session.
How can I register my updateCategory() action in EntryRecorder so that it is triggered when the bean is updated?
Answering point 2:
<h:inputText styleClass="id_tag" value="#{entryRecorder.tag}"
valueChangeListener="#{entryRecorder.tagUpdated}">
<f:ajax render="category" event="blur" />
</h:inputText>
Bean:
#ManagedBean
#ViewScoped
public class EntryRecorder {
private String tag;
private String category;
#EJB
private ExpenseService expenseService;
public void tagUpdated(ValueChangeEvent e) {
String value = (String) e.getNewValue();
setCategory(expenseService.getCategory(value));
}
}
Number 1, anybody?
To point 1, I'll use Request since there is no need to use View and Session is, as you well pointed, completely unnecessary.
For point 2, since you are using <f:ajax/> I suggest making full use of it. Here is my proposal:
xhtml:
<h:form>
<h:outputText value="Tag:" />
<h:inputText value="#{entryRecorder.tag}">
<f:ajax render="category" event="valueChange"/>
</h:inputText>
<h:outputText value="Category:" />
<h:inputText value="#{entryRecorder.category}" id="category" />
</h:form>
Note the use of valueChange event instead of blur (not that blur doesn't work but I find valueChange more 'proper' for a value holder component).
bean:
#ManagedBean
#RequestScoped
public class EntryRecorder {
private String tag;
private String category;
public String getCategory() {
return category;
}
public String getTag() {
return tag;
}
public void setCategory(String category) {
this.category = category;
}
public void setTag(String tag) {
this.tag = tag;
tagUpdated();
}
private void tagUpdated() {
category = tag;
}
}
Unless you really want the tagUpdated method executed only when tag is updated through the view, my proposal looks more clear. You don't have to deal with the events (nor casting) and the tagUpdated method can be private hiding it's functionality from possible misuses.

Resources