Is there a way to add a custom http header into the request done by an <iframe> when changing the source (src) using javascript?
You can have the results of an ajax request that has custom headers be set as the content of an iframe like so:
$.ajax({
type: "GET",
url: "https://app.icontact.com/icp/a/",
contentType: "application/json",
beforeSend: function(xhr, settings){
xhr.setRequestHeader("some_custom_header", "foo");},
success: function(data){
$("#output_iframe_id").attr('src',"data:text/html;charset=utf-8," + escape(data))
}
});
This is assuming the iframe is pointing at a cross domain src. It is simpler if everything is on the same domain.
Edit: Maybe try this variation.
$.ajax({
type: "GET",
url: "https://app.icontact.com/icp/a/",
contentType: "application/json",
beforeSend: function(xhr, settings){
xhr.setRequestHeader("some_custom_header", "foo");},
success: function(data){
$("#output_iframe_id").attr('src',"/")
$("#output_iframe_id").contents().find('html').html(data);
}
});
Rather than using a data URI, or setting the contents to a string, you can use URL.createObjectURL(), and set it as the src of the iframe.
var xhr = new XMLHttpRequest();
xhr.open('GET', 'some.pdf');
xhr.onreadystatechange = handler;
xhr.responseType = 'blob';
xhr.setRequestHeader('Authorization', 'Bearer ' + token);
xhr.send();
function handler() {
if (this.readyState === this.DONE) {
if (this.status === 200) {
// this.response is a Blob, because we set responseType above
var data_url = URL.createObjectURL(this.response);
document.querySelector('#output-frame-id').src = data_url;
} else {
console.error('no pdf :(');
}
}
}
The object URLs are pretty interesting. They're of the form blob:https://your.domain/1e8def13-3817-4eab-ad8a-160923995170. You can actually open them in a new tab and see the response, and they're discarded when the context that created them is closed.
Here's a full example: https://github.com/courajs/pdf-poc
I ended up going with the approach proposed by the other answers here, that use ajax to get the html string and then directly set the contents of the iFrame.
However, I used the approach posted in this answer to actually set the contents of the iFrame, as I found it worked well cross platform with almost all devices I could dig up.
Tested - successful:
Chrome 54 (desktop) ^
Firefox 49 (desktop) ^
IE 11 (desktop) ^
IE 10 (desktop) in emulation mode ^
Safari/Chrome on iOS 8 (ipad)
Chrome on Android 6 (nexus phone)
Edge on Lumia 950 (Win 10 Phone)
^ confirmed that linked css and js in the content run correctly (others not tested)
Tested - unsuccessful:
IE 9 (desktop) in emulation mode
Safari/Chrome on iOS 7 (iPhone)
So putting them together gives something like this (Note: I havn't actually run this exact code):
$.ajax({
type: "GET",
url: "https://yourdomain.com/gethtml",
beforeSend: function(xhr) {
xhr.setRequestHeader("yourheader", "value");
},
success: function(data) {
var iframeDoc = document.querySelector('#myiframe').contentWindow.document;
iframeDoc.open('text/html', 'replace');
iframeDoc.write(data);
iframeDoc.close();
}
});
Here's an example of setting the iFrame contents in this JS Bin
Edit: Here's the html part
<iframe id="myiframe" src="about:blank"></iframe>
Edit 2:
The solution above appears to no longer be working in Firefox (50.1.0) for some unknown reason. Using the solution in this answer I've now changed to code to the example below, which also seems to be more robust:
$.ajax({
type: "GET",
url: "https://yourdomain.com/gethtml",
beforeSend: function(xhr) {
xhr.setRequestHeader("yourheader", "value");
},
success: function(data) {
var iframe = document.getElementById('myiframe');
iframe.contentWindow.contents = data;
iframe.src = 'javascript:window["contents"]';
}
});
The following code works. It is a modification of the code provided by Matthew Graves, modified to use the srcdoc attribute to solve the problem of CSS and JavaScript references not been ran. Unfortunately, it is only working in Chrome.
$.ajax({
type: "GET",
url: "https://app.icontact.com/icp/a/",
contentType: "application/json",
beforeSend: function(xhr, settings){
xhr.setRequestHeader("some_custom_header", "foo");},
success: function(data){
$("#output_iframe_id").attr('srcdoc',data)
}
});
Edit: Finally, I have resolved the issue of the scripts blocks cross-browser, by reassigning them to the iframe on document.ready function:
$(document).ready(function () {
var doc = $(document);
if (frames.length > 0) {
doc = frames[0].document;
$(doc).find('script').each(function () {
var script = document.createElement("script");
if ($(this).attr("type") != null) script.type = $(this).attr("type");
if ($(this).attr("src") != null) script.src = $(this).attr("src");
script.text = $(this).html();
$(doc).find('head')[0].appendChild(script);
$(this).remove();
});
}
});
Related
I know how to use jQuery well, but I don't know so much pure JavaScript.
This is my jQuery code:
$(document).ready(function() {
$.get('http://jsonip.com/', function(r){
var ip_address = r.ip;
my_function(ip_address);
});
function my_function(ip_address){
var url = "Url_to my server hosted on a different domain";
var data = {number:"1286", ip: ip_address};
$.ajax({
url: url,
type: "POST",
dataType: 'json',
crossDomain: true,
data: {data: data},
success: function (data) {console.log(JSON.stringify(data));},
error: function (xhr, error) {console.log("There was an error and data was not posted.");}});}
});
What it does: it is pasted in any website, then it picks any visitors ip address and send that as JSON to my server as variable data.
Problem: the code is working perfectly okay in some sites but not all the sites due to jQuery dependency. And I want to remove this and use pure JavaScript.
I am getting great answers but CORS is not working, there failing them. I am using different domains since the site we are sending data to is hosted on another server.
As mentioned in my commment above, you do not need the first ajax request as you can get this information from the request headers (PHP Example below) from your AJAX request.
To make sure that your website(s) have jQuery loaded you can run a check in your script and load it in dynamically. Using some code from this answer. See below for an example:
// Anonymous "self-invoking" function
(function() {
// Load the script
var script = document.createElement("SCRIPT");
script.src = 'https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js';
script.type = 'text/javascript';
document.getElementsByTagName("head")[0].appendChild(script);
// Poll for jQuery to come into existance
var checkReady = function(callback) {
if (window.jQuery) {
callback(jQuery);
}
else {
window.setTimeout(function() { checkReady(callback); }, 100);
}
};
// Start polling...
checkReady(function($) {
var url = "Url_to my server hosted on a different domain";
var data = {number:"1286", ip: ip_address};
$.ajax({
url: url,
type: "POST",
dataType: 'json',
crossDomain: true,
data: {data: data},
success: function (data) {console.log(JSON.stringify(data));},
error: function (xhr, error) {console.log("There was an error and data was not posted.");
});
});
})();
To get the IP Address from your ajax request: (PHP) Source
if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
$ip = $_SERVER['HTTP_CLIENT_IP'];
} elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
} else {
$ip = $_SERVER['REMOTE_ADDR'];
}
The annoying part is that you need to do a cross-domain POST to send your data. There's a W3C standard for this called Cross-Origin Resource Sharing (CORS). Check out this tutorial for more info.
You'll want to put this at the bottom of the page. Different browsers handle ready state change events differently, so let's just avoid them.
<script>
// Once the JSONP script loads, it will call this function with its payload.
function getip(ipJson) {
var method = 'POST';
var url = 'URL of your server';
// The XMLHTTPRequest is the standard way to do AJAX. Try to use CORS.
var xhr = new XMLHttpRequest();
if ("withCredentials" in xhr) {
// XHR for Chrome/Firefox/Opera/Safari.
xhr.open(method, url, true);
} else if (typeof XDomainRequest != "undefined") {
// XDomainRequest for IE.
xhr = new XDomainRequest();
xhr.open(method, url);
}
// Create your request body. It has to be form encoded. I'm not sure
// where you get `number` from, so I've hard-coded it.
xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xhr.send('number=1286&ip=' + ipJson.ip);
}
</script>
<!-- Get the IP using JSONP so we can skip implementing that. -->
<script type="application/javascript" src="http://www.telize.com/jsonip?callback=getip"></script>
This probably only works in modern browsers, but it should work in most modern browsers.
Replace $.ready(function...) with document.addEventListener('DOMContentLoaded', function..., false).
Replace $.ajax with XMLHttpRequest:
var xhr = new XMLHttpRequest();
//var data = {number:"1286", ip: ip_address};
var data = new FormData();
data.append("number", "1286");
data.append("ip", ip_address); // As stated by Scriptable in the question comments, your server should be able to get it from the request headers.
xhr.onload = function() { console.log(JSON.stringify(this.response)); };
xhr.onerror = function() { console.log("There was an error and data was not posted.") };
xhr.open("POST", "URL to your server");
xhr.send(data);
I need to send a cross domain request using jQuery AJAX. But it is not working in IE9.
The strange thing is, it works fine when I try it in a standalone HTML file. But breaks when done in a CQ page.
The js code is below:
$.support.cors = true;
$.ajax({
cache: false,
url: "https://www.some.external.web.service",
dataType: "json",
contentType: "application/json; charset=utf-8",
type: "POST",
crossDomain: true,
data: "{"key":"value"}",
processData: false,
success: function (response) { alert("success"); },
error: function (xhr, status, error) { alert("AJAX Error:status: "+ status+ "\nerror: " + error + "\nxhr.status: " + xhr.status + "\nResponseText: \n" + xhr.responseText); }
});
I have tried using datatype as 'jsonp' but still no avail. In IE9, it never returns the 'Success' handler and always goes to the 'error' handler.
The error shown is 'Transport Error'.
The webservice is in https and my page can be either http(author) or http(publish)
I already have the $.support.cors = true; set before the ajax. What am I missing ?
I couldn't use JSONP or XDR because of the GET and text content respectively.
For this, I added an iframe in my page whose HTML resides in the client's server. So we post our data to the iframe and the iframe then posts it to the webservice. Hence the cross-domain referencing is eliminated.
We've added a 2-way origin check to confirm only authorized page posts data to and from the iframe.
<iframe style="display:none;" id='receiver' name="receiver" src="https://iframe-address-at-client-server">
</iframe>
//send data to iframe
var hiddenFrame = document.getElementById('receiver').contentWindow;
hiddenFrame.postMessage(JSON.stringify(message), 'https://client-server-url');
//The iframe receives the data using the code:
window.onload = function () {
var eventMethod = window.addEventListener ? "addEventListener" : "attachEvent";
var eventer = window[eventMethod];
var messageEvent = eventMethod == "attachEvent" ? "onmessage" : "message";
eventer(messageEvent, function (e) {
var origin = e.origin;
//if origin not in pre-defined list, break and return
var messageFromParent = JSON.parse(e.data);
var json = messageFromParent.data;
//send json to web service using AJAX- same origin now
//return the response back to source
e.source.postMessage(JSON.stringify(aJAXResponse), e.origin);
}, false);
}
The below code doesn't run in IE7/8. I researched online, .innerhtml will not work in IE 7/8 Browser. I really need this code to run in those browsers.
$(document).ready(function(){
var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1);
$.ajax({
type: "GET",
url: "/get_header",
data: hashes,
success: function(data) {
if (!$.support.leadingWhitespace) {
alert('j');
document.getElementById('logo-bar').innerHTML = data;
} else {
$('#logo-bar').html(data);
}
},
error: function(data) {}
});
You're using jQuery for the AJAX request, so you may as well use it to update the DOM too. If you are concerned about leading whitespace in the response text, you can use $.trim() to remove it:
success: function(data) {
$('#logo-bar').html($.trim(data));
},
I need to copy file between document libraries. Library A is located in one site and Library B is located in subsite. I know how to copy file between libraries on the same level but the problem is with copying between different level.
The code I use to copy file between libraries on the same level.
$.ajax({
url : "http://xxx/PWA/_api/web/folders/GetByUrl('/PWA/CopyFromLibrary')/Files/getbyurl('Import.csv')/copyTo(strNewUrl = '/PWA/TargetLibrary/Import.csv',bOverWrite = true)",
method: 'POST',
headers: {
"Accept": "application/json; odata=verbose",
"X-RequestDigest": $("#__REQUESTDIGEST").val()
},
success: function () {
alert("Success! Your file was copied properly");
},
error: function () {
alert("Problem with copying");
}
});
For different level I use just another target URL:
url : "http://xxx/PWA/_api/web/folders/GetByUrl('/PWA/CopyFromLibrary')/Files/getbyurl('Import.csv')/copyTo(strNewUrl = '/PWA/Subsite/TargetLibrary/Import.csv',bOverWrite = true)",
And it doesn't work.
How to work around this problem?
Just figured this one out today for the cross site solution. The trick is-- don't use $.ajax for the download of the document. Use good old XMLHttpRequest. The reason is that JQuery simply doesn't let you get a raw binary data array from SharePoint. But, the XMLHttpRequest does because it allows you to get an arraybuffer as part of its implementation, which SharePoint accepts!
The following is the code with the parts identified for building the full source and target REST urls. Note that you can use $.ajax to upload the file.
sourceSite is a sharepoint site suitable for appending the '_api' rest endpoint
sourceFolderPath is the relative folder path your document is located within
sourceFileName is the filename of the document
targetSite, targetFolderPath and targetFileName are the mirror images or source, only for the destination.
requestDigest is that special value you need for SharePoint to accept updates.
function copyDocument(sourceSite, sourceFolderPath, sourceFileName, targetSite, targetFolderPath, targetFileName, requestDigest) {
var sourceSiteUrl = sourceSite + "_api/web/GetFolderByServerRelativeUrl('" + sourceFolderPath + "')/Files('" + sourceFileName + "')/$value";
var targetSiteUrl = targetSite + "_api/web/GetFolderByServerRelativeUrl('" + targetFolderPath + "')/Files/Add(url='" + targetFileName + "',overwrite=true)";
var xhr = new XMLHttpRequest();
xhr.open('GET', sourceSiteUrl, true);
xhr.setRequestHeader('binaryStringResponseBody', true);
xhr.responseType = 'arraybuffer';
xhr.onload = function (e) {
if (this.status == 200) {
var arrayBuffer = this.response;
$.ajax({
url: targetSiteUrl,
method: 'POST',
data: arrayBuffer,
processData: false,
headers: { 'binaryStringRequestBody': 'true', 'Accept': 'application/json;odata=verbose;charset=utf-8', 'X-RequestDigest': requestDigest }
})
.done(function (postData) {
console.log('we did it!');
})
.fail(function (jqXHR, errorText) {
console.log('dadgummit');
});
}
}
xhr.send();
}
What kind of error are you getting?
One probable cause of your problem is that your RequestDigest does not match the location where you want to POST your file since it is fetched from the page where your code is running. Fetch a matching RequestDigest by calling '_api/contextinfo' on your target location.
See:
http://blogs.breeze.net/mickb/2012/11/20/SP2013GettingAFormDigestForUpdateRESTCalls.aspx
and
http://msdn.microsoft.com/en-us/magazine/dn198245.aspx (writing to Sharepoint section)
Note
File Move operations only work within the scope of a given document library. You cannot copy between document libraries.
http://msdn.microsoft.com/en-us/library/office/dn605900(v=office.15).aspx#Folder6
For POST - operation we need request digest value, which is used by SharePoint to authenticate mainly for Post, Delete, Update not needed for GET operation,
Sample jquery ajax code for post operation-
$.ajax({
url: url + "/_api/web/lists/getbytitle('" + listname + "')/items",
type: "POST",
contentType: "application/json;odata=verbose",
data: JSON.stringify(item),
headers: {
"Accept": "application/json;odata=verbose",
"X-RequestDigest": $("#__REQUESTDIGEST").val()
},
success: function (data) {
success(data); // Returns the newly created list item information
},
error: function (data) {
failure(data);
}
});
You can try the following code for copying file from one location to another within SharePoint.
The following example will be helpful in copying files within SharePoint sandbox.
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<div ng-app="myapp" ng-controller="mycont">
<input type="button" ng-click = "myclick()" value="Angular File Copy" />
</div>
<input type=button onclick="x()" value="jQueryFile copy" />
<script>
var dt =new Date();
var val_ue = dt.getDate()+""+dt.getHours()+""+dt.getMinutes()+""+dt.getSeconds() +"1" ;
var url1 = "/_api/web/getfilebyserverrelativeurl('/Lists/Document_Mapping/Attachments/1/9.jpg')";
var url2 = "/Lists/AddressVersioning/Attachments/84/" ;
var combined = "";
var app = angular.module('myapp',[]);
var _headers = {
'X-RequestDigest': document.getElementById("__REQUESTDIGEST").value,
'accept':'application/json;odata=verbose'
};
app.controller('mycont',function($scope,$http){
$scope.myclick = function(){
combined = url1 + "/copyTo('" + url2 + val_ue + ".jpg')";
$http({method:'POST',url:combined,headers:_headers}).then(
function(response){
console.log("hi");
val_ue += 1;
},
function(error){
console.log("Error:");
console.log(error);
},
function(process){
console.log("process:");
console.log(process);
}
);
}
});
var x = function(){
combined = url1 + "/copyTo('" + url2 + val_ue + ".jpg')";
$.ajax({
url : combined,
method: 'POST',
headers: {
"Accept": "application/json; odata=verbose",
"X-RequestDigest": $("#__REQUESTDIGEST").val()
},
success: function () {
alert("Success! Your file was copied properly");
val_ue +=1;
},
error: function () {
alert("Problem with copying");
}
});
}
</script>
Note: the above function will not work if the list item is newly created. But for all other situations it will work (even form one doc library to another doc library or cross site / site collection)
Hi I have built a web app and everything was working ok until I tested on IE9 with JSON files coming from another domain
Basically all of out JSON files are stored on AMAZON.
The idea on the first load is that I get a site.json file and this initializes and setups the app - but in IE9 and periodically in Safari and Chrome I am getting cross domain errors
So this is some extracts from the head of my homepage
<meta http-equiv="Access-Control-Allow-Origin" content="*"/>
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jqueryui/1.10.0/jquery-ui.min.js"></script>
<script type="text/javascript">
var SiteConfig, frameworkHost;
$(document).ready(function() {
var promise = $.ajax({
url: '//s3-ap-southeast-2.amazonaws.com/****/site.json',
method: 'get',
dataType: 'json'
});
$.when(promise).then(function(result) {
SiteConfig = result.data;
frameworkHost = '//s3-ap-southeast-2.amazonaws.com/**/public_html';
var requireTag = document.createElement('script');
requireTag.setAttribute('type', 'text/javascript');
requireTag.setAttribute('src', frameworkHost + '/js/require/require.js');
requireTag.setAttribute('data-main', frameworkHost + '/js/bootstrap');
document.head.appendChild(requireTag);
});
});
</script>
but the problem is as soon as the url to get site.json is not local on IE9 it fails.
Also in chrome, and safari on iphone 4s with ios 5 on occasions i get this error
XMLHttpRequest cannot load http://s3-ap-southeast-2.amazonaws.com/*. Origin It is not allowed by Access-Control-Allow-Origin
when i clear the cache this works though. It works perfectly on FF.
Can anyone help?
Thanks
if ($.browser.msie && window.XDomainRequest) {
// Use Microsoft XDR
var xdr = new XDomainRequest();
xdr.open("get", "someurl");
xdr.onload = function () {
var JSON = $.parseJSON(xdr.responseText);
if (JSON == null || typeof (JSON) == 'undefined')
{
JSON = $.parseJSON(data.firstChild.textContent);
}
processData(JSON);
};
xdr.send();
} else {
$.ajax({
type: 'GET',
url: "someurl",
processData: true,
data: {},
dataType: "json",
success: function (data) { processData(data); }
});
}