So I am integrating my angular application into a payment gateway, in certain instances there is an additional security check required by the payment processor. For anyone interested, its a 3D Secure implementation.
I can perform the post request no problem, but the value returned from my provider is simply....
<html>
<head>
<title>Redirecting...</title>
I was hoping it would return full html that I could just render in a modal, no such luck.
So I tried to create an iframe to post into and handle this (like the old school days) but I can't get this to work. My code so far...
Component
export class CheckoutComponent implements OnInit {
#ViewChild('form') postForm: ElementRef;
private MD: any;
private PaReq: any;
private TermUrl: any;
private demoEndpoint: any;
#ViewChild('threedsModal', { static: true }) private threedsModal;
constructor(
private http: HttpClient,
) { }
ngOnInit(): void {
this.demoEndpoint = 'www.example.com/post/'
this.MD = 'foo';
this.PaReq = 'bar';
this.TermUrl = 'www.myexample.com/response';
}
onLoad() {
console.log('onLoad triggered.');
}
// Called from another part of the code when we need to perform the POST
submitForm(){
// values are custom encoded, not needed to show for example
const myParams = new HttpParams({encoder: new HttpUrlEncodingCodec()})
.set('MD', this.MD)
.set('PaReq', this.PaReq)
.set('TermUrl', this.TermUrl);
this.http.post(this.demoEndpoint, myParams, {responseType: 'text'}).subscribe(x => console.log(x));
return true;
}
}
Then in my template:
<iframe class="custom-frame" #frame width="400" height="400" id="frame" name="frame"
frameborder="0" [src]="demoEndpoint | safeResourceUrl" (load)="onLoad()"></iframe>
<form target="frame" action="demoEndpoint| safeResourceUrl" #form method="POST">
<input type="hidden" name="MD" value={{MD}} id="MD" />
<input type="hidden" name="PaReq" value={{PaReq}} id="PaReq" />
<input type="hidden" name="TermUrl" value={{TermUrl}} id="TermUrl" />
</form>
But this iframe simply renders "Unable to determine the request"
If I perform the POST request manually in postman, in renders the correct HTML, but the response from my httpPOST in console just shows Re-directing.
So my question, how can I achieve this in an iframe and render the correct response?
EDIT: This question helped me somewhat
So for the help of anyone in the future, this was fairly easy with the help of this answer
// create a form for the post request
const form = window.document.createElement('form');
form.setAttribute('method', 'post');
form.setAttribute('action', 'http://post.example.com');
// use _self to redirect in same tab, _blank to open in new tab
// form.setAttribute('target', '_blank');
form.setAttribute('target', 'threedframe');
// Add all the data to be posted as Hidden elements
form.appendChild(this.createHiddenElement('MD', 'foo'));
form.appendChild(this.createHiddenElement('PaReq', 'bar'));
form.appendChild(this.createHiddenElement('TermUrl','https://dump.example.com'));
console.log(form);
window.document.body.appendChild(form);
form.submit();
// create the form
private createHiddenElement(name: string, value: string): HTMLInputElement {
const hiddenField = document.createElement('input');
hiddenField.setAttribute('name', name);
hiddenField.setAttribute('value', value);
hiddenField.setAttribute('type', 'hidden');
return hiddenField;
}
Then setup an iframe in my template:
<iframe class="custom-frame" id="three-d-frame" width="430" height="450" frameborder="0" name="threedframe">
Related
I am integrating jquery and zk project.
My goal is to pass value from js/jquery side to java side but in vain.
Here is the code I reference: use zAu to send data from client to server
However, there exists the error:
java.lang.ClassCastException: org.zkoss.zk.ui.event.MouseEvent cannot be cast to org.zkoss.zk.ui.event.ForwardEvent
I have seen some other person saying that we must cast the mouseevent to forwardevent in order to get a NOT NULL getData() value.
At my java side:
public class TryHttpLenovo extends SelectorComposer<Component> {
#Listen("onClick=#btnHttp")
public void serverReceive(Event e) {
ForwardEvent forwardE = (ForwardEvent) e;
System.out.println("forwardE.getData()"+forwardE.getData());
}
}
In my http.zul:
<window apply="foo.TryHttpLenovo" xmlns:w="client">
<button id="btnHttp" w:onClick="sentToServer();">http send</button>
</window>
In my testhttp.js:
function sentToServer(){
var wgt=zk.Widget.$('btnHttp');
zAu.send(new zk.Event(wgt, "serverReceive", {foo: 'my data'}, {toServer:true}));
}
After several trial-and-error, I finally solve this!!!!
The solution is to extend GenericForwardComposer.
I also adjust some other things, but the only important change is to extend GenericForwardComposer instead of SelectorComposer.
The #Listen annotation is not needed in my solution.
in .java
public class TryHttpV2 extends GenericForwardComposer {
public void onUser2$info(Event event) {
ForwardEvent forwardE = (ForwardEvent) event;
System.out.println("forwardE.getOrigin().getData(): " + forwardE.getOrigin().getData());
}
}
in .js
function sendToServer(){
payload = "using generic composer";
zAu.send(new zk.Event(zk.Widget.$(this), 'onUser2', payload));
}
in .zul
<?page title="try using generic composer" contentType="text/html;charset=UTF-8"?>
<?script src="/js/tryhttp_v2.js" ?>
<zk xmlns="http://www.zkoss.org/2005/zul">
<window id="info" apply="foo.TryHttpV2" xmlns:w="client">
<button id="btnExec" w:onClick="sendToServer();" label="to be tested button" />
</window>
</zk>
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 am running into an issue where all google app endpoints are running smoothly. No issue at getting, updating or deleting entries while using the API explorer.
I am running into issue when trying to mesh all this together in an html file.
Updates and deletes work fine... Only get/list methods are returning no record.
Any idea what the issue is? What is best to troubleshoot this kind of issue?
Thanks.
test.java
import com.googlecode.objectify.annotation.*;
#Entity
#Index
public class Test {
#Id Long number;
Long number2;
public Test(){
}
public Test(Long number, Long number2){
this.number = number;
this.number2 = number2;
}
public Test(Long number2){
this.number2 = number2;
}
public Long getNumber2() {
return number2;
}
public void setNumber2(Long number2) {
this.number2 = number2;
}
public Long getNumber() {
return number;
}
public void setNumber(Long number) {
this.number = number;
}
}
test.html
<html>
<head>
<title></title>
</head>
<body>
<div>
<form>
<div>
<input type="text" id="insert" value="2"><br><br>
<button type="submit" id="getTestButton" onclick="getTest()" disabled>Get</button>
</div>
</form>
<p id="result"></p>
<hr>
</div>
<!--
Load the Google APIs Client Library for JavaScript
More info here : https://developers.google.com/api-client- library/javascript/reference/referencedocs
-->
<script type="text/javascript">
function init() {
gapi.client.load('testEndpoint', 'v1', enableButton, 'http://localhost:8080/_ah/api');
document.getElementById('getTestButton').onclick = function() {
getTest();
}
}
function enableButton() {
console.log("enabling button");
getTestButton.disabled = false;
}
function getTest() {
console.log("entering getTest function");
var features = {};
features.number2 = document.getElementById("insert").value;
console.log(features);
var req = gapi.client.testEndpoint.getTest(features);
req.execute(function(data) {
console.log(data);
document.getElementById("result").innerHTML = data.number + " " + data.number2;
});
}
</script>
<script src="https://apis.google.com/js/client.js?onload=init"></script>
</body>
</html>
TestEndpoint.java
import com.google.api.server.spi.config.Api;
import com.google.api.server.spi.config.ApiMethod;
import com.google.api.server.spi.config.ApiNamespace;
import java.util.logging.Logger;
import javax.inject.Named;
import com.googlecode.objectify.cmd.Query;
import static com.Backend.OfyService.ofy;
/** An endpoint class we are exposing */
#Api(name = "testEndpoint", version = "v1", namespace = #ApiNamespace(ownerDomain = "Backend.com", ownerName = "Backend.com", packagePath=""))
public class TestEndpoint {
// Make sure to add this endpoint to your web.xml file if this is a web application.
private static final Logger LOG = Logger.getLogger(TestEndpoint.class.getName());
/**
* This method gets the <code>Test</code> object associated with the specified <code>id</code>.
* #param id The id of the object to be returned.
* #return The <code>Test</code> associated with <code>id</code>.
*/
#ApiMethod(name = "getTest")
public Test getTest(#Named("number2") Long number2) {
// Implement this function
LOG.info("***GetTest***NUMBER=" + number2);
Test t = new Test(1L, 2L);
//t = ofy().load().type(Test.class).filter("number2", number2).first().now();
LOG.info("t.getNumber()==> " + t.getNumber().toString());
LOG.info("Calling getTest method");
return t;
}
}
Seems legit to me. To isolate the cause of the error, I would suggest to do the following :
Test your getTest endpoint method through the API explorer, located at http://yourAppAddress/_ah/api/explorer . If it works you know the issue is in your client code.
If it did not work, then the issue is either with the code inside getTest or with the way you use endpoints (or with endpoints itself). To check this, create a pure Java servlet that will call the getTest() method directly, and log the result. If it works you know the issue is either on the way you use endpoints or on endpoints itself.
Sorry I don't have an immediate answer to your question.
EDIT : Since you tell me that the API Explorer test works, I checked your javascript code and there's something weird : you try to get resp.items.length in the callback. But your endpoint method only returns a Test entity, so there are no items attribute.
Can you try this code ?
gapi.client.testEndpoint.getTest(requestData).execute(function(resp) {
console.log(resp);
});
EDIT 2 : So you've found the cause of the issue by yourself : you cannot call the endpoints method before the API client is loaded. Since your method is called by an onClick event, probably on a button, you must do the following :
By default, disable the button
In the gapi.client.load 's callback, enable the button
That way you will be sure to only click on the button when the Google service is initialized.
EDIT 3 : It is actually a problem in your html. You have a submit button, which makes Chrome reload the page. Every time you click the button the page reloads and you never see the result of your endpoint query.
This HTML file works for me on the dev server :
<html>
<head>
<title></title>
</head>
<body>
<div>
<div>
<input type="text" id="insert" value="2"><br><br>
<button id="getTestButton" onclick="getTest()" disabled>Get</button>
</div>
<p id="result"></p>
<hr>
</div>
<!--
Load the Google APIs Client Library for JavaScript
More info here : https://developers.google.com/api-client- library/javascript/reference/referencedocs
-->
<script type="text/javascript">
function init() {
gapi.client.load('testEndpoint', 'v1', enableButton, '/_ah/api');
document.getElementById('getTestButton').onclick = function () {
getTest();
}
}
function enableButton() {
console.log("enabling button");
getTestButton.disabled = false;
}
function getTest() {
console.log("entering getTest function");
var features = {};
features.number2 = document.getElementById("insert").value;
console.log(features);
var req = gapi.client.testEndpoint.getTest(features);
req.execute(function (data) {
console.log(data);
document.getElementById("result").innerHTML = data.number + " " + data.number2;
});
}
</script>
<script src="https://apis.google.com/js/client.js?onload=init"></script>
</body>
</html>
I want to POST form values and display them on another html page using Javascript. No server-side technology should be used. I have a function that posts the values but to read the values to another html page, I think I am missing something. Below is the code.
Any help? Thanks in advance.
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
<title>Untitled Page</title>
<script type="text/javascript">
function post_to_page(path, params, method) {
method = method || "post"; // Set method to post by default, if not specified.
var form = document.createElement("form");
form.setAttribute("method", method);
form.setAttribute("action", path);
form.setAttribute("target", "formresult");
for (var key in params) {
if (params.hasOwnProperty(key)) {
var hiddenField = document.createElement("input");
hiddenField.setAttribute("type", "hidden");
hiddenField.setAttribute("name", key);
hiddenField.setAttribute("value", params[key]);
form.appendChild(hiddenField);
}
}
document.body.appendChild(form);
// creating the 'formresult' window with custom features prior to submitting the form
window.open('target.htm', 'formresult', 'scrollbars=no,menubar=no,height=600,width=800,resizable=yes,toolbar=no,status=no');
form.submit();
}
</script>
</head>
<body>
<form id="form1" action="target.htm" method="post">
<div>
USB No: <input name="usbnum" id="usbnum" type="text"/><br />
USB Code: <input name="usbcode" id="usbcode" type="text"/>
</div>
<button onclick="post_to_page()">Try it</button>
</div>
</form>
</body>
</html>
Here is a simple example of moving data from one Window to another
<!-- HTML -->
<textarea id="foo"></textarea><br/>
<input id="bar" value="click" type="button"/>
and the real code to make it work, which assumes you pass the same origin policy
// JavaScript
var whatever = 'yay I can share information';
// in following functions `wnd` is the reference to target window
function generateWhatever(wnd, whatever) { // create the function actually doing the work
return function () {wnd.document.getElementById('foo').innerHTML = whatever};
} // why am I using a generator? You don't have to, it's a choice
function callWhenReady(wnd, fn) { // make sure you only invoke when things exist
if (wnd.loaded) fn(); // already loaded flag (see penultimate line)
else wnd.addEventListener('load', fn); // else wait for load
}
function makeButtonDoStuff() { // seperated button JS from HTML
document
.getElementById('bar')
.addEventListener('click', function () {
var wnd = window.open(window.location); // open new window, keep reference
callWhenReady(wnd, generateWhatever(wnd, whatever)); // set up function to be called
});
}
window.addEventListener('load', function () {window.loaded = true;}); // set loaded flag (do this on your target, this example uses same page)
window.addEventListener('load', makeButtonDoStuff); // link button's JavaScript to HTML when button exists
You can't get POST values using JavaScript. You can use GET method to pass values.
If you are using html5 you can use localStorage. Otherwise a query string or cookies are your other options.
You said you didn't want the server involved...why are you calling submit?
[Edit]
#Paul S's comment/answer looks very helpful. But you might look at something like the jQuery PostMessage plugin if you need it to be cross browser compatible.
http://benalman.com/projects/jquery-postmessage-plugin/
You don't require a POST request to send data from one page to another. Simply use LocalStorage to do the trick. Just call a Javascript function on form submission. This may help:
HTML:
<form id="form1" action="target.htm" method="post">
<div>
USB No: <input name="usbnum" id="usbnum" type="text"/><br />
USB Code: <input name="usbcode" id="usbcode" type="text"/>
</div>
<button onclick="post_to_page()">Try it</button>
</form>
Javascript:
function post_to_page() {
localStorage.value = "Your content here";
window.location = "nextpage.html";
}
This will save the data locally and go to the next page. In the next page, simply call this function to retrieve the stored data:
function get_stored_data() {
alert(localStorage.value);
}
You can simply assign it to a div, textbox other Javascript variable.
I have a HTML page in which I have a button; pressing that button a javascript function is called - here results a String which is the representation of an xml. I want to represent this xml on the same page with the button, similar with what is in the picture below:!
Here is the simplified code I've tried but did not worked (see under the code the result of it - nothing displayed):
<html>
<head>
<script type="text/javascript">
function xml_test()
{
var xmlString = "<note><name>Kundan Kumar Sinha</name><place>Bangalore</place><state>Karnataka</state></note>";
var my_div = document.getElementById("labelId");
alert(xmlString)
my_div.innerHTML += xmlString;
}
</script>
</head>
<body>
<input type="button" value="TEST" onclick="xml_test()"/>
<br><br>
<label id="labelId">XML: </label>
</body>
</html>
I've tried with an iframe also, but I do not have an file for the src attribute.
What I've tried is:
<html>
<head>
<script type="text/javascript">
function populateIframe() {
var xml = "<?xml version='1.0' encoding='UTF8' standalone='yes'?><note><name>Kundan Kumar Sinha</name><place>Bangalore</place><state>Karnataka</state></note>";
var iframe = document.getElementById('myIframe');
var idoc= iframe.contentDocument || iframe.contentWindow.document; // IE compat
idoc.open("text/xml"); // I know idoc.open(); exists but about idoc.open("text/xml"); I'm not sure if exists;
idoc.write('<textarea name="xml" rows="5" cols="60"></textarea>');
//idoc.write(xml); // doesn't work
idoc.getElementsByTagName('textarea')[0].value= xml;
idoc.close();
}
</script>
</head>
<body onload="populateIframe();">
<iframe id="myIframe" width="900" height="400"></iframe>
</body>
</html>
and the result is:
I've already looked over How to display XML in a HTML page as a collapsible and expandable tree using Javascript?
I took some ideas from here
Thank you for helping me!
Just Create am HttpHandler, and open it in a Iframe:
public class Handler : IHttpHandler
{
#region IHttpHandler Members
public bool IsReusable
{
get { return true; }
}
public void ProcessRequest(HttpContext context)
{
XmlSerializer serializer = new XmlSerializer(typeof(Note));
MemoryStream stream = new MemoryStream();
StreamWriter writer = new StreamWriter(stream, Encoding.Unicode);
serializer.Serialize(writer, new Note() { Name = "Kundan Sinha", Place = "Bangalore", State = "Karnataka" });
int count = (int)stream.Length;
byte[] arr = new byte[count];
stream.Seek(0, SeekOrigin.Begin);
stream.Read(arr, 0, count);
UnicodeEncoding utf = new UnicodeEncoding();
stream.Close();
writer.Close();
context.Response.ContentType = "text/xml;charset=utf-8";
context.Response.Write(utf.GetString(arr).Trim());
context.Response.Flush();
}
#endregion
}
public class Note
{
public string Name { get; set; }
public string Place { get; set; }
public string State { get; set; }
}
You can pass your received xml string to this where I am doing
context.Response.Write('Pass you XML data here');
You must use your favorite JavaScript library with a tree widget to display that XML in tree form.
Note that the "tree-like" view you see is actually IE's default view for XML files. Other browsers will have different views for XML files, and some do not even let you view XML files without a plug-in.
You should not depend on browser-specific functionality if viewing the XML in tree form is important to your page's functionality.
If you, however, just want to press a button and then the whole page gets turned into an XML, then by all means just redirect to that XML URI on button press. IE will show that XML file in tree form, while other browsers may either ask you to download the file, or display the XML file in whatever format that is determined by their plugin's.
I set the xml data in the src attribute:
iframeElement.setAttribute('src', 'data:text/xml,<test>data</test>');