I am trying to create an interactive chat web application using Java EE 7, in particular using JSF 2.2 with ajax.
The idea is that there is always one slow pending asynchronous ajax request waiting
on the server for each individual client. Once a new message arrives to the server,
all waiting requests are returned so that the messages are rendered in all clients.
On completion of the requests, new waiting requests are sent by the clients.
If no message arrives within 30 seconds, the request is returned so that a new one
can be submitted before the old one times out.
I could make it work like this:
index.xhtml:
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core">
<h:head>
<title>async jsf app</title>
<h:outputScript library="js" name="resendscript.js" />
</h:head>
<h:body>
async jsf app
<h:form id="jsfappform">
say something:
<h:inputText id="newmsg" value="#{jsfAsync.newMessage}" />
<h:commandButton id="sendbut" value="say" action="#{jsfAsync.say}" />
<br /><br />
Messages:
<br /><br />
<h:outputText id="msgs" value="#{jsfAsync.msgs}" escape="false">
<h:outputScript>resendRequest()</h:outputScript>
</h:outputText>
<h:commandButton id="reloadbut" value="" action="#{jsfAsync.resend}" style="visibility: hidden">
<f:ajax execute="#this" render="msgs" onevent="handleAjax" onerror="handleError" />
</h:commandButton>
<h:commandButton id="clearbut" value="clear" action="#{jsfAsync.clear}" />
<h:outputScript>resendRequest()</h:outputScript>
</h:form>
</h:body>
</html>
resendscript.js:
function handleAjax(data)
{
var status = data.status;
switch(status)
{
case "success": resendRequest();
break;
}
}
function handleError(data) { }
function resendRequest()
{
document.getElementById("jsfappform:reloadbut").click();
}
backing bean JsfAsync.java:
package jsfasync;
import java.util.ArrayList;
import java.util.List;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ApplicationScoped;
#ManagedBean
#ApplicationScoped
public class JsfAsync
{
private final List<String> messages;
private final Object wakeup;
public JsfAsync()
{
wakeup = new Object();
messages = new ArrayList<String>();
}
public void setNewMessage(String msg)
{
synchronized(messages) { messages.add(msg); }
}
public void say()
{
synchronized(wakeup) { wakeup.notifyAll(); }
}
public void resend()
{
try {
synchronized(wakeup) { wakeup.wait(30000); }
} catch (Exception e) { }
}
public void clear()
{
synchronized(messages) { messages.clear(); }
say();
}
public String getNewMessage() { return ""; }
public String getMsgs()
{
StringBuilder msgs = new StringBuilder();
synchronized(messages)
{
for (String m : messages)
{
msgs.append(m);
msgs.append("<br />");
}
return msgs.toString();
}
}
}
I would like to replace the body of the resendRequest() javascript function with the ajax request API as follows:
jsf.ajax.request('jsfappform:reloadbut', null,
{'javax.faces.behavior.event': 'action',
'execute': 'jsfappform:reloadbut',
'render': 'jsfappform:msgs',
'onevent': 'handleAjax',
'onerror': 'handleError'});
Unfortunately, I can't get it work this way. The call can perform the ajax request, but it seems the onevent option was ignored, and the event handler was not called when this request completed. Do you, perhaps, have any hints how to make it work in this way?
For hints, check the generated HTML source of <h:commandButton id="reloadbut">. You'll see that JSF has generated it as 'onevent': handleAjax. Indeed, as function reference instead of as a string.
Fix it accordingly:
jsf.ajax.request('jsfappform:reloadbut', null,
{'javax.faces.behavior.event': 'action',
'execute': 'jsfappform:reloadbut',
'render': 'jsfappform:msgs',
'onevent': handleAjax,
'onerror': handleError});
Related
I am facing a problem passing string to HTML page through javascript.
I have a window form,
A HTML file, where I have my Javascript and HTML code.
In the function in C# page, I have a string that I need to send to the HTML page through javascript. But I can not pass it. Please advise me.
Thanks
My C# method code below
private void Form1_Load(object sender, EventArgs e)
{
Assembly assembly = Assembly.GetExecutingAssembly();
StreamReader reader = new StreamReader(assembly.GetManifestResourceStream("ProjectName.Maps.html"));
webBrowser1.DocumentText = reader.ReadToEnd();
***//pass getDefaultMap() value (str) to the javascript in Maps.html page.***
}
private string getDefaultMap()
{
string str;
str = (#"Exec SP_Map_Display #Opt=1");
return str ;
}
My HTML page is below
<body>
<script>
$(document).ready(function () {
$("#btnSubmit").click(function () {
***// Get the data from C# code str***
}
</script>
<input type="button" name="btnSubmit" value="Submit" />
<div id="dvMap">
</div>
</body>
Assuming this is WinForms since there's a WebBrowser control, to call C# code from the HTML page JavaScript can be accomplished with this minimum example:
Simple HTML page added to the root of the project and Properties was setup to Copy to Output Directory: Copy if newer this will ensure there's a simple page for testing:
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
<title>WebForms WebBrowser Control Client</title>
</head>
<body>
<input type="button" onclick="getLocations()" value="Call C#" />
<script type="text/javascript">
function getLocations() {
var locations = window.external.SendLocations();
alert(locations);
}
</script>
</body>
</html>
The JS function getLocations will call C# method SendLocations, the important parts are the Form1 class annotations and setting webBrowser1.ObjectForScripting = this :
using System.Windows.Forms;
using System.Security.Permissions;
using System.IO;
[PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
[System.Runtime.InteropServices.ComVisibleAttribute(true)]
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
webBrowser1.ObjectForScripting = this;
var path = Path.GetFullPath("Client.html");
var uri = new Uri(path);
webBrowser1.Navigate(uri);
}
public string SendLocations()
{
return "SF, LA, NY";
}
}
Clicking the HTML button Call C# will show a popup with the return value from C# method
I'm trying to integrate Stripe into my JSF application and am having difficulty navigating away from the "add credit card" page. Everything works, except after the user hits submit, the page does not navigate away.
Below is the addCreditCard.xhtml facelet. Adding the javascript logic as a submit eventListener and triggering the bean update method() using onclick="#{stripeCCBean.update()}" was the only way I could get the javascript to successfully create the token (the createToken method would fail if the javascript was triggered by onclick for some unknown reason) AND get the bean to recognize the hidden fields.
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
template="/WEB-INF/template.xhtml"
xmlns:pt="http://xmlns.jcp.org/jsf/passthrough"
xmlns:c="http://xmlns.jcp.org/jsp/jstl/core">
<head>
<title>Facelet Title</title>
<link rel="stylesheet" type="text/css" href="/css/StripeCCTokenize.css"/>
<script src="https://js.stripe.com/v3/" type="text/javascript"></script>
<script src="https://code.jquery.com/jquery-3.2.0.js" type="text/javascript"></script>
<script src="/js/StripeCCTokenize.js" type="text/javascript"></script>
</head>
<h:body>
<h:form id="addCC" pt:action="/secure/addCreditCard.xhtml" pt:method="POST">
<h:inputHidden id="cardholder-name" value="#{userManagerBean.user.fullName}"/>
We loaded your customer details (name, email and customer ID) from the backend database:
<label>
Hello #{userManagerBean.user.firstName} #{userManagerBean.user.lastName}
</label>
<label>
E-Mail - #{userManagerBean.user.email}
</label>
<label>
Stripe Customer ID - #{userManagerBean.stripeUser.id}
</label>
<h:outputText value="Please enter the requested credit card and billing information below"/>
<span>Address</span>
<h:panelGrid columns="2">
<h:outputText value="Address" />
<h:inputText class="field" id="address1" value="#{stripeCCBean.card.address1}" pt:placeholder="Street address"/>
<h:outputText value="Address"/>
<h:inputText class="field" id="address2" value="#{stripeCCBean.card.address2}" pt:placeholder="Street address"/>
<h:outputText value="City" />
<h:inputText class="field" id="city" value="#{stripeCCBean.card.city}" pt:placeholder="city"/>
<h:outputText value="State" />
<h:inputText class="field" id="state" value="#{stripeCCBean.card.state}" pt:placeholder="state"/>
<h:outputText value="zip" />
<h:inputText class="field" id="address-zip" value="#{stripeCCBean.card.zipcode}" pt:placeholder="zipcode"/>
<h:outputText value="cc"/>
</h:panelGrid>
<div id="card-element" class="field"></div>
<h:commandButton value="Add Credit Card" onclick="#{stripeCCBean.update()}" type="submit" id="addButton"/>
</h:form>
</h:body>
Here is the StripeCCTokenize.js:
var stripe; var card;
$(document).ready(function () {
stripe = Stripe('pk_test_key');
var elements = stripe.elements();
card = elements.create('card', {
hidePostalCode: true,
style: {
base: {
iconColor: '#F99A52',
color: '#32315E',
lineHeight: '48px',
fontWeight: 400,
fontFamily: '"Helvetica Neue", "Helvetica", sans-serif',
fontSize: '15px',
'::placeholder': {
color: '#CFD7DF'
}
}
}
});
card.mount('#card-element');
function stripeTokenHandler(token) {
// Insert the token ID into the form so it gets submitted to the server
var form = document.getElementById('addCC');
var hiddenInput = document.createElement('input');
hiddenInput.setAttribute('type', 'hidden');
hiddenInput.setAttribute('name', 'stripeToken');
hiddenInput.setAttribute('value', token.id);
form.appendChild(hiddenInput);
// Submit the form
form.submit();
}
function setOutcome(result) {
if (result.token) {
// Use the token to create a charge or a customer
// https://stripe.com/docs/charges
console.log("Token: " + result.token.id);
stripeTokenHandler(result.token);
}
}
card.on('change', function (event) {
setOutcome(event);
});
document.querySelector('form').addEventListener('submit', function (e) {
e.preventDefault();
var extraDetails = {
address_line1: document.getElementById('addCC:address1').value,
address_line2: document.getElementById('addCC:address2').value,
address_city: document.getElementById('addCC:city').value,
address_state: document.getElementById('addCC:state').value,
address_zip: document.getElementById('addCC:address-zip').value,
name: document.getElementById('addCC:cardholder-name').value
};
console.log(extraDetails);
stripe.createToken(card, extraDetails).then(setOutcome);
});
});
Here is the stripeCCBean class:
import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.RequestScoped;
import javax.faces.context.FacesContext;
import lombok.Data;
import lombok.ToString;
#Data
#ToString
#RequestScoped
#ManagedBean(name = "stripeCCBean")
public class StripeCCBean implements Serializable {
StripeCard card;
#ManagedProperty(value = "#{stripeServiceBean}")
private StripeServiceBean stripeServiceBean;
#ManagedProperty(value = "#{userManagerBean}")
private UserManagerBean userManagerBean;
#PostConstruct
public void init() {
System.out.println("StripeCCBean.init()");
card = new StripeCard();
card.setName(userManagerBean.getUser().getFullName());
}
public void update() throws IOException {
String token = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("stripeToken");
if (token == null) {
return;
}
System.out.println("StripeCCBean.update()");
System.out.println("Token: " + token);
System.out.println("Card: " + card);
try {
StripeService.addCard(userManagerBean.getStripeUser().getId(), token);
} catch (AuthenticationException | APIConnectionException | CardException | APIException | InvalidRequestException ex) {
ex.printStackTrace();
}
}
}
I tried adding action="#{stripeCCBean.viewAccount()}" to the <h:commandButton .../> and the corresponding method to the StripeCCBean:
public String viewAccount() {
return "AccountView";
}
However the form simply runs the Javascript, calls the stripeCCBean.update() (everything works) and then stays on that page. The customer information fields do not get cleared, however the credit card element does.
I tried adding FacesContext.getCurrentInstance().getExternalContext().redirect("/secure/AccountView.xhtml");
as well as
FacesContext.getCurrentInstance().getExternalContext().dispatch("/secure/AccountView.xhtml"); to the stripeCCBean.update() method and neither works. In fact, they throw an exception.
Can anyone see what I'm doing wrong? If I'm triggering the JS incorrectly or inefficiently, I'm happy to change that as well.
Another one of those "I have no idea why this worked", but I tried adding FacesContext.getCurrentInstance().getExternalContext().redirect("/secure/AccountView.xhtml"); to the end of the stripeCCBean.update() method and now it works.
Still no idea why I have to have the update() method called via the commandButton's onclick though...
Please remove the preventDefault function which prevents the browse default behaviour and you need not use the onclick event.
If you want to navigate by a f:commandButton / f:commandLink, use the action attribute instead of onclick.
<f:commandButton ... action="#{myBean.actionHandler}".../>
If you don't use any ajax mechanism, the bean can be #RequestScoped, other case #ViewScoped
#Named
#RequestScoped
public class MyBean
{
public String actionHandler()
{
...
return "navigationRuleName";
}
...
}
Where navigationRuleName is registered in the faces-config.xml:
<navigation-rule>
<from-view-id>/path/source.xhtml</from-view-id>
<navigation-case>
<from-outcome>navigationRuleName</from-outcome>
<to-view-id>/path/targetPageName.xhtml</to-view-id>
<redirect/>
</navigation-case>
</navigation-rule>
Or it can be a page name:
#Named
#RequestScoped
public class MyBean
{
public String actionHandler()
{
...
return "/path/targetPageName.xhtml?faces-redirect=true";
}
...
}
Or the xhtml extension can be omitted.
The '' entity or the faces-redirect=true parameter necessary if you want the location URL of the browser changing to targetPageName.xhtml after the HTTP POST request-response navigation. Redirection do it by another HTTP GET call after the HTTP POST one.
I'm using p:remoteCommand,its working fine for update and process except its not invoking either action method nor actionListener
Xhtml Code
<h:form id="mainForm">
<h:outputLabel id="tempAge" value="#{remoteBean.tempAge}"/>
<h:inputText id="age" value="#{remoteBean.age}" onkeypress="callRem()">
<f:validateLongRange minimum="18"/>
</h:inputText>
<script type="text/javascript">
var timex=0;
function callRem(){
clearTimeout(timex);
timex = setTimeout("remote()",2000);
}
</script>
<p:remoteCommand name="remote"
process="age"
update="tempAge"
action="#{remoteBean.act}"
actionListener="#{remoteBean.listen}">
</p:remoteCommand>
</h:form>
Managed Bean Code
#ManagedBean
public class RemoteBean {
private int age=18;
private int tempAge=20;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
System.out.println("Setting age :"+age);
}
public int getTempAge() {
return tempAge;
}
public void setTempAge(int tempAge) {
this.tempAge = tempAge;
}
public void act(){
System.out.println("in action()");
tempAge+=age+2;
}
public void listen(ActionEvent event) {
System.out.println("in Action Listener");
tempAge+=age+2;
}
}
I can't figure out where I'm doing wrong, may be its the Javascript code i've written.
If anyone faces and solved same issue please help.
Using: Primefaces 3.5
I tried yours example and found problem.
Seemse when you processing only age (process="age"), it executes only age input and ignores remoteCommand actionListener and action.
So you can change it to:
process="#form"
or
process="#this age"
worked both for me.
ps. I used View scope here.
I want my web application to print w popup page just after appearance automatically without asking the client to choose with printer to be choose.
how can I handle silent printing in ASP.Net with java-script or ajax or what is the most suitable solution for this case?
You can't and for good reasons, such as:
The user should always be able to choose which printer they want to use.
The user should always be able to choose whether they print something or not (imagine the spam that would constantly fly out of your printer otherwise)
Some third party controls are available for this(in WPF). Please check whether this is useful in asp.net also.
http://www.textcontrol.com/en_US/support/documentation/dotnet/n_wpf_printing.printing.htm
//OnTouchPrint.aspx.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Drawing.Printing;
using System.IO;
using System.Drawing;
namespace TokenPrint
{
public partial class Try : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
}
}
private void printDocument1_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)
{
Graphics g = e.Graphics;
SolidBrush Brush = new SolidBrush(Color.Black);
string printText = TextBox1.Text;
g.DrawString(printText, new Font("arial", 12), Brush, 10, 10);
}
protected void Press_Click(object sender, EventArgs e)
{
try
{
string Time = DateTime.Now.ToString("yymmddHHMM");
System.Drawing.Printing.PrinterSettings ps = new System.Drawing.Printing.PrinterSettings();
ps.PrintToFile = true;
// ps.PrintFileName = "D:\\PRINT\\Print_"+Time+".oxps"; /* you can save file here */
System.Drawing.Printing.PrintDocument pd = new System.Drawing.Printing.PrintDocument();
pd.PrintPage += new PrintPageEventHandler(printDocument1_PrintPage);
System.Drawing.Printing.StandardPrintController printControl = new System.Drawing.Printing.StandardPrintController();
pd.PrintController = printControl;
pd.DefaultPageSettings.Landscape = true;
pd.PrinterSettings = ps;
pd.Print();
TextBox1.Text = "";
ScriptManager.RegisterClientScriptBlock(this, this.GetType(), "alertMessage", "alert('Printed Successfully.Check: Drive D')", true);
}
catch (Exception ex)
{
}
}
protected void Button1_Click(object sender, EventArgs e)
{
Response.Redirect("Try.aspx");
}
}
}
//OnTouchPrint.aspx
<%# Page Language="C#" AutoEventWireup="true" CodeBehind="OnTouchPrint.aspx.cs" Inherits="TokenPrint.Try" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<asp:TextBox ID="TextBox1" runat="server" Width="235px" Height="142px"
TextMode="MultiLine"></asp:TextBox>
<br />
<br />
<asp:RequiredFieldValidator ID="RequiredFieldValidator1" runat="server"
ControlToValidate="TextBox1" ErrorMessage="Empty message can not be printed!"
ValidationGroup="vgp1"></asp:RequiredFieldValidator>
<br />
<br />
<asp:Button ID="Press" runat="server" Text="Press" onclick="Press_Click"
ValidationGroup="vgp1" />
<asp:Button ID="Button1" runat="server" onclick="Button1_Click" Text="Refresh"
ValidationGroup="vgp2" />
</form>
</body>
</html>
I know you cant save javascript variables into server side variables (vbscript) directly, but is there a way around this like saving java script variables into html hidden inputs then using javascript to post. Is this possible? If not what else can i do? Below is my code so far get the value of a drop down list - javascript
function selectedDatabase() {
select_temp = form1.elements["selection"];
select_index = select_temp.selectedIndex;
select_text = select_temp.options[select_index].text;
}
Below is the HTML code
<center><select id="selection" onchange="selectedDatabase()">
<option>Movies</option>
<option>Movies 2</option>
<option>New Movies</option>
<option>New Movies 2</option>
</select></center>
</td></tr>
What you're looking for is called ajax. You can do it manually, or better use a JavaScript library such as MooTools, jQuery, or Prototype.
Check out Google University's Ajax tutorial. I would avoid w3schools' tutorials.
Just to cover all the bases, why can't you just have the user submit the form?
Also, you could do this with cookies, though you won't get the cookie values on the server until the next GET or POST from the user.
It is Possible to store javascript variable values into server side variable. All you have to do is to implement "System.Web.UI.ICallbackEventHandler" class.
Below is the code demonstrating how to do it.
In aspx Page:
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<title>Client Calback Example</title>
<script type="text/ecmascript">
function LookUpStock()
{
var lb=document.getElementById("tbxPassword");
var product=lb.value;
CallServer(product,"");
}
function ReceiveServerData(rValue){
}
</script>
</head>
<body>
<form id="form1" runat="server">
<div>
<input type="password" id="tbxPassword" />
<input type="Button" onclick="LookUpStock">Submit</button>
</div>
</form>
</body>
**
In Code Behind (CS) Page
**
public partial class _Default : System.Web.UI.Page,System.Web.UI.ICallbackEventHandler
{
protected String returnValue;
protected void Page_Load(object sender, EventArgs e)
{
String cbReference = Page.ClientScript.GetCallbackEventReference
(this,"arg", "ReceiveServerData", "context");
String callbackScript;
callbackScript = "function CallServer(arg, context)" +
"{ " + cbReference + ";}";
Page.ClientScript.RegisterClientScriptBlock(this.GetType(),
"CallServer", callbackScript, true);
}
public void RaiseCallbackEvent(String eventArgument)
{
if(eventArgument == null)
{
returnValue = "-1";
}
else
{
returnValue = eventArgument;
}
}
public String GetCallbackResult()
{
return returnValue;
}
}
Now you can get the JavaScript variable "product" value into Server side variable "returnValue".