How to pass bean value to JavaScript before form submit - javascript

I am making webpage about ride sharing/selling bus tickets using JSF.
On one particular page, logged users can publish their ad (offering or looking for ride).
They should enter info like: ad title, origin city, destination city, departure time, etc.
What I want is, that users get weather forecast of destination city showed in popup after they hit submit.
This also means I am consuming service like openweathermap.
Basically, I have one h:form and h:commandButton like this:
<h:commandButton value="Publish" action="#{adBean.publishAd}" type="submit" onclick="showPopup()">
</h:commandButton>
The problem is that I don't know how to pass bean value of
<h:inputText value="#{adBean.ad.destinationCity}"/>
to JavaScript method showPopup().
I've tried this, but destinationCity turns out to be null.
<h:commandButton value="Publish" action="#{adBean.publishAd}" type="submit" onclick="showPopup(#{adBean.ad.destinationCity})">
</h:commandButton>
Why is this happening and how can I pass its value to JavaScript code?

It is null because it is put in an attribute (onclick) that is used for javascript. Attributes like these are 'rendered' at the time the page is displayed, not (again) at submission time or other moments. So if it is initialized null at that time, what is transferred from the server to the client is
<button value="Publish" ... onclick="showPopup(null)" />
A quote from #BalusC about this in How to invoke a bean action method using a link? The onclick does not work:
In JSF, only the attributes which interpret the EL expression as a MethodExpression can be used to declare action methods. All other attributes are interpreted as ValueExpression and they are immediately executed when the HTML output is generated by JSF. This covers the onclick attribute, whose value should actually represent a JavaScript function.
The (h:?)inputText on the client-side is rendered as a plain html inputText, so if you want access to its value before submitting (like I suspect you want to), you can do so in the showPopup like you would in plain html/javascript.
How to do this is mentioned in many stackoverflow Q/A so either pick one that suites you best e.g. How do I get the value of text input field using JavaScript?, but make sure to also read How can I know the id of a JSF component so I can use in Javascript

Related

How do I get the data value from a button?

I am building a forum app in node and I would like to create big bright buttons on my home page that would route users to another /view (topic) when clicked on.
I would like to gather the value of the button pushed inside of an object, so that I can use it within a dynamic route to be able to render to a specific view. I will also need that value to query with. Unfortunately I am having trouble getting the value of the button clicked.
Here are my buttons/inputs:
<form action='/topics' method="GET">
<input type="submit" value="boy" id="boy" class="bounce topics">
<button type="submit" value="girl" id="girl" class="bounce topics"><h2 class='topic'>Girl</h2></button>
</form>
when I console log req.body neither method gives me anything, I only get an empty object. I have read the two other threads I could find that were similar, but even though my code is comparable, I am getting nada.
I believe the method attribute in your form element needs to be POST instead of GET
You may use either GET or POST in the method. The difference is that you will be retrieving them from the $_GET or $_POST global variables on the server side in PHP (or similar variables in the language of your choosing).
Instead of using "id" for each input element, you must specify names:
<input type="submit" name="boy" value="boy">
<input type="submit" name="girl" value="girl">
You should be able to access URL / GET variables via req.query.<variablename>.

Call function from JSF backing bean with javascript var or other tag value

I' have seen many answers here but none worked for what I want, I need to do this in a way that the form is not submited, and by using the hidden button approach (with an ajax call) and calling the click() event from javascript, the method is called, but I need to pass an int in the method, how can I do that?
I can get the int from a javascript var or from a hidden input text field, just don't know how to do that, can anyone help with that?
JSF code:
<script type="text/javascript" language="javascript">
var position;
</script>
<h:inputHidden id="hiddenHolder" value="#{backingBean.beanPosition}" />
<h:commandButton id="hiddenButton" style="display: none;">
<f:ajax listener="#{backingBean.testMethod(need to send here javascript var or inputHidden value)}"/>
</h:commandButton>
Bean function;
public void testMethod(int i){
//do stuff
}
When I change the hiddenHolder value from javascript that is not reflected in the backingBean, I guess it needs a submit for that to work. That is why I need to pass the value in the method call.
When I change the hiddenHolder value from javascript that is not reflected in the backingBean
You're indeed not telling JSF to process the input value. The <f:ajax execute> should be used for this, which defaults to #this (the current input or command component). As the <f:ajax> is enclosed inside a command component, only the command component itself (its action) will be processed.
So, just explicitly specify the input value along with the command component:
<f:ajax execute="#this hiddenHolder" ... />
Or, if this all is within the same form, use #form:
<f:ajax execute="#form" ... />
See also:
How to invoke a JSF managed bean on a HTML DOM event using native JavaScript?
How to use jsf.ajax.request to manually send ajax request in JSF
Calling JSF managed bean method with arguments in jQuery
Use the OmniFaces commandScript for this. Works great (or use the PrimeFaces remoteCommand if you already use that)
To prevent the rest of the form being submitted, use the execute attribute like with an f:ajax call (process attribute on p:remoteCommand) or use separate forms

method of including data in a url

URLs include data about where have you been in a website and when you re-visit, they show the exact information. For example I was in Google Maps, searched "Barcelona" and then "fly" to the Isle Of Man. If you open this url https://www.google.com/maps/place/Barcelona/#54.2584676,-4.4790783,10z/data=!4m2!3m1!1s0x12a49816718e30e5:0x44b0fb3d4f47660a you will see Barcelona in the search box (place/Barcelona) but the map will zoom in the Isle Of Man (#54.2584676,-4.4790783 lon-lat I guess)?
So it shows you where I have been, not just a map and an empty search box. This happens to most websites, urls include data about photos, profiles, modules etc. I am not talking about simple anchors like (site.com/page.html#header). I am NOT talking about AJAX.
I want to learn more on how you can store data in a url and when you visit it, the page loads specific parts AND data.
What is the name of that method? How does it work? How do I implement it?
One of the things I believe you're referring to is the GET method.
To add data to the query string (that's what the string is called that is usually after the question mark (?) and the divided by the and sign (&) depending on the number of attributes you want to pass to it.
One way of passing attributes to the query string is by using the GET method in a form for example as follows:
<form method="get" action="other-page.php">
<input name="example" type="text" />
<input name="other" type="text" />
<input name="submit" type="submit" value="submit" />
</form>
Once you click submit on the above form, the name attributes of the inputs will become the attributes of the query string and their values will be whatever has been added as value for those fields. So if you filled in 'this' for example and 'that' for other, then the query string would look like this:
domain.com/page?example=this&other=that
This information can then be retrieved on the other page that the form has been sent to (you will see the name of that other page under action="other-page.php in the form tag).
Assuming it's a page written in php, this is how you can get the values of the attributes:
echo $_GET['example']; // this would output 'this'
echo $_GET['other']; // this would output 'that'
In your example, google for example uses the lon and lat attributes to place you on the right spot on the map. Though looking at their query string, they look like using a different method than the classic GET as I explained above.
The hashtag however (#) is there to point to specific sections of a page (assuming it's not being manipulated by some javascript code, but that's a whole different story). If you setup a link like this one:
Click here to go to section 2
...then further down on the page you added...
<a id="section2"></a>
...and clicked the link above, the page would jump down to section 2 for you.
Please have a look at the history-API, espacially history.pushState():
https://developer.mozilla.org/de/docs/Web/Guide/DOM/Manipulating_the_browser_history#Adding_and_modifying_history_entries

calling a method with jsf 2.0 ajax library

I am working on an application where users will be evaluating a piece of art and filling out a review form as they go along. They may spend a substantial amount of time on the form, so I want to save it automatically for the user, say every 5 minutes. I was hoping I could use javascript and set a timer for the 5 minutes and then have it basically execute the entire form via ajax and I could save the data to the database in case the user gets disconnected, etc. Unfortunately I cannot seem to find any way to do this. Getting the model updated with the data is not a problem, but I can't figure out how to get it to invoke the method (similar to how the action normally would when it was submitted.) I don't want or need it to re-render anything, just let me call a method to save the data. How can I do this?
Problems implementing the solution
I tried implementing the solution of the hidden command link but I'm getting some very strange behavior. I am not sure what is causing this. First, some background on the implementation. Form #1 creates a bean (None scoped) and puts it into the flash, then redirects to Form #2. Form #2 is the big form I was writing about, where I want to implement the auto-save. Form #2 has a ViewScoped bean. In the PostConstruct for this bean, it retrieves the value from flash, and populates a property field. So far so good. This works perfectly without the javascript. I can press the command button to submit the form, and all is well. However, when I introduce the javascript, when it executes I get a null pointer exception from the variable that should have been populated from the flash by the PostConstruct. How is this javascript interfering with that? Once I have populated the property of view scoped bean with the object, it should not matter if its removed from flash scope, right? FYI if I remove ONLY the javascript code and leave everything else it goes back to working fine when I press the button to submit.
Form #1
<h:form>
... bunch of form objects ...
<h:commandButton "Start New" action="#{someRequestScopedBean.someMethod"/>
</h:form>
code for someRequestScopedBean.Method:
public String someMethod() {
// bunch of logic here
FacesContext.getCurrentInstance()
.getExternalContext()
.getFlash()
.put("myFlashObj", myFlashObj);
return "form2?faces-redirect=true";
}
view scoped bean used in form 2:
#ManagedBean
#ViewScoped
public class someViewScopedBean {
//bunch of properties here
#PostConstruct
public void initialize() {
this.myObject = (MyObject) FacesContext.getCurrentInstance()
.getExternalContext()
.getFlash()
.get("myFlashObject");
public void saveDraft() {
// save to database
}
}
Form 2 page:
<h:outputScript library="javax.faces" name="jsf.js"/>
<h:form id="myForm">
... whole bunch of fields here ...
... real button for user to submit ...
<h:commandButton value="Submit myForm"
action="#{someViewScopedBean.save}" />
... hidden button for auto-save by javascript ...
<h:commandLink id="hiddenSaveDraft" style="display: none;"
action="#{someViewScopedBean.saveDraft}" >
<f:ajax execute="#form" />
</h:commandLink>
<script>
function saveDraft() {
document.getElementById('qForm:hiddenSaveDraft').onclick();
window.setTimeout('saveDraft()',15000);
}
saveDraft();
</script>
</h:form>
Since you wrote down Javascript as one of your tags i'm going to assume you incorporate Client side Javascript code in your app.
First of all use a hidden <h:commandButton/> or a hidden <h:inputText/> ( I use the latter in cases where I need to hold some information regarding a certain variable)
In the form you are submitting add one of these:
<h:commandButton style="display:none" id="clickme">
<f:ajax execute="#form">
</h:commandButton>
<h:inputText style="display:none" id="changeme">
<f:ajax execute="#form">
</h:inputText>
In your Javascript code add this code to either click or change:
setInterval(function() {
document.getElementById("clickme").onclick();
}, 3000); // update every 3 seconds
setInterval(function() {
document.getElementById("changeme").onchange();
}, 3000); // update every 3 seconds
Both will work fine. Just make sure they are within the form you are updating.
I figured out the final solution, and the cause of problems I had implementing it the first time around. It had to do with WHEN the javascript was being fired. The script code was being fired at the exact point I placed the <script></script> block, which was before the page was completely loaded and probably before the DOM was complete. This was causing all kinds of nasty, including duplicate invocations of #PostConstruct.
I fixed it by using a javascript event listener to fire when the page was completely loaded. This is important because I am using facelets templating, and I didn't have access to the <h:body onload= attribute. The listener is a useful and elegant solution. The script block can be placed anywhere in the page. Here is what the script block looks like:
<script>
function saveDraft() {
document.getElementById('qForm:saveDraft').onclick();
window.setTimeout(saveDraft,300000);
}
function initSaveTimer(e) {
window.setTimeout(saveDraft,300000);
}
this.addEventListener("load",initSaveTimer,true);
</script>
This will invoke the hidden button every 5 minutes to save the form.

a4j:param not invoking my javascript pointed to by value attribute

I am open to a different way to do this, but what I have seems like it should work from the documentation for RichFaces4 and JSF2.
The user flow is like this:
1) There is a 'Check Out' document link implemented with h:outputLink
2) The user clicks it and gets prompted with a dialog to enter check out comments implemented with rich:popupPanel
3) The user enters comments and clicks 'Continue' Button on the rich:popupPanel implemented with h:link (tried h:commandLink and a4j:commandLink also)
4) A new window pops up with the contents set to the h:link outcome attribute
In my broken case, everything works except when I pass a parameter from h:link
with a4j:param, whose value attribute does not resolve the javascript it points to correctly.
<h:outputLink id="promptForCommentsLink"
onclick="#{rich:component('commentsDlg')}.show();return false;"
value="#"> Check Out </h:outputLink>
<rich:popupPanel id="commentsDlg" modal="true">
<h:inputTextarea id="commentsId"/>
<h:link id="continueLink"
outcome="editorPage" <!-- editor for making changes to document -->
target="_blank" <!-- open in it;s own indow -->
value="Continue Check Out"
onclick="#{rich:component('commentsDlg')}.hide();">
<!-- these params get assignd to backing bean properties -->
<a4j:param name="dataId"
value="#{ithRow.id}" assignTo="#{myController.dataId}"/>
<a4j:param name="checkedOut"
value="true" assignTo="#{myController.checkedOut}"/>
<!-- this one is broken. assigns chars 'document.getElementById('..
to #{myController.checkOutComment} -->
<a4j:param name="checkOutComment"
assignTo="#{myController.checkOutComment}"
noEscape="true"
value="document.getElementById('myForm:dataTable:0:commentsId').value"
/>
</h:link>
</rich:popupPanel>
I was thinking maybe
document.getElementById('myForm:dataTable:0:commentsId').value
didn't point to what I typed into the textarea, but by putting another button on the dlg and pointing it's onclick to the same element id, it did indeed alert me with what it typed.
When I stop on the server side view scoped myController.setCheckOutComment(String s) method, it gets passed the string "document.getElementById('myForm:dataTable:0:commentsId').value"
According to RF4 documentation:
The a4j:param tag can be used with non-Ajax components in addition to Ajax components. This includes components which are working through the GET request, such as the h:link
and
Variables from JavaScript functions can be used for the value attribute. In such an implementation, the noEscape attribute should be set to true. Using noEscape="true", the value attribute can contain any JavaScript expression or JavaScript function invocation, and the result will be sent to the server as the value attribute.
Since I seem to be playing by the jsf/rf4 rules, I thought this would be okay.
One thing to note, if I use a4j:commandLink instead of h:link, it does indeed
send the result of javascript evaluated, however, that breaks the opening in its own window
and a few other issues.
Any thoughts on what might be happening, or even a better way to do this?
You could use a a4j:jsFunction with the parameters you need. Then call that function from the onclick in the h:link tag like setParams(#{ithRow.id}, true). Problem remain that you can't pass the value as a parameter to the javascript function. You could though use 'execute' to save the value of the inputArea to a backing bean and let the backend handle the value.
So yes, I would do it differently. I think you could handle the two other params at the backend and I would use 'execute' to store the value of the inputArea.
MAG,
Milo van der Zee

Categories