create links dynamically - jsf

I have a user-defined text, such as
#SessionScoped
public class MyBean {
private String text = "Life’s but a walking shadow, a poor player
that struts and frets his hour upon the stage and
then is heard no more.";
public String getText() {
return text;
}
}
Of course the text is not static, but will be loaded from somewhere else. I want the text to be displayed one the page, as in
<h:form id="myForm">
<h:outputText value="#{myBean.text}" />
</h:form>
Now have a logic in the bean which marks certain words, e.g. every noun, in the text. These words should be rendered as links, as if they were commandLinks.
That is, the form should be submitted and I should be able to find out which link was clicked.
Something similar was already asked here, here and here, but I am not sure if the solutions given there suit my case.
My best guess right now is to split the text at the marked words into a list of snippets in the bean, e.g.
List<TextSnippet> textSnippets;
class TextSnippet {
private String precedingText;
private String markedWord;
...
}
such that each text snippet ends with a marked word. Then I would be able to iterate over the list in the xhtml, e.g.
<h:form id="myForm">
<ui:repeat var="snippet" value="#{myBean.textSnippets}">
<h:outputText value="#{snippet.precedingText}" />
<h:commandLink action="#{myBean.clickedOn(snippet.markedWord)}">
<h:outputText value="#{snippet.markedWord}">
</h:commandLink>
</ui:repeat>
</h:form>
However, I feel that this tightly couples the bean (logic of splitting) to the view. Any better ideas?

What I would personally do is try to keep the jsf tree small and implement something like the lines below that I think is more performant (disclamer: no full code coming )
Prepare the text serverside in a bean as This is a <div class="linkedWord">specific</div> word that needs a link and so is <div="linkedWord">this</div>
Output this in plain html via an <h:outputText value="#{myBean.text}"> (for escaping!)
Add a jquery dynamic eventhandler on the class="linkedWord" (so it works for each link) and call a javascript function
In that javascript function read the content of the div (or maybe add the text as a data- attribute aas well (like <div class="linkedWord" data-word="specific">specific</div>
and call a <h:commandScript> (JSF 2.3 and up) or a o:commandScript for previous JSF versions (or the `p:remoteCommand) and pass the content of the div (or the value of the attribute) as a parameter to a serverside method.
Keep in mind that there is no explicit reason to do everything in a 'JSF' way. Using client-side features and some small integration with JSF is very valid usage. People not doing this often 'blame' JSF but they themselves are effectively the cause of the less optimal behaviour)
See also:
Event binding on dynamically created elements?
http://omnifaces.org/docs/javadoc/2.6/org/omnifaces/component/script/CommandScript.html
https://javaserverfaces.github.io/docs/2.3/vdldocs/facelets/h/commandScript.html

You seem to go the right way, but I think I can suggest you some improvements. Don't know your exact requirements, but your current structure limits the marked word (which I guess acts as a mere link) to be at the end of the paragraph. What would happen if you have text after it? What about having two marked words? This class might suit better:
class TextSnippet {
private String text;
private String linkUrl;
...
}
You'll need to build the List<TextSnippet> the way you do, but evaluate the links before, so ui:repeat can access them.
Then, iterate over it. Instead of performing a POST to evaluate where to go, you've got it already, so you can use a h:link if you want to point to somewhere in your application or h:outputLink if it's outside it:
<ui:repeat var="snippet" value="#{myBean.textSnippets}">
<h:outputText value="#{snippet.text}" rendered="#{empty snippet.linkUrl}" />
<h:link outcome="#{snippet.linkUrl}" rendered="#{not empty snippet.linkUrl}">
<h:outputText value="#{snippet.text}">
</h:link>
</ui:repeat>

Related

How to trigger click event on command button in JSF, after the evalution of action EL expression [duplicate]

Problem: Sometimes you will want to access a component from javascript with
getElementById, but id's are generated dynamically in JSF, so you
need a method of getting an objects id. I answer below on how you can do this.
Original Question:
I want to use some code like below. How can I reference the inputText JSF component in my Javascript?
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">
<head>
<title>Input Name Page</title>
<script type="javascript" >
function myFunc() {
// how can I get the contents of the inputText component below
alert("Your email address is: " + document.getElementById("emailAddress").value);
}
</script>
</head>
<h:body>
<f:view>
<h:form>
Please enter your email address:<br/>
<h:inputText id="emailAddresses" value="#{emailAddresses.emailAddressesStr}"/>
<h:commandButton onclick="myFunc()" action="results" value="Next"/>
</h:form>
</f:view>
</h:body>
</html>
Update: this post Client Identifiers in JSF2.0 discusses using a technique like:
<script type="javascript" >
function myFunc() {
alert("Your email address is: " + document.getElementById("#{myInptTxtId.clientId}").value);
}
</script>
<h:inputText id="myInptTxtId" value="backingBean.emailAddress"/>
<h:commandButton onclick="myFunc()" action="results" value="Next"/>
Suggesting that the attribute id on the inputText component
creates an object that can be accessed with EL using #{myInptTxtId},
in the above example. The article goes on to state that JSF 2.0 adds
the zero-argument getClientId() method to the UIComponent class.
Thereby allowing the #{myInptTxtId.clientId} construct suggested
above to get the actual generated id of the component.
Though in my tests this doesn't work. Can anyone else confirm/deny.
The answers suggested below suffer from drawback that the above
technique doesn't. So it would be good to know if the above technique
actually works.
You need to use exactly the ID as JSF has assigned in the generated HTML output. Rightclick the page in your webbrowser and choose View Source. That's exactly the HTML code which JS sees (you know, JS runs in webbrowser and intercepts on HTML DOM tree).
Given a
<h:form>
<h:inputText id="emailAddresses" ... />
It'll look something like this:
<form id="j_id0">
<input type="text" id="j_id0:emailAddress" ... />
Where j_id0 is the generated ID of the generated HTML <form> element.
You'd rather give all JSF NamingContainer components a fixed id so that JSF don't autogenerate them. The <h:form> is one of them.
<h:form id="formId">
<h:inputText id="emailAddresses" value="#{emailAddresses.emailAddressesStr}"/>
This way the form won't get an autogenerated ID like j_id0 and the input field will get a fixed ID of formId:emailAddress. You can then just reference it as such in JS.
var input = document.getElementById('formId:emailAddress');
From that point on you can continue using JS code as usual. E.g. getting value via input.value.
See also:
How to select JSF components using jQuery?
Update as per your update: you misunderstood the blog article. The special #{component} reference refers to the current component where the EL expression is been evaluated and this works only inside any of the attributes of the component itself. Whatever you want can also be achieved as follows:
var input = document.getElementById('#{emailAddress.clientId}');
with (note the binding to the view, you should absolutely not bind it to a bean)
<h:inputText binding="#{emailAddress}" />
but that's plain ugly. Better use the following approach wherein you pass the generated HTML DOM element as JavaScript this reference to the function
<h:inputText onclick="show(this)" />
with
function show(input) {
alert(input.value);
}
If you're using jQuery, you can even go a step further by abstracting them using a style class as marker interface
<h:inputText styleClass="someMarkerClass" />
with
$(document).on("click", ".someMarkerClass", function() {
var $input = $(this);
alert($input.val());
});
Answer: So this is the technique I'm happiest with. Doesn't require doing too much weird stuff to figure out the id of a component. Remember the whole point of this is so you can know the id of a component from anywhere on your page, not just from the actual component itself. This is key. I press a button, launch javascript function, and it should be able to access any other component, not just the one that launched it.
This solution doesn't require any 'right-click' and see what the id is. That type of solution is brittle, as the id is dynamically generated and if I change the page I'll have to go through that nonsense each time.
Bind the component to a backing bean.
Reference the bound component wherever you want.
So here is a sample of how that can be done.
Assumptions: I have an *.xhtml page (could be *.jsp) and I have defined a backing bean. I'm also using JSF 2.0.
*.xhtml page
<script>
function myFunc() {
var inputText = document.getElementById("#{backBean.emailAddyInputText.clientId}")
alert("The email address is: " + inputText.value );
}
</script>
<h:inputText binding="#{backBean.emailAddyInputText}"/>
<h:commandButton onclick="myFunc()" action="results" value="Next"/>
BackBean.java
UIInput emailAddyInputText;
Make sure to create your getter/setter for this property too.
Id is dynamically generated, so you should define names for all parent elements to avoid j_id123-like ids.
Note that if you use jQuery to select element - than you should use double slash before colon:
jQuery("my-form-id\\:my-text-input-block\\:my-input-id")
instead of:
jQuery("my-form-id:my-text-input-block:my-input-id")
In case of Richfaces you can use el expression on jsf page:
#{rich:element('native-jsf-input-id')}
to select javascript element, for example:
#{rich:element('native-jsf-input-id')}.value = "Enter something here";
You can view the HTML source when this is generated and see what the id is set to, so you can use that in your JavaScript. As it's in a form it is probably prepending the form id to it.
I know this is not the JSF way but if you want to avoid the ID pain you can set a special CSS class for the selector. Just make sure to use a good name so that when someone reads the class name it is clear that it was used for this purpose.
<h:inputText id="emailAddresses" class="emailAddressesForSelector"...
In your JavaScript:
jQuery('.emailAddressesForSelector');
Of course you would still have to manually manage class name uniqueness.
I do think this is maintainable as long as you do not use this in reusable components. In that case you could generate the class names using a convention.
<h:form id="myform">
<h:inputText id="name" value="#{beanClass.name}"
a:placeholder="Enter Client Title"> </h:inputText>
</h:form>
This is a small example of jsf. Now I will write javascript code to get the value of the above jsf component:
var x = document.getElementById('myform:name').value; //here x will be of string type
var y= parseInt(x,10); //here we converted x into Integer type and can do the
//arithmetic operations as well

Creating command links dynamically from a managed bean

I have a need to create command links dynamically based on content coming from elsewhere.
When a user clicks on a link it should call a method in a managed bean, and the method needs to know which link was clicked.
I can create the command links using the following code:
JSF:
<h:outputText value="#{myBean.dynamicLinks}" escape="false" />
Bean:
public String getDynamicLinks(){
// Return an html string that contains a set of <a> elements, based on the dynamic content
}
This works fine, but what I can't work out is how my <a> elements can call back into the bean.
This is not the right way to "dynamically" create markup. For that you should be using XHTML, and absolutely not Java and for sure not massage some plain HTML in the model and present it with escape="false". That's plain nonsense. You're basically mingling the view into the model. You need to make the model itself dynamic, not the view. The view must be static and dumb. The view must just present the model to the world. The model itself can be dynamic. You normally achieve that by using a flexible collection, such as List<String>, List<SomeEntity>, etc which you then present using an iterator in the view such as <ui:repeat> or <h:dataTable>.
E.g.
<ui:repeat value="#{bean.links}" var="link">
<h:commandLink value="link" action="#{bean.action(link)}" />
</ui:repeat>
public void action(Link link) {
// ...
}
You see, the action method can know about the pressed link by just inspecting the method argument.
See also:
How to create dynamic JSF form fields
How can I pass selected row to commandLink inside dataTable?

JSF 2.0 dynamic form best practice

Update: for those flagging this to be closed as a duplicate, the supposed duplicate question is nothing like what I am asking. My problem is I do not know until render time what the question set will be, how many questions there will be or what the question types will be so I cannot use the technique described in the "possible duplicate" answer.
Part of our JSF 2.x application has a requirement to render sets of questions to the user where the questions and the question types are not known until run-time. e.g we have something like (getters/setters omitted for clarity) :
public class QuestionSet {
private List<Section> sections;
}
public class Section {
private String sectionTitle;
private List<Question> questions;
private SectionStatus status; // e.g. UNANSWERED, CURRENTLY_ANSWERING,ANSWERED, COMPLETED
}
public class Question {
private String questionText;
private QuestionType questionType; // E.G TEXT, RADIO, LIST, CHECKBOX
private List<String> options; // for RADIO/LIST/CHECKBOX types
private List<String> answers;
}
We need to render each section in a seperate div, depending on it's status (e.g. UNANSWERED would display a div with just the title, ANSWERED would display a div with the section title and a green tick mark, and CURRENTLY_ANSWERING would render a div with the section title and then each question with the appropriate input control based on the question type.
The questions are also dynamic during the run - e.g. if a user answers yes to a radio button question, this may prompt further sub-questions.
I am currently doing this using a binding, i.e.
<h:panelGroup binding = "#{bean.panelGroup}" />
and within the bean's getPanelGroup creating the component tree by hand usin things like HtmlPanelGroup, HtmlOutputText, UIInput with ValueExpressions etc. which works fine but on reading some of BalusC's answers, particlarly to this question: How does the 'binding' attribute work in JSF? When and how should it be used? I am wondering if there is a "better" approach?
One of the things that concerns me is that the getter is called during RECREATE_VIEW for reasons explained in the linked question (after invoking the method referred to in the binding) so unless I take steps to, in RECREATE_VIEW phase, just return the component I created in the last RENDER_RESPONSE phase, this introduces unnecessary expense of recreating something I've just created.
In this case, it also seems pointless that JSF calls my setter to set the thing I just gave it in the getter for the bound property. (my bean is View scope as I will need to use ajax for some of the functionality our users require)
Thoughts/opinions (Especially from the ever helpful BalusC) greatly appreciated...
I don't see much reason to use component binding in this case. You can decide in your view what to render and how. You can have <ui:fragment>/<c:if> to conditionally render elements basing on question type, <ui:repeat>/<c:forEach> to handle the question set, etc.
So, if I understand the workflow correctly, your question set will be determined in e.g. post constructor method:
#PostConstruct
public void init() {
questionSet = service.get();//get it somehow
}
Then you'll have a set of sections and each of these section will contain questions, or answers, and validity is to be checked via AJAX. If I understand you right, then you can have the following view:
<h:form id="q-set">
<ui:repeat value="#{bean.questionSet.sections}" var="section">
<div>#{section.title}</div>
<div class="#{section.status eq 'UNANSWERED' ? 'section-unanswered' : ... }"/>
<ui:fragment rendered="#{section.status eq 'ANSWERED' ?}"><div class="tick"/></ui:fragment> ...
<ui:fragment rendered="#{section.status eq 'ANSWERED' ?}">
<ui:repeat value="#{section.questions}" var="question">
<div>#{question.title}</div>
<ui:fragment rendered="#{question.type eq 'RADIO'}">
<h:selectOneRadio value="#{question.answers[0]}" validator="...">
<f:selectItems value="#{question.options}" var="opt" itemLabel="#{opt}" ... />
<f:ajax ...>
</h:selectOneRadio>
</ui:fragment>
...
</ui:repeat>
</ui:fragment>
</ui:repeat>
</h:form>
It looks like you are going to have too much logic/conditions in your view.
What about generating the view programmatically on the Java side ?
For tricky parts you may resort to JavaScript and JSON.

JSF validation for client side injected elements

I know there is a property in asp.net (probably this EnableEventValidation of "<%# Page%> tag) .Which, once caused problem when i try to add select items to a component using javascript ,I want to know how jsf handling this. That is,
if i send a h:select* like below and client add a new item "option3 " to item list, is jsf detect this automaticly before update model values .
<h:selectOneMenu id="type"
value="#{foo.value}"
required="true"
requiredMessage="Type is required"
style="width:100px">
<f:selectItem value="option1}"/>
<f:selectItem value="option2}"/>
</h:selectOneMenu>
I think what you need to understand regarding JSF is that the client/server parts of the components are tightly coupled together. You are probably better off thinking of them strictly as one entity, and forget about fiddling with one side only, reverting to custom Javascript when that is the only solution left.
The other way to think of it is that the server side renders the client side, not vice versa! So whenever you need to update a component the update must be done on the server side first, which will propagate to the client side (the browser).
In your example the proper way to add and element to the select* items is to store the selectable items in a data structure within a bean (probably #ViewScoped), and then do a partial update via AJAX for the select* component or its container component, when the server side gets the chance to become aware of the changes and can update the client side properly as well.
Sure, you can hack your way through Javascript only, but then why use JSF? The whole point of JSF is to avoid the need for hacks like this.
Remember, JSF is not JSP, which is basically a println macro for html output. JSF stores the page components' representation on the server side, mirroring the browser's representation.
Check the Primefaces showcase for examples on how to do partial updates. More specifically this is the example you could be looking for. This is available in standard JSF2, for JSF 1.2 you must use a component library to get AJAX support.
You should not add the new option by JavaScript, but you should add the new option by JSF. JSF needs to know about the new option somehow in order to allow the submitted value. The new option really needs to be served by <f:selectItem(s)>. Otherwise you will face Validation error: Value not valid all the time when submitting the option value which is added by JS. This is after all just a safeguard of JSF to prevent clients from manipulating the request and submitting values which they are not supposed to submit.
The following kickoff example should work:
<h:form>
<h:selectOneMenu id="menu" value="#{bean.item}">
<f:selectItems value="#{bean.items}" />
</h:selectOneMenu>
<h:inputText id="newItem" value="#{bean.newItem}" />
<h:commandButton value="add" action="#{bean.addNewItem}">
<f:ajax execute="#this newItem" render="menu" />
</h:commandButton>
<h:commandButton value="submit" action="#{bean.submit}" />
</h:form>
with a #ViewScoped managed bean something like follows:
private String item;
private List<String> items = Arrays.asList("option1", "option2");
private String newItem;
public void addNewItem() {
items.add(newItem);
}
// ...

JSF <h:outputFormat>: use array values as parameters

On my JSF2 page, i'm using internationalized error messages.
In my backing bean, i'm putting the messages into the flash Scope:
flash.put("error", exception.getType());
On the page, this string gets translated this way:
<h:outputText value="#{bundle[flash.error]}"/>
Works fine.
NOW i want to be also able to put (an arbitrary number of) parameters into the message text, that get inserted into the placeholders in the i18n-property in my message.properties. Therefore, i'm putting the parameters as a String array into the Flash Scope, like this:
//exception.getParameters returns String[]
flash.put("errorParams", exception.getParameters())
Now i also want to be able to use this String array as parameters for an outputFormat element, to insert them into a property like Welcome, {0} {1}.
So i tried to achieve this by using ui:repeat:
<h:outputFormat value="#{bundle[flash.error]}" rendered="#{! empty flash.error}" class="invalid">
<ui:repeat value="#{flash.errorParams}" var="_param">
<f:param value="#{bundle[_param]}"/>
<!-- also doesn't work: <f:param value="#{_param}"/>-->
</ui:repeat>
</h:outputFormat>
Unfortunately, the param value is ignored and the placeholders of the i18n-property aren't replaced, so the rendered output is Welcome, {0} {1}. When using a "regular" repeater, displaying the array elements just as an outputtext, it works. So the outputFormat tag doesn't seem to support the use of a repeat as a child.
Damn, so close ;) Anyone knows a good way to do what i want, or is there any component library supporting something like that?
The problem here is that ui:repeat is a render-time child of h:outputFormat which it indeed doesn't support at all. You'd like to put multiple f:param elements directly as children of h:outputFormat during build time.
The c:forEach is suitable for this task. The JSTL core tags (which are already included in Facelets, so you don't need to install any extra JARs) do their job during building the view tree, right before it's JSF turn to process/render the view tree.
<html xmlns:c="http://java.sun.com/jsp/jstl/core">
...
<h:outputFormat value="#{bundle[flash.error]}" rendered="#{! empty flash.error}" class="invalid">
<c:forEach items="#{flash.errorParams}" var="_param">
<f:param value="#{bundle[_param]}"/>
</c:forEach>
</h:outputFormat>

Resources