I have tryed to build a Java Class in JSf witch adds a view with a Pager to an XPage
Im Using a UiDataview in this simple example but my problem is that the Pager witch is added to the result is never displayed in my Xpage. anyone an idea what i have to do?
public class MainLibcontrol extends UIComponentBase implements FacesComponent {
private static final String RENDERER_TYPE = "de.my.MainLibcontrol";
private static final String COMPONENT_FAMILY = "de.my";
public MainLibcontrol() {
setRendererType(RENDERER_TYPE);
}
#Override
public String getFamily() {
return COMPONENT_FAMILY;
}
#SuppressWarnings("unchecked")
public void initBeforeContents(FacesContext arg0) throws FacesException {
try {
UIDataView viewtable = new UIDataView();
viewtable.setColumnTitles(true);
CategoryColumn categoryColumn = new CategoryColumn();
categoryColumn.setComponent(viewtable);
categoryColumn.setColumnName("form");
categoryColumn.setColumnTitle("form");
categoryColumn.setContentType("text");
viewtable.addCategoryColumn(categoryColumn);
DominoViewData data = new DominoViewData();
data.setComponent(viewtable);
data.setViewName("142342");
data.setVar("view2");
viewtable.setData(data);
viewtable.setId("dataView1");
viewtable.setRows(3);
SummaryColumn summaryColumn = new SummaryColumn();
summaryColumn.setComponent(viewtable);
summaryColumn.setColumnName("5");
summaryColumn.setColumnTitle("5");
viewtable.setSummaryColumn(summaryColumn);
XspPager pager = new XspPager();
pager.setPartialRefresh(true);
pager.setLayout("Previous Group Next");
pager.setId("pager1");
viewtable.getChildren().add(pager);
this.getChildren().add(viewtable);
} catch (Exception e) {
e.printStackTrace();
}
}
public void buildContents(FacesContext arg0, FacesComponentBuilder arg1) throws FacesException {
.....
}
public void initAfterContents(FacesContext arg0) throws FacesException {
....
}
}
I haven't tried this out, but I would imagine you want to add it as a facet of the viewTable not as a child.
so your line should be
viewtable.getFacets().put("headerPager", pager);
Related
I am working on an application where I would like to include dynamic XHTML content from a stream. To handle this I wrote a taghandler extension which dumps the dynamic XHTML content to output component as
UIOutput htmlChild = (UIOutput) ctx.getFacesContext().getApplication().createComponent(UIOutput.COMPONENT_TYPE);
htmlChild.setValue(new String(outputStream.toByteArray(), "utf-8"));
This works fine for XHTML content which has no JSF tags. If I have JSF tags in my dynamic XHTML content like <h:inputText value="#{bean.item}"/>, then they're printed as plain text. I want them to render as input fields. How can I achieve this?
Essentially, you should be using an <ui:include> in combination with a custom ResourceHandler which is able to return the resource in flavor of an URL. So when having an OutputStream, you should really be writing it to a (temp) file so that you can get an URL out of it.
E.g.
<ui:include src="/dynamic.xhtml" />
with
public class DynamicResourceHandler extends ResourceHandlerWrapper {
private ResourceHandler wrapped;
public DynamicResourceHandler(ResourceHandler wrapped) {
this.wrapped = wrapped;
}
#Override
public ViewResource createViewResource(FacesContext context, String resourceName) {
if (resourceName.equals("/dynamic.xhtml")) {
try {
File file = File.createTempFile("dynamic-", ".xhtml");
try (Writer writer = new FileWriter(file)) {
writer
.append("<ui:composition")
.append(" xmlns:ui='http://java.sun.com/jsf/facelets'")
.append(" xmlns:h='http://java.sun.com/jsf/html'")
.append(">")
.append("<p>Hello from a dynamic include!</p>")
.append("<p>The below should render as a real input field:</p>")
.append("<p><h:inputText /></p>")
.append("</ui:composition>");
}
final URL url = file.toURI().toURL();
return new ViewResource(){
#Override
public URL getURL() {
return url;
}
};
}
catch (IOException e) {
throw new FacesException(e);
}
}
return super.createViewResource(context, resourceName);
}
#Override
public ResourceHandler getWrapped() {
return wrapped;
}
}
(warning: basic kickoff example! this creates a new temp file on every request, a reuse/cache system should be invented on your own)
which is registered in faces-config.xml as follows
<application>
<resource-handler>com.example.DynamicResourceHandler</resource-handler>
</application>
Note: all of above is JSF 2.2 targeted. For JSF 2.0/2.1 users stumbling upon this answer, you should use ResourceResolver instead for which an example is available in this answer: Obtaining Facelets templates/files from an external filesystem or database. Important note: ResourceResolver is deprecated in JSF 2.2 in favor of ResourceHandler#createViewResource().
My solution for JSF 2.2 and custom URLStream Handler
public class DatabaseResourceHandlerWrapper extends ResourceHandlerWrapper {
private ResourceHandler wrapped;
#Inject
UserSessionBean userBeean;
public DatabaseResourceHandlerWrapper(ResourceHandler wrapped) {
this.wrapped = wrapped;
}
#Override
public Resource createResource(String resourceName, String libraryName) {
return super.createResource(resourceName, libraryName); //To change body of generated methods, choose Tools | Templates.
}
#Override
public ViewResource createViewResource(FacesContext context, String resourceName) {
if (resourceName.startsWith("/dynamic.xhtml?")) {
try {
String query = resourceName.substring("/dynamic.xhtml?".length());
Map<String, String> params = splitQuery(query);
//do some query to get content
String content = "<ui:composition"
+ " xmlns='http://www.w3.org/1999/xhtml' xmlns:ui='http://java.sun.com/jsf/facelets'"
+ " xmlns:h='http://java.sun.com/jsf/html'> MY CONTENT"
+ "</ui:composition>";
final URL url = new URL(null, "string://helloworld", new MyCustomHandler(content));
return new ViewResource() {
#Override
public URL getURL() {
return url;
}
};
} catch (IOException e) {
throw new FacesException(e);
}
}
return super.createViewResource(context, resourceName);
}
public static Map<String, String> splitQuery(String query) throws UnsupportedEncodingException {
Map<String, String> params = new LinkedHashMap<>();
String[] pairs = query.split("&");
for (String pair : pairs) {
int idx = pair.indexOf("=");
params.put(URLDecoder.decode(pair.substring(0, idx), "UTF-8"), URLDecoder.decode(pair.substring(idx + 1), "UTF-8"));
}
return params;
}
#Override
public ResourceHandler getWrapped() {
return wrapped;
}
static class MyCustomHandler extends URLStreamHandler {
private String content;
public MyCustomHandler(String content) {
this.content = content;
}
#Override
protected URLConnection openConnection(URL u) throws IOException {
return new UserURLConnection(u, content);
}
private static class UserURLConnection extends URLConnection {
private String content;
public UserURLConnection(URL url, String content) {
super(url);
this.content = content;
}
#Override
public void connect() throws IOException {
}
#Override
public InputStream getInputStream() throws IOException {
return new ByteArrayInputStream(content.getBytes("UTF-8"));
}
}
}
}
Here is my code. I am using scene builder. The code is not working.For first time it loads the hello1.html but in thread the hello2.html does not load.
public class TwavlController implements Initializable {
/**
* Initializes the controller class.
*/
#FXML public WebView webPane;
private Service<Void> back_thread;
private WebEngine engine;
#Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
engine = webPane.getEngine();
final String html_file = "hello1.html"; //HTML file to view in web view
URL urlHello = getClass().getResource(html_file);
engine.load(urlHello.toExternalForm());
run();
}
private File last_update,current;
public void run(){
back_thread = new Service<Void>() {
#Override
protected Task<Void> createTask() {
return new Task<Void>() {
#Override
protected Void call() throws Exception {
updateMessage("hello2.html");
return null;
}
};
}
};
engine.userAgentProperty().bind(back_thread.messageProperty());
back_thread.restart();
}
}
I'm not really clear what you're trying to do here, but I think maybe you are looking for
public void run(){
back_thread = new Service<Void>() {
#Override
protected Task<Void> createTask() {
return new Task<Void>() {
#Override
protected Void call() throws Exception {
Platform.runLater(() ->
engine.load(getClass().getResource("hello2.html").toExternalForm()));
return null;
}
};
}
};
back_thread.restart();
}
I'm trying to implement Menu with select box which sets to display or not component. I have this checkbox:
final CheckMenuItem toolbarSubMenuNavigation = new CheckMenuItem("Navigation");
toolbarSubMenuNavigation.setOnAction(new EventHandler<ActionEvent>()
{
#Override
public void handle(ActionEvent e)
{
DataTabs.renderTab = toolbarSubMenuNavigation.isSelected();
// call here the getter setter and send boolean flag
System.out.println("subsystem1 #1 Enabled!");
}
});
And I have this tabpane which I want to render only if I have selected the checkbox:
public static boolean renderTab;
public DataTabs()
{
}
public boolean isRenderTab()
{
return renderTab;
}
public void setRenderTab(boolean renderTab)
{
this.renderTab = renderTab;
}
// below this code
tabPane.setVisible(renderTab);
When I run the code it's not working. I also tested this:
DataTabs tabs = new DataTabs(); // instantiate first
tabs.setRenderTab(toolbarSubMenuNavigation.isSelected());
public static boolean renderTab;
TabPane tabPane = new TabPane();
public DataTabs()
{
}
public boolean isRenderTab()
{
return renderTab;
}
public void setRenderTab(boolean renderTab)
{
tabPane.setVisible(renderTab);
}
But again there is no result when I run the code and I check or uncheck the checkbox.
This is the complete source code:
http://pastebin.com/tkj4Fby1
Maybe I need to add listener or something else which I'm missing?
EDIT
Test 3
I also tested this code:
final CheckMenuItem toolbarSubMenuNavigation = new CheckMenuItem("Navigation");
toolbarSubMenuNavigation.setOnAction(new EventHandler<ActionEvent>()
{
#Override
public void handle(ActionEvent e)
{
DataTabs.toolbarSubMenuNavigation = toolbarSubMenuNavigation;
// call here the getter setter and send boolean flag
System.out.println("subsystem1 #1 Enabled!");
}
});
// class with tabs
public static CheckMenuItem toolbarSubMenuNavigation;
public static CheckMenuItem getToolbarSubMenuNavigation()
{
return toolbarSubMenuNavigation;
}
public static void setToolbarSubMenuNavigation(CheckMenuItem toolbarSubMenuNavigation)
{
DataTabs.toolbarSubMenuNavigation = toolbarSubMenuNavigation;
}
// below
abPane.visibleProperty().bind(toolbarSubMenuNavigation.selectedProperty());
I get NPE when I run the code.
You can easely tell to your tab to be visible when you check the box in one line
yourTab.visibleProperty().bind(yourCheckBox.selectedProperty());
And just with this line your tabpane will be visible only when it's checked
I wrote myself a custom NavigationHandler very similar to following one but just using a stack to save the history:
http://jsfatwork.irian.at/book_de/custom_component.html#!idx:/custom_component.html:fig:backnavigationhandler-code
public class HistoryNavigationHandler extends NavigationHandler
{
private final NavigationHandler navigationHandler;
private final Stack<String> outcomes;
public HistoryNavigationHandler(final NavigationHandler navigationHandler)
{
this.navigationHandler = navigationHandler;
this.outcomes = new Stack<String>();
}
#Override
public void handleNavigation(final FacesContext context, final String fromAction, final String outcome)
{
if (outcome != null)
{
if (outcome.equals("back"))
{
final String lastViewId = this.outcomes.pop();
final ViewHandler viewHandler = context.getApplication().getViewHandler();
final UIViewRoot viewRoot = viewHandler.createView(context, lastViewId);
context.setViewRoot(viewRoot);
context.renderResponse();
return;
}
else
{
this.outcomes.push(context.getViewRoot().getViewId());
}
}
this.navigationHandler.handleNavigation(context, fromAction, outcome);
}
}
Registering this one in the faces-config.xml:
<navigation-handler>
package.HistoryNavigationHandler
</navigation-handler>
Results in following log warning and a message where a previously working link was present:
Warning: jsf.outcome.target.invalid.navigationhandler.type
Something like: this link is disabled because a navigation case could not be matched
What is the problem?
Since JSF 2, the NavigationHandler has been replaced by ConfigurableNavigationHandler. All JSF 2 specific tags/components like <h:link> and so on are relying on it. The NavigationHandler is kept for backwards compatibility.
Here's a kickoff example how to properly extend ConfigurableNavigationHandler:
public class HistoryNavigationHandler extends ConfigurableNavigationHandler {
private NavigationHandler wrapped;
public HistoryNavigationHandler(NavigationHandler wrapped) {
this.wrapped = wrapped;
}
#Override
public void handleNavigation(FacesContext context, String from, String outcome) {
// TODO: Do your job here.
wrapped.handleNavigation(context, from, outcome);
}
#Override
public NavigationCase getNavigationCase(FacesContext context, String fromAction, String outcome) {
return (wrapped instanceof ConfigurableNavigationHandler)
? ((ConfigurableNavigationHandler) wrapped).getNavigationCase(context, fromAction, outcome)
: null;
}
#Override
public Map<String, Set<NavigationCase>> getNavigationCases() {
return (wrapped instanceof ConfigurableNavigationHandler)
? ((ConfigurableNavigationHandler) wrapped).getNavigationCases()
: null;
}
}
I am trying to build an JSF library control for XPages based on the examples by Keith Strickland.
http://xprentice.gbs.com/A55BAC/keithstric.nsf/default.xsp?documentId=82770C11FA7B9B21852579C100581766
I'm having a little bit trouble in building a FileDownloadControl
Here is the code I've built:
public class Libcontrol extends UIComponentBase implements FacesComponent {
private static final String RENDERER_TYPE = "de.chris.Libcontrol ";
private static final String COMPONENT_FAMILY = "de.chris";
public Libcontrol() {
setRendererType(RENDERER_TYPE);
}
#Override
public String getFamily() {
return COMPONENT_FAMILY;
}
#SuppressWarnings("unchecked")
public void initBeforeContents(FacesContext arg0) throws FacesException {
FacesContext context;
ExpressionEvaluatorImpl evaluator;
context = FacesContext.getCurrentInstance();
evaluator = new ExpressionEvaluatorImpl(context);
XspFileDownload result = new XspFileDownload();
String sourceId = "fileDownload1/#value";
String valueExpr = "#{document1.FileField}";
ValueBinding value = evaluator.createValueBinding(result, valueExpr, sourceId,Object.class);
result.setValueBinding("value", value);
result.setDisplayLastModified(true);
result.setAllowDelete(true);
result.setTitle("filedown");
result.setRows(30);
result.setId("fileDownload1");
this.getChildren().add(result);
}
public void buildContents(FacesContext arg0, FacesComponentBuilder arg1) throws FacesException {
// Do Nothing
}
public void initAfterContents(FacesContext arg0) throws FacesException {
// Do nothing
}
}
Why is the control not completely rendered? When I look to the HTML Code I see a starttag from the control but no Files to download
and yes I've uploaded files to the corresponding NotesDocument.
Here is the renderer I have implmented respectively copied:
public class MainLibcontrolRenderer extends Renderer {
#Override
public void encodeBegin(FacesContext context, UIComponent component) {
try {
super.encodeBegin(context, component);
context = FacesContext.getCurrentInstance();
UIViewRootEx rootEx = (UIViewRootEx) context.getViewRoot();
/*rootEx.setDojoParseOnLoad(true);
rootEx.setDojoTheme(true);*/
ResponseWriter writer = context.getResponseWriter();
writer.startElement("fieldset", component);
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
public void encodeChildren(FacesContext context, UIComponent component) {
try {
super.encodeChildren(context, component);
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
public void encodeEnd(FacesContext context, UIComponent component) {
try {
super.encodeEnd(context, component);
ResponseWriter writer = context.getResponseWriter();
writer.endElement("fieldset");
} catch (Exception e) {
e.printStackTrace();
}
}
}
Stephan is right: the reason the contents do not render is that you're not building them. When implementing FacesComponent, the buildContents method typically should instruct the FacesComponentBuilder to initiate the build process; e.g.:
arg1.buildAll(arg0, this, true);
NOTE: I'm using the argument names from your example; ideally, you should use meaningful argument names like "context" and "builder".
The buildAll method referred to above causes the component tree to properly reflect any changes made to the structure during the init methods. If you skip this step, the subsequent JSF phases (including RENDER_RESPONSE) are unaware of any components you injected.
By the way, Keith also makes a valid point: hardcoding the value binding and other properties - at least, in the example you provided - tends to defeat the purpose of defining a reusable control. I'd echo Keith's advice to take a closer look at what you're trying to accomplish to determine whether a custom component is really the appropriate implementation. And one final caution: use extreme care when programmatically setting the id property on injected components... you could end up with a name collision that cannot be detected during compilation. In other words, Designer can't warn you... it will just break at runtime and the reason for failure will probably not be obvious.