Here a snippet of my JSF:
<p:tabView id="tabView" var="tab" value="#{data.tabs}" widgetVar="tabViewWidget"
activeIndex="#{data.newActiveTabIndex}">
<p:ajax event="tabClose" listener="#{logic.closeTab}" />
<p:tab title="#{tab.content.title != null ? tab.content.title : '<new>'}"
closable="#{tab.isClosable and data.tabs.size() > 2}">
<h:outputText value="#{tab.id} Test" />
<p:focus rendered="#{data.componentIdToFocus != null}" for="#{data.componentIdToFocus}" />
<p:inputText id="test" value="#{tab.content.title}">
<p:ajax event="keyup" listener="#{logic.setFocusingComponent}" update=":form:tabView" />
</p:inputText>
</p:tab>
</p:tabView>
The intent is that there is a textfield within each tab that updates the title of the tab while writing.
The given snippet works except that p:focus places the cursor at the beginning of the text that is already written. I want the cursor to be placed at the end of the text already written. So that a user can type and while he/she is typing the title adapts automatically.
I hope my case is clear.
Does anybody have a solution for that?
Best regards,
Florian
You can use the onfocus="this.value=this.value" trick to "deselect" the value so that the cursor automagically ends up in the end of the value. This should work as good for the <p:inputText> as it basically generates just a <input type="text"> element.
<p:inputText ... onfocus="this.value=this.value" />
See also:
Use JavaScript to place cursor at end of text in text input element
Unrelated to the concrete problem, I wouldn't use ajax and such on keyup event and an update of the whole tabview. This seems to be quite expensive. I'd rather do a simple HTML DOM traversion and manipulation here by JS/jQuery.
E.g.
<p:inputText ... onkeyup="updateTitle(this)" />
with
function updateTitle(inputInTab) {
var panelId = $(inputInTab).closest(".ui-tabs-panel").attr("id");
$("a[href='#" + panelId + "']").text(inputInTab.value);
}
Related
I know this question exists somewhere else in SO but either the solutions are old (and JSF seems to have improved a lot) or I cannot make the solution work.
As simple as it sounds, I would like to replace the text of an input element based on the value of a combo box. I would like to use Ajax, and would like this to work even if there is only one element in the combo (it doesn't matter if by default the selection of the combo is empty).
<h:selectOneMenu id="fnamecombo" valueChangeListener="#{namesController.setForename(fnamecombo)}">
<c:forEach items="#{namesController.myForenames}" var="myforename">
<f:selectItem itemValue="#{myforename}" itemLabel="#{myforename}" />
</c:forEach>
<f:ajax render="fnameinput" />
</h:selectOneMenu>
<h:inputText value="#{namesController.forename}" id="fnameinput" />
This doesn't work. So first of all, I have no idea how to call the setForename method. If I use valueChangeListener="#{namesController.setForename('xxxxx')}" it works, but only the 1st time and iff there are more than one element in the combo, since otherwise the event does not seem to be fired.
What is the easy fix?
EDIT
Ok, so I have made progress. It was easier than I expected:
<h:selectOneMenu id="fnamecombo" value="#{namesController.forename}">
<c:forEach items="#{namesController.myForenames}" var="myforename">
<f:selectItem itemValue="#{myforename}" itemLabel="#{myforename}" />
</c:forEach>
<f:ajax render="fnameinput" />
</h:selectOneMenu>
<h:inputText value="#{namesController.forename}" id="fnameinput" />
This seems to work on a selectItem that I create by hand, but not on the one that is printing with the foreach loop. So this is the rendered code, where I obtained 'john' from the loop and I manually created 'example':
<select id="myForm:fnamecombo" name="myForm:fnamecombo" size="1" onchange="mojarra.ab(this,event,'valueChange',0,'myForm:fnameinput')">
<option value="example">example</option>
<option value="john">john</option>
</select>
It works with 'example' but not with 'john'.
Finally I got the answer.
<h:selectOneMenu id="fnamecombo" value="#{namesController.forename}">
<f:selectItems value="#{namesController.myForenames}" />
<f:ajax render="fnameinput" />
</h:selectOneMenu>
<h:inputText value="#{namesController.forename}" id="fnameinput" />
No need for forEach as mentioned by Alexandre Lavoie.
This answer by Luiggi Mendoza gave me the hint to find it out. The reason my input was not updated by the values in the f:selectItems and it was in the ones that I introduced manually is the scope of the managed bean. I realised that the input was actually being updated in any case, but when coming from the f:selectItems the input was updated with null. Why? Because the scope of namesController was #RequestScoped and not #ViewScoped. Changing this solves the problem.
I started using primafaces and I came up with the following scenario. The user rates and element and if the rating is valid then a span block appears or it hides depending the case. I am based on the example here: (http://www.primefaces.org/showcase/ui/input/rating.xhtml ) with the ajax approach. Note that a rate is valid if the user clicks on any star. So here's what I've done so far:
<h:form>
<p:panelGrid>
<p:row>
<p:column>
<p:rating value="#{searchBean.dateWeight}">
<p:ajax event="rate" listener="#{searchBean.addDatetoWeights}"
update="dates" render="dates" />
<p:ajax event="cancel"
listener="#{searchBean.removeDatefromWeights}"
update="dates" />
</p:rating>
<h:panelGroup id="dates" rendered="#{searchBean.dateRated}">
<h:outputText value="test"></h:outputText>
</h:panelGroup>
</p:column>
</p:row>
</p:panelGrid>
</h:form>
segment of the bean:
boolean dateRated;
int dateWeight;
public void addDatetoWeights(){
dateRated=true;
weights.put("date",dateWeight);
System.out.println(dateRated);
}
public void removeDatefromWeights(){
dateRated=false;
if(weights.containsKey("date"))
weights.remove("date");
}
Let's go back to the basics: HTML and JavaScript. It's important to also know them before diving into JSF. JSF is in the context of this question merely a HTML/JS code generator.
With <p:ajax update="dates"> you're basically telling JavaScript to grab the HTML element by the given ID and then replace its contents with the new contents retrieved from server in ajax response. However, as the <h:panelGroup id="dates"> is in first place never rendered to the HTML output, JavaScript can't find the element by document.getElementById() stuff in order to replace its contents and then just ignores the instruction.
Instead, the <p:ajax update="dates"> must refer a component which is always rendered, so that JavaScript can actually find it. Only its contents can be conditionally rendered.
Here's a rewrite:
<h:panelGroup id="dates">
<h:outputText value="test" rendered="#{searchBean.dateRated}" />
</h:panelGroup>
See also:
Why do I need to nest a component with rendered="#{some}" in another component when I want to ajax-update it?
I have the following JSF 2 code:
<p:selectOneMenu id="dropdown" value="#{data.selection}" required="true" converter="selectOneMenuConverter">
<f:selectItem itemLabel="Select one..." itemValue="" noSelectionOption="true" />
<f:selectItems value="#{data.entries}" var="entry" itemLabel="#{entry.name}" itemValue="#{entry}" />
<p:ajax update="display" event="change" />
</p:selectOneMenu>
<h:panelGroup id="display">
<h:outputText value="#{data.selection}" />
</h:panelGroup>
Everything works as expected when I choose a value from the dropdown.
When the user "deselects" an entry by choosing "Select One", JSF complains that this is not possible because the selectonemenu is required.
The problem comes from there that the p:ajax makes a partial submit that triggers validation. Immediate=true does also not work because in case the immediate happens on an input field (like selectonemenu is) a validation is performed.
The validation shall only happen when the user presses the "go on" button on the bottom of the page (not shown in code)
Further the given converter converts the Strings to Objects and for the default value it returns null (that's also the expected value within the domain for "no selection").
So my question is what I must do to fulfill my case.
For my this is a standard case and I cannot imagine that there is no solution for this.
Any ideas?
Best regards,
Florian
The validation shall only happen when the user presses the "go on" button on the bottom of the page (not shown in code)
Then just tell the dropdown's required attribute to do exactly that instead of hardcoding a true.
<h:form id="form">
<p:selectOneMenu ... required="#{not empty param['form:go']}">
...
</p:selectOneMenu>
...
<p:commandButton id="go" ... />
</h:form>
The #{not empty param['form:go']} will only evaluate true when the form submit has actually been taken place by the submit button which has the client ID form:go in the particular example. If you don't like hardcoding client IDs either, then reference it as follows:
<h:form>
<p:selectOneMenu ... required="#{not empty param[go.clientId]}">
...
</p:selectOneMenu>
...
<p:commandButton binding="#{go}" ... />
</h:form>
I have a page containing a PrimeFaces (2.2.1) Editor component, a Refresh button and a selectOneMenu, whose selection affects the contents of the Editor, as follows:
<p:editor id="uploadedText" value="#{facilityDataUploadBean.uploadedText}"
width="600" height="180" disabled="true" controls="" />
<h:commandButton value="Refresh" immediate="true" />
<h:selectOneMenu id="skipLines" styleClass="dropdown"
value="#{facilityDataUploadBean.skipLines}">
<f:selectItems value="#{facilityDataUploadBean.skipLinesList}" />
<f:ajax listener="#{facilityDataUploadBean.importParameterChanged}" />
</h:selectOneMenu>
facilityDataUploadBean.importParameterChanged updates facilityDataUploadBean.uploadedText. After changing the selectOneMenu value, the operator presses the Refresh button to refresh the page, including the contents of the p:editor. (I cannot simply refresh the p:editor using AJAX, because it doesn't re-render correctly, at least in PF 2.2.1.)
It seems like I ought to be able to accomplish the page refresh automatically when the selectOneMenu value is changed, but I've been unable to come up with a combination of attributes and events that will do that. I've tried various combinations of onchange="submit();", immediate="true" and valueChangeListener on the selectOneMenu, as well as execute="#all/#form", render="#all/#form" on the f:ajax event, all to no avail. My current workaround is to display a message asking the user to press the Refresh button whenever they change the selectOneMenu selection - pretty hokey.
Invoke window.location.replace(window.location.href) rather than submit() in the onchange event, as in:
<h:selectOneMenu id="skipLines" ... onchange="window.location.replace(window.location.href);">
<f:selectItems ... />
<f:ajax ... />
</h:selectOneMenu>
please try the onchange="window.location.reload();" approach like:
<h:selectOneMenu id="skipLines" ... onchange="window.location.reload();">
<f:selectItems ... />
<f:ajax ... />
</h:selectOneMenu>
This works just fine in my environment (GF 3.1.1, PF 3.2) but please be aware that there is the possibility of interrupting some ajax functinality.
Hope this helpes, have Fun!
I am trying to filter a datatable using filter field in the column and get the filtered list (which populates datatable) and update another component (Toplam TL Teminati and Toplam Dolar Teminati) according to the filtered list's values in my page.
Is there anyway to do this in Primefaces 2.2.1 and JSF 2? If not can you rec commend a workaround for this case?
Thanks in advance.
To give you an example of how I achieved custom filter logic in my Primefaces 2.2.1 dataTable, I am giving you a scaled version of my code.
<p:dataTable value="#{listBeans.beans}" var="bean" dynamic="true" paginator="true" rows="20" paginatorPosition="bottom"
emptyMessage="No Beans" loadingMessage="Loading. . ." selectionMode="single" selection="#{listBeans.selectedBean}"
id="beanList" widgetVar="beanTable">
<f:facet name="header">
<h:panelGrid columns="4">
<h:outputText value="Bean List" />
<p:outputPanel>
<h:outputText value="Year Filter: " />
<h:selectOneMenu value="#{listBeans.yearFilter}"
onchange="yearFilterBtn.jq.click(); refreshFilters();">
<f:selectItems value="#{listBeans.years}" />
</h:selectOneMenu>
<p:commandButton id="yearFilterBtn" widgetVar="yearFilterBtn" action="#{listBeans.filterYears}"
update="listBeansForm:beanList" style="display:none;" />
</p:outputPanel>
<p:outputPanel>
<h:outputText value="Filter By Beanchild: " />
<p:inputText value="#{listBeans.beanchildFilter}" style="width: 150px; margin-right: 4px;" />
<!-- refreshFilters forces the visitor filter to refresh the selection if column filters are selected. -->
<p:commandButton oncomplete="refreshFilters();" value="Filter"
action="#{listBeans.filterBeanchildren}" update="listBeansForm:beanList" />
</p:outputPanel>
<p:commandButton value="Export to XLS" ajax="false">
<p:dataExporter target="beanList" type="xls" fileName="BeanReport"
excludeColumns="0,5,6" postProcessor="#{listBeans.postProcessExcelReport}" />
</p:commandButton>
</h:panelGrid>
</f:facet>
<p:column style="width:16px">
<p:rowToggler />
</p:column>
<p:column filterStyleClass="filtertag" filterBy="#{bean.beanDateDisplay}" filterMatchMode="startsWith">
....
</p:dataTable>
Without really going into too much detail about the managed bean code, the actions of the command button are essentially passing filter arguments to my BO layer that requery the database for the new list of beans. The explicit update of the dataTable component is needed to refresh the data.
You will notice that on the explicit Beanchild Filter button that is not hidden, I have an oncomplete attribute that references a javascript function called refreshFilters(). I can't remember exactly the problem I had, but I think it is a bug in the 2.2.1 version of Primefaces when a column filter value exists and an asynchronous update occurs within the dataTable itself. Here is the javascript function:
function refreshFilters() {
var filters = jQuery('.filtertag');
var uppedOnce = false;
filters.each(function(idx) {
var curEl = jQuery(this);
if (curEl.val() != '') {
curEl.keyup();
uppedOnce = true;
}
});
if (!uppedOnce) {
jQuery(filters[0]).keyup();
}
}
You can see here that I am locating every DOM element that has the class filtertag, which would be the column filters. I am saying that if a value exists in that field after the server action is complete, then I am manually triggering a keyup event as this will "refilter" the column with the previous value from before.
I am not sure if it is necessary in later versions of Primefaces, I am not even sure it is necessary now, so I suggest trying to do this without the Javascript workaround and if you run into problems cooridnating the two then you can consider using the Javascript.