Radio buttons using twitter bootstrap - unable to get value - jsf

I've browsed SO, and found some answers that have guided me closer to getting working radio buttons, but I'm stuck now.
I have the buttons, but am unable to get the value of the selected one.
I'm using JSF, hence the #{searchFlightsBean.setDir()}
Here's what I currently have:
<h:panelGrid>
<div class="btn-group" data-toggle-name="is_private" data-toggle="buttons-radio" >
<button type="button" value="0" class="btn" data-toggle="button">Public</button>
<button type="button" value="1" class="btn" data-toggle="button">Private</button>
</div>
<h:inputHidden id="hiddenDir" value="0" valueChangeListener="#{searchFlightsBean.setDir()}" onchange="submit()"/>
</h:panelGrid>
<script>
$(function() {
$('div.btn-group[data-toggle-name]').each(function() {
var group = $(this);
var form = group.parents('form').eq(0);
var name = group.attr('data-toggle-name');
var hidden = $('input[name="' + name + '"]', form);
$('button', group).each(function() {
var button = $(this);
button.on('click', function() {
hidden.val($(this).val());
});
if (button.val() == hidden.val()) {
button.addClass('active');
#{searchFlightsBean.setDir(button.value)}
}
});
});
});
</script>
In my bean, when setDir() is called, I am logging the value that it receives, like so:
public void setDir(ValueChangeEvent e) {
this.dir = e.getNewValue().toString();
log.info("NEW DIRECTION: " + this.getDir());
}
It doesn't log - setDir() is never called. For some reason the valueChangeListener attribute on the h:inputHidden tag doesn't work. Am I missing something?

Your concrete problem is caused because you used valueChangeListener the wrong way.
<h:inputHidden ... valueChangeListener="#{searchFlightsBean.setDir()}">
This does not match the method signature. You should omit the parentheses ().
<h:inputHidden ... valueChangeListener="#{searchFlightsBean.setDir}">
Otherwise JSF expects an argumentless setDir() method. Then, you're nowhere in JavaScript triggering the change event on the input element. The onchange="submit()" is therefore never invoked. You should be doing hidden.trigger("change") in JS to achieve that.
But, after all, this is somewhat clumsy. You're sending a full synchronous request and your JS code is rather overcomplicated (and stops working once you ajax-update the form). Provided that you're indeeed using JSF 2.x, I suggest to bring in <f:ajax> — which unfortunately doesn't work in <h:inputHidden>, hence the <h:inputText style="display:none"> — and to make use of $.on() in jQuery to keep the functions working even when you ajax-update the DOM.
<h:form>
<div class="btn-group" data-toggle-name="is_private" data-toggle="buttons-radio" >
<button type="button" value="0" class="btn" data-toggle="button">Public</button>
<button type="button" value="1" class="btn" data-toggle="button">Private</button>
</div>
<h:inputText id="is_private" value="#{bean.dir}" style="display: none;">
<f:ajax listener="#{bean.changeDir}" />
</h:inputText>
<!-- Note: <h:inputText id> must be exactly the same as <div data-toggle-name> -->
</h:form>
<h:outputScript>
$(document).on("click", "[data-toggle=buttons-radio] button", function() {
var $button = $(this);
var id = $button.closest(".btn-group").attr("data-toggle-name");
var $input = $button.closest("form").find("input[id$=':" + id + "']");
if ($input.val() != $button.val()) {
$input.val($button.val()).trigger("change");
}
});
</h:outputScript>
(noted should be that the whole script should really be placed in its own .js file which you include by <h:outputScript name="some.js" target="body">; note that you don't need $(document).ready() nor $(function() {}) mess; also note that the very JS function is reusable on all other <div data-toggle="buttons-radio"> groups without changes)
With this bean:
private Integer dir;
public void changeDir() {
System.out.println("New direction: " + dir);
}
// ...
(noted should be that when you're doing further nothing relevant in changeDir() method, then you could just omit the whole method and <f:ajax> altogether and revert <h:inputText style="display:none"> back to <h:inputHidden> and remove .trigger("change") and rely on the regular form submit. It'll work as good)

You cannot just call any backing bean functions via Expression Language calls (#{...}) in JavaScript.
What you could do, is using a4j:jsFunction to offer your bean method to the java script code. That might look like this:
<a4j:jsFunction name="setDir" action="#{searchFlightsBean.setDir()}" ajaxSingle="true">
<a4j:param name="dir" assignTo="#{searchFlightsBean.dir}" />
</a4j:jsFunction>
See http://docs.jboss.org/richfaces/latest_3_3_X/en/devguide/html/a4j_jsFunction.html
and http://showcase.richfaces.org/richfaces/component-sample.jsf?demo=jsFunction&skin=blueSky

Related

p:remoteCommand not executing / not called from javascript

After calling the javascript function by clicking on logout p:remotecommand is not executing.
This is my XHTML code:
<script type="text/javascript">
function logoutAccount() {
debugger;
var txt = "eeeeeeeeeeeeeee";
command([{name:'param',value:txt}]); //This is important
}
</script>
<i class="fa fa-sign-out fa-fw"></i> Logout
<p:remoteCommand name="command" action="#{MyiaTaskBean.method}" />
This is my code in Java bean:
public void method() {
String value = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("param");
System.out.print("value is::::::::::::::::::::::"+value);
}
I tried to change action by action listener but it didn't work.
p:remoteCommand needs to be inside form.
Below code works in my environmet (you haven't said what JSF/PF version you're using):
<script>
function logoutAccount() {
console.log('logoutAccount fired!');
var txt = 'some text';
command([{name:'param',value:txt}]);
}
</script>
<i class="fa fa-sign-out fa-fw"></i> Logout
<h:form>
<p:remoteCommand name="command" action="#{testBean.method}" />
</h:form>
With your java code the result is:
value is::::::::::::::::::::::some text

Problems with multiple actions in a JSF page

I have a JSF 2.2 + Primefaces 5 web application which contains an .xhtml with multiple possible outcomes:
<h:body>
<script type="text/javascript">
function download(file) {
document.forms[0].elements["filename"].value = file;
document.forms[0].submit();
}
function back() {
document.forms[0].method = "get";
document.forms[0].action = "home.xhtml";
document.forms[0].submit();
}
</script>
<form id="download" action="DownloadServlet" method="post">
. . . .
<h:commandButton id="back" value="Back" onclick="back();" />
<h:commandButton id="download" value="Download" type="Submit"
onclick="download('#{value}');" />
</form>
By clicking on the "Download" button, the Servlet "DownloadServlet" kicks in and downloads a file selected in the form.
However by clicking on the Back button, I'm not redirected to the page "home.xhtml". The Javascript function "back" simply is not invoked but the Servlet kicks again. It seems a conflict between the two actions. How can I solve it and add a button to return to another page ?
Thanks
Don't do it the hard way. Use a <h:button> to generate a GET button.
<h:button id="back" value="Back" outcome="home.xhtml" />
The second <h:commandButton> could better be just a plain vanilla <input type="submit">, by the way.

Validation failed javascript callback in JSF

I have a template in which I can add a CSS error class to a div when the validation of a component has failed and it renders a pretty nice effect on the browser.
Now, I don't need to add a css class to a component (this won't help me), but rather I need to change the css of the html that surrounds it, this is pretty simple with jQuery, however I can't seem to find a javascript callback for failed validation, is this possible? I'm also using primefaces (in case they provide such capabilities).
Markup:
<div class="control-group ERROR_CLASS_GOES_HERE_IF_VALIDATION_FAILED">
<label class="control-label">Input value:</label>
<div class="controls">
<h:inputText class=" inputbox" type="text" required="true" /> <!--Component that can fail -->
</div>
</div>
if the input text is empty, I need the div that wraps the "control group" to have an extra class. I can turn it into a <h:panelGroup> so it is a JSF component but still I wouldn't know how to do it. Javascript seems easier as I can do a:
jQuery("#ID_OF_DIV").addClass("error_class")
Just let JSF/EL conditionally print the class based on FacesContext#isValidationFailed().
<div class="control-group #{facesContext.validationFailed ? 'error_class' : ''}">
You only need to ensure that this element is covered by ajax update/render.
Another way would be hooking on the oncomplete event of an arbitrary PrimeFaces ajax based component. There's an args object available in the scope which in turn has a validationFailed property. E.g. <p:commandButton oncomplete> or even <p:ajaxStatus oncomplete>.
<p:ajaxStatus ... oncomplete="if (args && args.validationFailed) $('#ID_OF_DIV').addClass('error_class')">
If you want to do everything on the client side.
<h:outputText class="samplecls" rendered="#{facesContext.validationFailed}"
value="Please enter all the required fields">
</h:outputText>
<div class="control-group ERROR_CLASS_GOES_HERE_IF_VALIDATION_FAILED">
<label class="control-label">Input value:</label>
<div class="controls">
<h:inputText class=" inputbox" type="text" required="true" /> <!--Component that can fail -->
</div>
</div>
Javascript/Jquery
This class will exist in DOM only validation fails by rendered="#{facesContext.validationFailed}"
$(window).load(function(){
if($('.samplecls').length>0){
$("#ID_OF_DIV").addClass("error_class");
}
});

How to create a button in JSF page with custom label

I have this simple JSF button:
//Question Dialog
function deletedialog(button, a){
$("<div />", {
text: a
}).dialog({
width: 600,
buttons: {
"Ok": function() {
$("#form\\:deleterow").click();
// $('input[id$="deleterow"]').click();
$(this).dialog("close");
button.value = "Processing...";
button.disabled = true;
},
"Cancel": function(event) {
$(this).dialog("close");
event.preventDefault();
button.value = "Delete";
button.disabled = false;
}
}
});
}
<!-- hidden button -->
<h:commandButton id="deleterow" value="HiddenDelete" action="#{AccountsController.deleteSelectedIDs}" style="display:none">
<f:ajax render="#form"></f:ajax>
</h:commandButton>
<!-- the delete button -->
<h:button onclick="deletedialog(this, 'Do you want to delete the selected rows?'); return false;" >
<h:graphicImage name="small-hover.png" library="images" title="Delete" />
</h:button>
I want to create png image which will be the visual body of the button. The only thing that I will change will be the title of the button which I will set every time using the value attribute of the button. Is this possible? Now when I load the JSF page I see only empty button without label.
P.S 1 I get this result:
Use a command link that will wrap your image:
<script type="text/javascript">
function deletedialog(button, a) {
$("<div />", {
text: a
}).dialog({
width: 600,
buttons: {
"Ok": function() {
//$("#form\\:deleterow").click();
//using the hidden button click
document.getElementById('myForm:deleterow').click();
// $('input[id$="deleterow"]').click();
$(this).dialog("close");
button.value = "Processing...";
button.disabled = true;
},
"Cancel": function(event) {
$(this).dialog("close");
event.preventDefault();
button.value = "Delete";
button.disabled = false;
}
}
});
}
</script>
<h:form id="myForm">
<h:commandLink onclick="deletedialog(this, 'Do you want to delete the selected rows?')) return false;">
<h:graphicImage name="small-hover.png" library="images"
title="#{someBean.imageTitle}" />
</h:commandLink>
<h:commandButton id="deleterow" value="HiddenDelete" action="#{AccountsController.deleteSelectedIDs}" style="display:none">
<f:ajax render="#form" />
</h:commandButton>
</h:form>
Also, there is a good example of <h:graphicImage/> in mkyong site.
Based on your comments, it looks like you want to have a button with an icon. Also, the real action is performed by your hidden <h:commandButton>. so I recommend you to read this answer:
HTML / CSS How to add image icon to input type=“button”?
Your code would be like this:
<h:commandButton id="deleterow" value="HiddenDelete" action="#{AccountsController.deleteSelectedIDs}" style="display:none">
<f:ajax render="#form" />
</h:commandButton>
<button type="submit" onclick="deletedialog(this, 'Do you want to delete the selected rows?')) return false;"><img src="resources/images/small-hover.png" /> Delete</button>
Yes, you can mix basic HTML with JSF code, but read the link warning about this implementation on IE 6 browser clients.
I'd start from basics. Since you don't even see an image, when you right click on the browser window, and select 'view source' does it provide any meaningful information on whether the image is even being inserted onto the page? If you don't have the image path correct, it won't render the image on the page. That is the first thing to check and try to correct. (i.e. is the computer plugged in).

Using CKEditor instead of PrimeFaces Editor

I am trying to use CKEditor in my JSF application. How to get the content of CKEditor into backing bean..?
index.xhtml
<form action="" method="post">
<p>
My Editor:<br />
<textarea cols="90" rows="20" id="editor1" name="editor1" value="#{EditorBean.value}"></textarea>
<script type="text/javascript">
CKEDITOR.replace( 'editor1',
{
uiColor: '#85B5D9'
});
</script>
<input type="button" value="Clear" name="clear" onclick="clear1()"/>
</p>
</form>
BackingBean
#ManagedBean
public class EditorBean {
private String value;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
System.out.println("Content: "+value);
}
}
When I tried to print the value, It is not printing. Help me on this issue. PrimeFaces Editor is not supporting "Insert Table" function. So, I want to use CKE.
As el wont be able to evaluate non-JSF component.
Add this to your page :
<h:inputHidden value="#{EditorBean.value}" id="editorValue"/>
and onblur of editor textarea assign the value to the hidden element using
document.getElementById(editorValue).value = this.value;
Since this question bumped up somehow....
There is another option:
You can use the PrimeFaces Extensions , here is the link PrimeFaces Extensions CKEditor
Here an example from the showcase
<p:growl id="growl" showDetail="true" />
<pe:ckEditor id="editor" value="#{editorController.content}" interfaceColor="#33fc14">
<p:ajax event="save" listener="#{editorController.saveListener}" update="growl"/>
</pe:ckEditor>
<p:commandButton actionListener="#{editorController.changeColor}" update="editor"
value="Change color with AJAX" style="margin-top:10px;"/>
try this:
<textarea class="ckeditor" cols="80" id="editor1" rows="10"/>
<h:inputHidden value="#{tskCtrl.selected.dsc}" id="editorValue"/>
<p:commandButton onclick="document.getElementById('editorValue').value = CKEDITOR.instances.editor1.getData();" action="#{tskCtrl.create()}" value="Post" />
The answer from niksvp was helpful and set me in the right direction, but
the problem I found was that the blur handler never fires. I had to copy
the value from the textarea to the inputHidden on the onclick handler of
the commandButton:
<textarea id="textareaValue" .../>
<a4j:commandButton execute="editorValue" onclick="document.getElementById('editorValue').value = document.getElementById('textareaValue').value;"
...
or
<a4j:commandButton execute="editorValue" onclick="jQuery('#editorValue').val(jQuery('#textareaValue').val())"
I tried using onbegin & onbeforedomupdate but they didn't work.
Another option is to use the JSF versions of form and textarea. (It is likely possible to do this with passthrough elements as well, but I didn't try that.)
<h:form id="form">
<p>
My Editor:<br />
<h:inputTextarea cols="90" rows="20" id="editor1" value="#{EditorBean.value}" />
<script type="text/javascript">
ClassicEditor.create(document.querySelector('form\\:editor1'))
.then( editor => {
console.log( editor );
} )
.catch( error => {
console.error( error );
} );
</script>
</p>
</form>
This assumes that you do not have prependId=false.
The weird \\: is an escaping issue. It won't work without that. You'd get the "is an invalid selector" error in the console.
You can ID form and editor1 with other names, but you'll need to change the selector as well. You don't want to leave it to the defaults, as those are fragile, often changing as you update the page. Now it will only change if you change the structure of where editor1 is relative to form. E.g. if you add a fieldset around editor1, that would make the ID something like form\\:fieldset\\:editor1, where fieldset is the ID of the fieldset as specified in JSF. JSF will create the long version for you.
This also requires the CKEditor script to be added to the head, e.g.:
<script src="https://cdn.ckeditor.com/ckeditor5/11.2.0/classic/ckeditor.js"></script>
This particular example is for the ClassicEditor version. If you want a different version, you'd need to change the script and the part that says ClassicEditor.
Differences between the script as called in the question and this version may be that this is the current version (as I write this) while the question is older.
Alternately, you might prefer to use h:outputScript. But then you might need to host the script in your resources folder rather than using the version from the CDN.
See also:
Is the ID generated by JSF guaranteed to be the same across different versions and implementations?
Select element with double dot in id, error: “#octo:cat” is not a valid selector
Acquire full prefix for a component clientId inside naming containers with JSF 2.0
How to find out client ID of component for ajax update/render? Cannot find component with expression “foo” referenced from “bar”
How to include JavaScript files by h:outputScript?

Resources