Anchor/JumpTo in JSF - jsf

I use JSF + Primefaces 3.2.1.
There is an p:datatable on the page, in each row I have button "Edit". When I click that button, in the footer of the page renders a form for editing that row. Then I need to scroll down there to change values..
But I need the browser to scroll there automatically after clicking on "Edit" button like Anchors in basic HTML work.
I found this decision:
FacesContext.getCurrentInstance().getExternalContext().redirect("pProvidersPriceAppointment.xhtml#anchor1");
It works, but with that my update="#form" not working.. So the form in the bottom not renders. It renders after refreshing page.
How can I do it with p:commandButton or h:commandButton ?)
My button:
<p:commandButton id="providerEdit" actionListener="#{providersPriceAppointment.setEditProvider(provider.id)}" icon="iconEdit" update="#form"/>
Bean method:
public void setEditProvider(int id) throws IOException {
for (int i = 0; i < providersList.size(); i++) {
ProvidersExt p = providersList.get(i);
if (p.getId() == id) {
providerForEdit = p;
break;
}
}
enableEdit = true;
FacesContext.getCurrentInstance().getExternalContext().redirect("pProvidersPriceAppointment.xhtml#anchor1");
}
Form in the footer:
<a name="anchor1"/>
<p:fieldset id="editFieldset" legend="blablabla" rendered="#{providersPriceAppointment.enableEdit}"/>
...
</p:fieldset>

There isn't something like this implemented in JSF or Primefaces yet. But since you have the jQuery Framework running in your application (Primefaces), you could use the jQuery Animate features.
To get a Hint on how to realize something like this, you could check out this answer:
jQuery scroll to Element
For your application that would be somehow like that:
Add this to your <head> element:
function scrollToAnchor() {
jQuery('html, body').animate({
scrollTop: jQuery("#editFieldset").offset().top
}, 2000);
}
And this would be the Button Part:
<p:commandButton id="providerEdit"
actionListener="# {providersPriceAppointment.setEditProvider(provider.id)}"
icon="iconEdit" onComplete="scrollToAnchor();" update="#form"/>

Use PrimeFaces RequestContext with scrollTo to target a component id:
https://www.primefaces.org/showcase/ui/misc/requestContext.xhtml
public void save() {
RequestContext context = RequestContext.getCurrentInstance();
...
//scroll to panel
context.scrollTo("form:panel");

Simple decision that I found on PrimeFaces ShowCase:
<p:fieldset id="edit" legend="Here you can edit.." rendered="#{providersPriceAppointment.enableEdit}">
<p:focus context="panel"/>
</p:fieldset>
When this fieldset is rendered, browser simply jump to this place)
https://www.primefaces.org/showcase/ui/misc/focus.xhtml
Hope, somebody will find this helpful (",)

Related

Primefaces Dialog framework open dialog from <p:poll>

Salam,
I'm trying to show a notification in a dialog dynamically from a poll component but it doesn't seem to work !!
<p:poll interval="15" listener="#{notificationBean.showNotification}" />
the action works well when i use it with a commandButton.
<p:commandButton value="View" icon="ui-icon-extlink" actionListener="#{notificationBean.showNotification}" />
This is my actionListener's code:
public void showNotification() {
System.out.println("showNotification");
Map<String,Object> options = new HashMap<String, Object>();
options.put("resizable", false);
RequestContext.getCurrentInstance()
.openDialog("notifications/notify", options, null);
}
I'm working with PF 6.0
Can't figure out what happens :(
Try to add following to your p:poll oncomplete="PF('DIALOG_WIDGETVAR').show()"/> or oncomplete="PF('DIALOG_WIDGETVAR').loadContents()"/>
Maybe you also have to add update within <p:poll> so content of dialog is updated.

accessing PrimeFaces command button from bean to add action listener

I have the following command button in the view with ID "save":
<p:panel style="border:none;text-align:left;margin:0;">
<p:commandButton value="Save Document" id="save" icon="fa fa-save"
disabled="#{dIGRCController.digrc.qconce == '020'}">
<f:param name="validate" value="true" />
</p:commandButton>
<p:commandButton value="Clear" icon="fa fa-undo"></p:commandButton>
</p:panel>
I am trying to dynamically assign a different actionListener. If the user wants to INSERT some new record, I want it to call the insert method. If the user wants to update an existing record, it should call the update method.
Right now I am trying to do this:
#PostConstruct
public void init() {
// setting the action listener of the Save Document button
UIViewRoot viewRoot = FacesContext.getCurrentInstance().getViewRoot();
// UIComponent button = viewRoot.findComponent("save");
CommandButton button = (CommandButton) viewRoot.findComponent("save");
FacesContext context = FacesContext.getCurrentInstance();
MethodExpression methodExpression = context
.getApplication()
.getExpressionFactory()
.createMethodExpression(context.getELContext(),
"#{dIGRCController.updateDocument}", null,
new Class[] { DIGRCController.class });
button.addActionListener(new MethodExpressionActionListener(
methodExpression));
}
I am getting a null pointer exception on the line:
button.addActionListener(new MethodExpressionActionListener(
methodExpression));
What am I doing wrong? Is there another way to accomplish what I am trying to do? I am using JSF 2.2, PrimeFaces 5.3 and OmniFaces 1.11.
The findComponent() takes a client ID as argument not a component ID. The client ID is exactly the value of the generated HTML id attribute associated with the component in question. In case of a command button, usually the component ID of the parent <h:form> is prepended, separated by the naming container separator character which defaults to :.
Given this,
<h:form id="form">
<p:commandButton id="save" ... />
</h:form>
the client ID would be form:save.
CommandButton button = (CommandButton) viewRoot.findComponent("form:save");
See also this related question as to identifying and using client ID: How to find out client ID of component for ajax update/render? Cannot find component with expression "foo" referenced from "bar"
Unrelated to the concrete problem, manipulating the component tree in Java side is a poor practice. You'd better keep using XHTML+XML for this which is so much more self-documenting as to declaring/defining tree structures. You can use JSTL tags to dynamically build the view (note: this is different from dynamically rendering the view using rendered attribute!).
E.g.
<p:commandButton ... action="#{bean.save}">
<c:if test="#{bean.existing}">
<f:actionListener binding="#{bean.needsUpdate()}" />
</c:if>
</p:commandButton>
See also JSTL in JSF2 Facelets... makes sense?
Even more, you could just pass #{bean.existing} as method argument.
<p:commandButton ... action="#{bean.save(bean.existing)}" />
Both approaches are in turn admittedly kind of weird if #{bean.existing} refers the same bean as #{bean.save}. You could just check for that inside #{bean.save} itself.
public void save() {
if (existing) {
// UPDATE
} else {
// INSERT
}
}
Going further on that, this is IMO not the responsibility of frontend layer, but of the service layer. You pass the whole entity to the service layer which in turn checks based on PK if it's existing or not.
if (entity.getId() == null) {
// INSERT
} else {
// UPDATE
}

Include dialog from another file via backing bean

I have a Primefaces project in which I am trying to replicate the behavior of a desktop application. Because of the nature of the desktop application, there are quite a few popup dialogs, which cause the processing of the page to become very slow (initial page load: 10-20 seconds, AJAX requests: 6-10 seconds).
I have separate files for all the dialogs already, and I want to use the backing bean to pop them up as dialogs without having to use <ui:include> in my main files. Is there a way to do this?
e.g.:
<p:commandButton id="showSearchDialog"
action="#{managedBean.showSearchDialog()}"/>
<p:dialog widgetVar="searchDialog">
</p:dialog>
public class ManagedBean {
public void showSearchDialog() {
//Some sort of function that knows to process the contents of searchDialog.xhtml
// and insert it into the relevant <p:dialog>
RequestContext.getCurrentInstance().execute("PF('searchDialog').show()");
}
}
If your goal is to reduce the size of the page, I'd approach it with conditional rendering of the dialog itself as determined by a backing bean property which would be set by the command action:
<p:commandButton id="showSearchDialog"
action="#{managedBean.showSearchDialog()}"
update="dialogs"
oncomplete="PF('searchDialog').show()" />
<h:panelGroup id="dialogs" layout="block">
<p:dialog widgetVar="searchDialog" rendered="#{managedBean.currentDialog eq 'search'}">
<ui:include src="searchDialog.xhtml" />
</p:dialog>
</h:panelGroup>
public class ManagedBean {
private String currentDialog;
public String getCurrentDialog() { return currentDialog; }
public void showSearchDialog() { currentDialog = "search"; }
}
Then you could conditionally render all of your dialogs within the 'dialogs' block and use ajax to refresh the rendered content dynamically.
Another option to consider is using the PrimeFaces Dialog Framework, which allows you to dynamically render an external page at runtime.

Get tabs of Tabview in Javascript

I have a tabview on page and add tabs with javascript dynamically. At the same time add the opened tab names to a list(lstOpenedPages). But close a tab, I can't get name of this tab which is closed for delete from the list. Now I want to read remain tabs of tabview because I can find which tab is closed from the list (lstOpenedPages).
How to I get remain tabs of tabview in Javascript?
xhtml code
<p:tabView id="tw" widgetVar="tw">
<p:ajax event="tabClose" listener="#{MenuBean.onTabClose}"/>
</p:tabView>
<p:menuitem value="#{itemMenu.menuAck}"
action="#{MenuBean.OpenPage(itemMenu.pageName)}"
ajax="true"
oncomplete="handleTabViewEvent(args);"
/>
<script type="text/javascript">
function handleTabViewEvent(args) {
alert('Add tab here..');
}
</script>
bean
public void OpenPage(String pageName) {
lstOpenedPages.add(pageName);
}
public void onTabClose(TabCloseEvent event) {
FacesContext context = FacesContext.getCurrentInstance();
TabView tw = (TabView)context.getViewRoot().findComponent("centerForm:tw");
String s = "I must delete tab here from lstOpenedPages which closed. But event does not give me tab information. It is always null. So I must be delete from javascript";
}

primefaces tabView activeIndex issue

I have Primefaces TabView with two Tab like:
<p:tabView dynamic="true" cache="false"
onTabShow="scrollBottom(#{stanzaBean.activeIndex})"
tabChangeListener="#{messaggioBean.onTabChange}"
activeIndex="#{stanzaBean.activeIndex}" >
it works fine, except that when I change the Tab the activeIndex isn't updated on the Server and it returns always the default value.
I'm using primefaces 2.2.1.
Thank you.
Going by the PrimeFaces ShowCase example, if you give each tab an id:
<p:tabView tabChangeListener="#{indexBean.onTabChange}" >
<p:tab title="tab 0" id="tab0"></p:tab>
<p:tab title="tab 1" id="tab1" ></p:tab>
<p:tab title="tab 2" id="tab2"></p:tab>
</p:tabView>
you can get that tab id in the tabChangeListener.
public void onTabChange(TabChangeEvent event) {
System.out.println("tab id = " + event.getTab().getId());
}
Then you'll know which tab was selected.
Edit:
There is an open PrimeFaces issue 1640 TabView: Wrong activeIndex in TabChangeListener, always 0 on the problem you are having.
Edit 2:
With PrimeFaces 5.0 and up the tabChangeListener is no longer available on the tabView element but should be used via an explicit ajax tag with a tabChange event.
<p:tabView id="analysisSections" value="#{analysisBean.analysis.sections}" var="section" activeIndex="#{analysisBean.activeIndex}">
<p:ajax event="tabChange" listener="#{analysisBean.onTabChange}"/>
Also you can directly get index of tab:
public void onTabChange(TabChangeEvent event) {
activeIndex = ((TabView) event.getSource()).getIndex();
}
with all these changes, activeIndex works properly.
this worked for me:
public void onTabChange(TabChangeEvent event) {
Tab activeTab = event.getTab();
tabPanelIndex = ((TabView)event.getSource()).getChildren().indexOf(activeTab);
}
Although the question was related to PrimeFaces 2.2.1, I like to mention that in modern PrimeFaces versions (tested with version 6.2) there is no need to trigger a separate event when attribute dynamic is set to true and cache is set to false. By using this attribute combination the active index is automatically updated on the server when another tab is selected.
Facelet:
<p:tabView activeIndex="#{stanzaBean.activeIndex}"
cache="false"
dynamic="true">
Bean:
#Named
#ViewScoped
public class StanzaBean implements Serializable {
private int activeIndex;
public int getActiveIndex() {
return activeIndex;
}
/**
* Automatically called whenever a tab changes and dynamic="true"
* and cache="false".
*/
public void setActiveIndex(int activeIndex) {
this.activeIndex = activeIndex;
// do other stuff when tab changes
}
}

Resources