HTML object as JSF UIComponent - jsf

I have a TabView whose tabs i generated with :
<p:tabView>
<c:forEach var="app" items="#{data.apps}">
<p:tab title="#{app.name}" closable="true" id="app_#{app.id}">
<object data="#{app.startUri}" height="800" width="1150" />
</p:tab>
</c:forEach>
</p:tabView>
However, I had a problem with adding new tabs. I had to update the TabView which caused the tabs and their contents to reload which was a problem for my situation.
I then switched to create my TabView with a TabViewHelper bean.
But then there was a problem with adding the object tag as a child to the tab:
public TabView initializeTabView(List<App> apps) {
tv = new TabView();
Tab tab;
for (App app : apps) {
tab = new Tab();
tab.setTitle(app.getName());
HTMLObjectElementImpl content = new HTMLObjectElementImpl(owner, "test-object");
tab.getChildren().add(content);
tv.getChildren().add(tab);
}
return tv;
}
I get the following error:
The method add(UIComponent) in the type List is not applicable for the arguments (HTMLObjectElementImpl)
I can only add an UIComponent.
I'm not sure if HTMLObjectElementImpl is right for <object> but I did not find something better.
Is there an UIComponent for the HTML <object>-tag or is there another class available for HTML <object>?
Did anyone else have this problem and found a solution?

<object> is not a JSF component. It's basically considered as plain text.
Simplest way would be to create a HtmlOutputText with escape set to false.
HtmlOutputText html = new HtmlOutputText();
html.setEscape(false);
html.setValue("<object>...</object>");
Beware of XSS attack holes in case you pass user-controlled variables to that.
In future you try to create a JSF component programmatically, use a subclass of UIComponent and not some random JAXP implementation specific class. Or, better, fix that update problem so you can keep using XHTML code to create the view instead of verbose Java code.

Related

How to set a dynamic value for ui:param [duplicate]

I am new to JSF and I am struggling with dynamicaly rendering included pages. My code looks like this:
MenuBean
#ViewScoped
public class MenuBean implements Serializable {
private MenuItem[] menuItems = new MenuItem[] {
new MenuItem("page_1", "/page_1.xhtml"),
new MenuItem("page_2", "/page_2.xhtml"),
};
private String selectedItemLabel;
//...
}
MenuItem
public class MenuItem implements Serializable {
private String label;
private String page;
//...
}
index.xhtml
<ui:repeat var="menuItem" value="#{menuBean.menuItems}">
<h:panelGroup rendered="#{menuBean.selectedItemLabel eq menuItem.label}" layout="block">
<h:outputText value="#{menuBean.selectedItemLabel}" />
<ui:include src="#{menuItem.page}" />
</h:panelGroup>
</ui:repeat>
The result is 2 buttons rendered. Whenever I click any button the label inside conditionaly rendered panelGroup appears but included page doesn't. If I change 'menuItem1' var from first ui:repeat it works but it is really unpredictable. For example if I hardcode setSelectedItemLabel parameter to 'page_1' then when I click to button_1 page_1 is displayed but even if I click to button_2 page_2 (!?) is displayed...
You're facing a view build time vs view render time problem. This is essentially the same problem which is already answered in detail in JSTL in JSF2 Facelets... makes sense? In that answer, replace "JSTL" with "ui:include". To the point, the <ui:repeat> runs during view render time, while the <ui:include> has already run during view build time before.
You'll understand that the only solution is to replace the <ui:repeat> by another tag which runs during view build time, such as JSTL <c:forEach>.
Note that I don't guarantee that it will solve the concrete functional requirement which you've in mind. Using JSTL may have undesirable "side effects" (which are however explainable, understandable and workaroundable).
See also:
How to ajax-refresh dynamic include content by navigation menu? (JSF SPA)

Dynamic <ui:include src> depending on <ui:repeat var> doesn't include anything

I am new to JSF and I am struggling with dynamicaly rendering included pages. My code looks like this:
MenuBean
#ViewScoped
public class MenuBean implements Serializable {
private MenuItem[] menuItems = new MenuItem[] {
new MenuItem("page_1", "/page_1.xhtml"),
new MenuItem("page_2", "/page_2.xhtml"),
};
private String selectedItemLabel;
//...
}
MenuItem
public class MenuItem implements Serializable {
private String label;
private String page;
//...
}
index.xhtml
<ui:repeat var="menuItem" value="#{menuBean.menuItems}">
<h:panelGroup rendered="#{menuBean.selectedItemLabel eq menuItem.label}" layout="block">
<h:outputText value="#{menuBean.selectedItemLabel}" />
<ui:include src="#{menuItem.page}" />
</h:panelGroup>
</ui:repeat>
The result is 2 buttons rendered. Whenever I click any button the label inside conditionaly rendered panelGroup appears but included page doesn't. If I change 'menuItem1' var from first ui:repeat it works but it is really unpredictable. For example if I hardcode setSelectedItemLabel parameter to 'page_1' then when I click to button_1 page_1 is displayed but even if I click to button_2 page_2 (!?) is displayed...
You're facing a view build time vs view render time problem. This is essentially the same problem which is already answered in detail in JSTL in JSF2 Facelets... makes sense? In that answer, replace "JSTL" with "ui:include". To the point, the <ui:repeat> runs during view render time, while the <ui:include> has already run during view build time before.
You'll understand that the only solution is to replace the <ui:repeat> by another tag which runs during view build time, such as JSTL <c:forEach>.
Note that I don't guarantee that it will solve the concrete functional requirement which you've in mind. Using JSTL may have undesirable "side effects" (which are however explainable, understandable and workaroundable).
See also:
How to ajax-refresh dynamic include content by navigation menu? (JSF SPA)

How to matching tabview component in server and client side with jsf?

I have two question as below;
I have a Menu and submenus in left side of my page and a Tabview on center of my page. when click to menuItem, I add tab to tabview with javascript dynamically
but I can't get tabs of tabview from backing bean. I can read only first tabs before I added with javascript.
so I want to match tabview at server side and client side synchronously.
how can i do this ?
and second;
When I closed to tab, I use TabCloseEvent in onTabClose method but event is always null. May be it will be solved with matching tabview with server and client side
i don't know.
codes are as below.
Please advise me.
thanks..
xhtml code :
<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 code :
public void OpenPage(String pageName) {
String s = "Divert to handleTabViewEvent function";
}
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 tw which closed.
But event does not give me tab information. It is always null. And tw has old values";
}
I add tab to tabview with javascript dynamically
This was completely wrong approached in first place.
You need to add the tab using JSF instead of using JS. Right now JSF is completely unaware about the changed client side state and will never know about the new tab. Any workaround would only end up to be uglier and harder to maintain than when just doing it by JSF instead of JS.
See also:
How to add button for adding new tabs near last tab?
What is the need of JSF, when UI can be achieved from CSS, HTML, JavaScript, jQuery?

use multiple form instances jsf 2.0

my jsf appication is designed so that by clicking on a menuitem the corresponding page is displayed in a newly created tab. the pages displayed on tabs have their own form element & backing bean.
normally this works pretty well, but could not find a way how to solve the situation when multiple instances of the same form is used concurrently, eg. more 'add new employee' tabs are opened at the same time.
i try to use a #SessionScoped managed bean with a Map containing instances of the form data (currently only one string for simplicity) like this:
#ManagedBean(name="employeeBean")
#SessionScoped
public class EmployeeBean extends BaseManagedBean implements Serializable{
private Map<String, String> fields = new HashMap<String, String>();
private String formId;
public void newForm(){
this.formId=RandomStringUtils.randomAlphabetic(10);
logger.debug("newForm: formId: " + formId);
this.fields.put(formId, new String());
}
//... etc
}
when i click on a menuitem, a new random formId is generated and new form data holder is added to the fields map.
the jsf page is this:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:fn="http://java.sun.com/jsp/jstl/functions"
xmlns:p="http://primefaces.prime.com.tr/ui">
<div class="dataContainer clearfix">
<h:form id = "#{employeeBean.formId}">
<h:inputText id="empField1" value="#{employeeBean.fields[employeeBean.formId]}" />
<p:commandLink action="#{employeeBean.action}" value="Action" id="actionLink">
</p:commandLink>
</h:form>
</div>
</html>
the last opened tab instance works perfectly but the old ones do not. if the commandLink is pressed on older tabs the right form is submitted and the getFormId method is called once in the restore view phase, but nothing else is called in my EmployeeBean.
if i use fixed formId not the random #{employeebean.formId} then always the first opened tab's data is submitted. (multiple forms with same id on the page).
i suppose something is wrong with my component tree.
i am using Primefaces's TabView component (based on jquery) and i add new tabs to the tab component in a jquery javascript function.
Can anyone tell me what i am doing wrong? or suggest a better way to solve problem? what is the right approach to handle situtations like this?
thanks a lot in advance
Do you need here a session scoped bean? E.g. do you want to reach bean-content from other pages? If not, than maybe you could simply make your EmployeeBean request scoped. Than you don't need a map inside your employeeBean, and you valuebindings could also be more simple...

Creating dynamic controls in jsf managed bean?

I want to dynamically create object of HtmlDivElement in my jsf managed bean and add it to panel but it seems that HtmlDivElement is interface. So, how can i do it?
This is a pretty major confusion. The org.w3c.dom.html.HTMLDivElement is not a JSF component. This represents a W3 DOM element which has an entirely different purpose (JAXP, DOM parsing).
You need a subclass of javax.faces.component.UIComponent (just click your way through the "Direct Known Subclasses" in the aforelinked Javadoc to find them all). To render a HTML <div> element, just use HtmlPanelGroup whose layout attribute is set to block.
HtmlPanelGroup div = new HtmlPanelGroup();
div.setLayout("block");
someParentComponent.getChildren().add(div);
which does effectively the same as the following in "static" JSF:
<h:panelGroup layout="block" />

Resources