I want to realize zipping .exe files from server, while somebody downloads files using checkboxes, but not the point. Trying to understand how jszip works.
But I have some issues : downloader example doesn't work correctly.
I take an example from https://stuk.github.io/jszip/documentation/examples/downloader.html , delete some excess features like styles, links etc.
Almost all runs correct except block: JSZipUtils.getBinaryContent(url, function (err, data) {..}
- this section doesn't execute, it gives me an error : " Error: InvalidStateError: Failed to read the 'responseText' property from 'XMLHttpRequest': The value is only accessible if the object's 'responseType' is" or 'text'(was'arraybuffer'). "
Also I have another question: if I place script "demo.js" in header section script doesn't run by pressing button. Scripts should be downloaded because they are small size and header loading faster then body. I read that best way to include scripts is to place they right in the end of body, before closing tag. But if I place all my scripts in the end of body nothing happens when button is pressed. Why it works that way? I red many articles but don't find an answer. I'm new in JS so don't beat me hard).
I'll be very appreciate for any help and suggestions.
this is my 1.html file:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>something</title>
<script type="text/javascript" src="dist/jszip.js"></script>
<script type="text/javascript" src="dist/jszip-utils.js"></script>
<script type="text/javascript" src="dist/jquery-1.8.3.min.js"></script>
<script type="text/javascript" src="dist/FileSaver.js"></script>
</head>
<body>
<form action="#" id="download_form">
<ul>
<li>
<label>
<input type="checkbox" data-url="dist/jszip.js" checked />
dist/jszip.js
</label>
</li>
<li>
<label>
<input type="checkbox" data-url="dist/demo.js" checked />
dist/demo.js
</label>
</li>
<li>
<label>
<input type="checkbox" data-url="dist/FileSaver.js" />
dist/FileSaver.js
</label>
</li>
</ul>
<button type="submit" class="btn btn-primary">pack them !</button>
</form>
<script type="text/javascript" src="dist/demo.js"></script>
</body>
</html>
and here is demo.js:
jQuery(function ($) {
"use strict";
/**
* Reset the message.
*/
function resetMessage () {
$("#result")
.removeClass()
.text("");
}
/**
* show a successful message.
* #param {String} text the text to show.
*/
function showMessage(text) {
resetMessage();
$("#result")
.addClass("alert alert-success")
.text(text);
}
/**
* show an error message.
* #param {String} text the text to show.
*/
function showError(text) {
resetMessage();
$("#result")
.addClass("alert alert-danger")
.text(text);
}
/**
* Fetch the content, add it to the JSZip object
* and use a jQuery deferred to hold the result.
* #param {String} url the url of the content to fetch.
* #param {String} filename the filename to use in the JSZip object.
* #param {JSZip} zip the JSZip instance.
* #return {jQuery.Deferred} the deferred containing the data.
*/
function deferredAddZip(url, filename, zip) {
var deferred = $.Deferred();
JSZipUtils.getBinaryContent(url, function (err, data) {
if(err) {
deferred.reject(err);
} else {
zip.file(filename, data, {binary:true});
deferred.resolve(data);
}
});
return deferred;
}
if(!JSZip.support.blob) {
showError("This demo works only with a recent browser !");
return;
}
var $form = $("#download_form").on("submit", function () {
alert("button press"); /* it works fine */
resetMessage();
var zip = new JSZip();
var deferreds = [];
// find every checked item
$(this).find(":checked").each(function () {
var $this = $(this);
var url = $this.data("url");
var filename = url.replace(/.*\//g, "");
deferreds.push(deferredAddZip(url, filename, zip));
});
// when everything has been downloaded, we can trigger the dl
// section below doesn't work at all - alerts used for simplest debugging
$.when.apply($, deferreds).done(function () {
//alert("downloading must start");
var blob = zip.generate({type:"blob"});
// see FileSaver.js
saveAs(blob, "example.zip");
showMessage("done !");
}).fail(function (err) {
showError(err);
});
return false;
});
});
my file folder which includes files looks like:
-root folder:
1.html
subfolder "dist":
demo.js
FileSaver.js
jquery-1.8.3.min.js
jszip.js
jszip-utils.js
Resolved my problem.
The problem is that html file was opened in browser on my local machine using file:/// protocol. For correct work it should use http protocol.
So I download apache server, run on my pc and start my html file on apache server which worked correctly.
Related
Fairly basic question here. I've run into a situation where I can't seem to access Javascript functions from within my HTML file, even though I've linked the JS file as a script src. It seems like a pretty simple issue but I can't figure out what the problem is.
I'm trying to add a function called startLogin to an HTML button. I added it as an onclick, but then when I try to click the button, the console says the function is undefined. However the function is clearly defined in the JS file and as far as I can tell the syntax I'm using for the onclick and the script src link is correct.
In addition I've confirmed that the JS file is linked to the HTML file. If I try to manipulate the DOM from the JS file just to do something simple, like set the background to red, that works fine. The problem is when I try to call a function defined in the JS file. Also I've made sure the function I'm trying to call does actually work. If I stick it right in the HTML file inside script tags, it works fine.
I've already tried moving the script tags inside the body at the end of the HTML, as I know that's often the issue, but in this case it didn't work. Can anyone help me identify why I'm unable to access the "startLogin" function from the HTML button?
FYI, this is a javascript project and I'm using Vite.js for bundling. All the other HTML/JS files in my project are playing nicely together, I'm only having an issue with the Login page.
file structure:
|-pages
|-login.html
|-login.js
login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-
scale=1.0" />
<title>Document</title>
<!-- LINK JS FILE -->
<!-- MODULE TYPE IS RELATED TO VITE.JS -->
<script type="module" src="./login.js"></script>
</head>
<body>
<!-- email login form -->
<form name="emailLogin" id="emailLogin" style="display: none">
<div class="row" style="width: 600px">
<div class="col">
<div class="form-row" style="padding-bottom: 10px">
<input
type="email"
class="form-control"
id="emailAddress"
placeholder="email associated with your login"
style="width: 576px"
/>
</div>
</div>
<div class="form-row">
<br />
<button type="button" class="btn btn-primary" onclick="startLogin('email')">
Send Email Login
</button>
</div>
</div>
</form>
</body>
</html>
login.js
// start the login process by generating a code sent either SMS or EMAIL
function startLogin(login_type) {
// local variables
var ajaxResult;
var subs;
var tempString;
// get the login values and set up the call
if (login_type == "phone") {
// get the values
use_country_code = $("#country").val();
use_phone = $("#phoneNumber").val();
use_phone = use_phone.replace(/\D/g, "");
// do the validation
if (use_phone.length < 10) {
$("#errorText").html(
"Phone number doesn't have enough digits, please try again."
);
$("#errorModal").modal("show");
return;
}
// build the url
post_url =
"https://us-central1-dev-api-327415.cloudfunctions.net/user-login?cc=" +
use_country_code +
"&phone=" +
use_phone;
} else {
// get the values
use_email = $("#emailAddress").val();
// do the validation
if (!validateEmail(use_email)) {
$("#errorText").html(
"Email address does not appear to be valid, please check the format and try again."
);
$("#errorModal").modal("show");
return;
}
// build the url
post_url =
"https://us-central1-dev-api-327415.cloudfunctions.net/user-login?email=" +
use_email;
}
// send the request to the server and process the results
$.LoadingOverlay("show");
$.ajax({
type: "POST",
url: post_url,
// process the returned result of the Ajax call
success: function (ajaxResult) {
// see if we have a session token and handle the response
session_token = ajaxResult["session_token"];
if (session_token == "None") {
// hide the login and show the text message area if phone, otherwise hide email and show email message
if (login_type == "phone") {
$("#loginMethod").hide();
$("#phoneLogin").hide();
$("#codeLogin").show();
$("#loginMessage").hide();
$("#textMessage").show();
} else {
$("#loginMethod").hide();
$("#emailLogin").hide();
$("#loginMessage").hide();
$("#codeLogin").show();
$("#emailMessage").show();
}
} else {
// hide everything since already logged in and show the right message
$("#phoneLogin").hide();
$("#emailLogin").hide();
$("#loginMethod").hide();
$("#loginMessage").hide();
$("#codeLogin").hide();
$("#continueLoginAlready").show();
}
},
// process after the Ajax call has been fully completed
complete: function () {
$.LoadingOverlay("hide");
},
// handle total failure
error: function (jqXHR, exception) {
console.log(jqXHR);
console.log(exception);
json_error = jqXHR["responseJSON"];
$("#errorText").html(json_error.error_message);
$("#errorModal").modal("show");
},
});
}
Javascript modules work a bit differently. There, variables and functions are not exposed to the global scope.
If you want to use your function from other parts of the code, you have to set it explicitly on the window object:
function startLogin(...) {
...
}
window.startLogin = startLogin;
an other solution is to set the js at end of the html, than you don't need to use the window object (memory lag)
<html lang="en">
<head>...</head>
<body>
<button type="button" id="myButton">Title</button>
</body>
<script>
function myFunction(){
console.log('running myFunction');
}
const button = document.querySelector('#myButton');
button.addEventListener('click', function clickListener(
{
myFunction();
}
</script>
</html>
the browser is simply stupid, it loads the page from top to bottom and if you load your js after the body all your html is present and you can do it this way.
I have this code and for a file to be converted into base64 I have to click on Choose file and then select it. I want to hardcode the file name so it is converted to base64 on page load.
JavaScript:
var handleFileSelect = function(evt) {
var files = evt.target.files;
var file = files[0];
if (files && file) {
var reader = new FileReader();
reader.onload = function(readerEvt) {
var binaryString = readerEvt.target.result;
document.getElementById("base64textarea").value = btoa(binaryString);
};
reader.readAsBinaryString(file);
}
if (window.File && window.FileReader
&& window.FileList && window.Blob) {
document.getElementById('filePicker')
.addEventListener('change', handleFileSelect, false);
} else {
alert('The File APIs are not fully supported in this browser.');
}
};
HTML:
<div>
<div>
<label for="filePicker">Choose or drag a file:</label><br/>
<input type="file" id="filePicker">
</div>
</br>
<div>
<h1>Base64 encoded version</h1>
<textarea id="base64textarea"
placeholder="Base64 will appear here"
cols="50" rows="15">
</textarea>
</div>
</div>
EDIT: Thank you for your answers, they were really helpful.
You simply can't do what you are trying to do. Setting the path for an input element through Javascript is not possible, as a security measure. Please check here: How to resolve the C:\fakepath?
You can launch chromium, chrome browser with --allow-file-access-from-files flag set, use fetch() of XMLHttpRequest() to request file from local filesystem.
fetch("file:///path/to/file")
.then(response => response.arrayBuffer())
.then(ab => {
// do stuff with `ArrayBuffer` representation of file
})
.catch(err => console.log(err));
See also Read local XML with JS
The File API is not good to read local files without user intervention, but the Web API is (of course, within its limitations, like not working in Chromium without explicitly enabling access to local files and whatnot).
So, here it is, in case someone else needs a working example of how to load a local file without user intervention, i.e., without requiring user to push any INPUT button (but still giving the user a means to abort the loading).
Parameters: file name, request type (text, blob etc.), MIME type and a function to be executed after the file is completely loaded. File is loaded in variable X, which is then used to populated an object.
To abort the file reading, just click on the progress bar (also, just an example, not essential for the program to work). Because it is asynchronous, as many files as wanted may be read at the same time (one progress bar is created for each file).
I only created examples for a text file and a video, but it should work with any kind of files.
<html>
<head>
<meta charset="utf-8"/>
<script type="text/javascript">
function LoadFile(FileName,RespType,FileType,RunMe)
{ var AJAXFileReader=new XMLHttpRequest();
// Creates new progress bar.
var ProgressBar=CreateSVGProgBar("ProgressBars");
AJAXFileReader.addEventListener("progress",
function FRProgress(AJAXFREvt)
{ // Calculate progress.
var X=-1;
if (AJAXFREvt.lengthComputable)
X=Math.trunc(AJAXFREvt.loaded/AJAXFREvt.total*100);
ShowProgressBar(ProgressBar,FileName,X);
});
AJAXFileReader.addEventListener("error",function FRFailed()
{ // This will be executed if an error occurs.
console.log("Error:",this.status);
});
AJAXFileReader.addEventListener("timeout",function FRTimeOut()
{ // This will be executed if the reading times out.
console.log("File reading timed out!");
});
AJAXFileReader.addEventListener("abort",
function FRCancel()
{ // This will confirm reading was aborted.
console.log("File reading cancelled by user!");
});
ProgressBar.addEventListener("click",
function KillMe()
{ // Adds an abort command to the object.
console.log(AJAXFileReader.readyState);
if (AJAXFileReader.readyState!=4)
{ console.log("Aborting file reading...");
AJAXFileReader.abort();
}
ProgressBar.removeEventListener("click",KillMe);
},
false);
AJAXFileReader.addEventListener("load",
function Finished()
{ // When reading is finished, send data to external function.
if ((this.readyState==4)&&(this.status==200))
{ ShowProgressBar(ProgressBar,FileName,100);
RunMe(this.response);
//ProgressBar.click();
}
},
false);
AJAXFileReader.open("GET",FileName,true);
AJAXFileReader.overrideMimeType(FileType);
AJAXFileReader.responseType=RespType;
AJAXFileReader.timeout=10000; // Setting time-out to 10 s.
AJAXFileReader.send();
}
function CreateSVGProgBar(AnchorId)
{ // Creates new SVG progress bar.
var Parent=document.getElementById(AnchorId);
var NewSVG=document.createElementNS("http://www.w3.org/2000/svg","svg");
NewSVG.setAttribute("viewBox","0 0 102 22");
NewSVG.setAttribute("width","102");
NewSVG.setAttribute("height","22");
Parent.appendChild(NewSVG);
return NewSVG;
}
function ShowProgressBar(E,N,X)
{ // Show progress bar.
var P=X<0?"???":X+"%";
E.innerHTML="<text x=\"50\" y=\"16\" font-size=\"12\" fill=\"black\" stroke=\"black\" text-anchor=\"middle\">"+N+"</text><rect x=\"1\" y=\"1\" width=\""+X+"\" height=\"20\" fill=\""+(X<100?"#FF0000":"#0000FF")+"\" stroke=\"none\"/><rect x=\"1\" y=\"1\" width=\"100\" height=\"20\" fill=\"none\" stroke=\"black\" stroke-width=\"1\"/><text x=\""+X/2+"\" y=\"16\" font-size=\"12\" fill=\"black\" stroke=\"black\" text-anchor=\"middle\">"+P+"</text>";
}
function TracerOn(X)
{ // This will be executed after the file is completely loaded.
document.getElementById("Tron").innerHTML=X;
}
function PlayIt(X)
{ // This will be executed after the file is completely loaded.
var blob_uri=URL.createObjectURL(X);
document.getElementById("MagicalBox").appendChild(document.createElement("source")).src=blob_uri;
}
function Startup()
{ // Run after the Page is loaded.
LoadFile("example.txt","text","text/plain;charset=utf-8",TracerOn);
LoadFile("video.mp4","blob","video/mp4",PlayIt);
}
</script>
</head>
<body onload="Startup()">
<div id="ProgressBars"></div>
<div id="Tron">Text...</div>
<video id="MagicalBox" width="400" controls>Video...</video>
</body>
</html>
I want home.html to load in <div id="content">.
<div id="topBar"> HOME </div>
<div id ="content"> </div>
<script>
function load_home(){
document.getElementById("content").innerHTML='<object type="type/html" data="home.html" ></object>';
}
</script>
This works fine when I use Firefox. When I use Google Chrome, it asks for plug-in. How do I get it working in Google Chrome?
I finally found the answer to my problem. The solution is
function load_home() {
document.getElementById("content").innerHTML='<object type="text/html" data="home.html" ></object>';
}
Fetch API
function load_home (e) {
(e || window.event).preventDefault();
fetch("http://www.yoursite.com/home.html" /*, options */)
.then((response) => response.text())
.then((html) => {
document.getElementById("content").innerHTML = html;
})
.catch((error) => {
console.warn(error);
});
}
XHR API
function load_home (e) {
(e || window.event).preventDefault();
var con = document.getElementById('content')
, xhr = new XMLHttpRequest();
xhr.onreadystatechange = function (e) {
if (xhr.readyState == 4 && xhr.status == 200) {
con.innerHTML = xhr.responseText;
}
}
xhr.open("GET", "http://www.yoursite.com/home.html", true);
xhr.setRequestHeader('Content-type', 'text/html');
xhr.send();
}
based on your constraints you should use ajax and make sure that your javascript is loaded before the markup that calls the load_home() function
Reference - davidwalsh
MDN - Using Fetch
JSFIDDLE demo
You can use the jQuery load function:
<div id="topBar">
HOME
</div>
<div id ="content">
</div>
<script>
$(document).ready( function() {
$("#load_home").on("click", function() {
$("#content").load("content.html");
});
});
</script>
Sorry. Edited for the on click instead of on load.
Fetching HTML the modern Javascript way
This approach makes use of modern Javascript features like async/await and the fetch API. It downloads HTML as text and then feeds it to the innerHTML of your container element.
/**
* #param {String} url - address for the HTML to fetch
* #return {String} the resulting HTML string fragment
*/
async function fetchHtmlAsText(url) {
return await (await fetch(url)).text();
}
// this is your `load_home() function`
async function loadHome() {
const contentDiv = document.getElementById("content");
contentDiv.innerHTML = await fetchHtmlAsText("home.html");
}
The await (await fetch(url)).text() may seem a bit tricky, but it's easy to explain. It has two asynchronous steps and you could rewrite that function like this:
async function fetchHtmlAsText(url) {
const response = await fetch(url);
return await response.text();
}
See the fetch API documentation for more details.
I saw this and thought it looked quite nice so I ran some tests on it.
It may seem like a clean approach, but in terms of performance it is lagging by 50% compared by the time it took to load a page with jQuery load function or using the vanilla javascript approach of XMLHttpRequest which were roughly similar to each other.
I imagine this is because under the hood it gets the page in the exact same fashion but it also has to deal with constructing a whole new HTMLElement object as well.
In summary I suggest using jQuery. The syntax is about as easy to use as it can be and it has a nicely structured call back for you to use. It is also relatively fast. The vanilla approach may be faster by an unnoticeable few milliseconds, but the syntax is confusing. I would only use this in an environment where I didn't have access to jQuery.
Here is the code I used to test - it is fairly rudimentary but the times came back very consistent across multiple tries so I would say precise to around +- 5ms in each case. Tests were run in Chrome from my own home server:
<!DOCTYPE html>
<html>
<head>
<script src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
</head>
<body>
<div id="content"></div>
<script>
/**
* Test harness to find out the best method for dynamically loading a
* html page into your app.
*/
var test_times = {};
var test_page = 'testpage.htm';
var content_div = document.getElementById('content');
// TEST 1 = use jQuery to load in testpage.htm and time it.
/*
function test_()
{
var start = new Date().getTime();
$(content_div).load(test_page, function() {
alert(new Date().getTime() - start);
});
}
// 1044
*/
// TEST 2 = use <object> to load in testpage.htm and time it.
/*
function test_()
{
start = new Date().getTime();
content_div.innerHTML = '<object type="text/html" data="' + test_page +
'" onload="alert(new Date().getTime() - start)"></object>'
}
//1579
*/
// TEST 3 = use httpObject to load in testpage.htm and time it.
function test_()
{
var xmlHttp = new XMLHttpRequest();
xmlHttp.onreadystatechange = function() {
if (xmlHttp.readyState == 4 && xmlHttp.status == 200)
{
content_div.innerHTML = xmlHttp.responseText;
alert(new Date().getTime() - start);
}
};
start = new Date().getTime();
xmlHttp.open("GET", test_page, true); // true for asynchronous
xmlHttp.send(null);
// 1039
}
// Main - run tests
test_();
</script>
</body>
</html>
try
async function load_home(){
content.innerHTML = await (await fetch('home.html')).text();
}
async function load_home() {
let url = 'https://kamil-kielczewski.github.io/fractals/mandelbulb.html'
content.innerHTML = await (await fetch(url)).text();
}
<div id="topBar"> HOME </div>
<div id="content"> </div>
When using
$("#content").load("content.html");
Then remember that you can not "debug" in chrome locally, because XMLHttpRequest cannot load -- This does NOT mean that it does not work, it just means that you need to test your code on same domain aka. your server
You can use the jQuery :
$("#topBar").on("click",function(){
$("#content").load("content.html");
});
$("button").click(function() {
$("#target_div").load("requesting_page_url.html");
});
or
document.getElementById("target_div").innerHTML='<object type="text/html" data="requesting_page_url.html"></object>';
<script>
var insertHtml = function (selector, argHtml) {
$(document).ready(function(){
$(selector).load(argHtml);
});
var targetElem = document.querySelector(selector);
targetElem.innerHTML = html;
};
var sliderHtml="snippets/slider.html";//url of slider html
var items="snippets/menuItems.html";
insertHtml("#main",sliderHtml);
insertHtml("#main2",items);
</script>
this one worked for me when I tried to add a snippet of HTML to my main.html.
Please don't forget to add ajax in your code
pass class or id as a selector and the link to the HTML snippet as argHtml
There is this plugin on github that load content into an element. Here is the repo
https://github.com/abdi0987/ViaJS
load html form a remote page ( where we have CORS access )
parse the result-html for a specific portion of the page
insert that part of the page in a div on current-page
//load page via jquery-ajax
$.ajax({
url: "https://stackoverflow.com/questions/17636528/how-do-i-load-an-html-page-in-a-div-using-javascript",
context: document.body
}).done(function(data) {
//the previous request fails beceaus we dont have CORS on this url.... just for illlustration...
//get a list of DOM-Nodes
var dom_nodes = $($.parseHTML(data));
//find the question-header
var content = dom_nodes.find('#question-header');
//create a new div and set the question-header as it's content
var newEl = document.createElement("div");
$(newEl).html(content.html());
//on our page, insert it in div with id 'inserthere'
$("[id$='inserthere']").append(newEl);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<p>part-result from other page:</p>
<div id="inserthere"></div>
Use this simple code
<div w3-include-HTML="content.html"></div>
<script>w3.includeHTML();</script>
</body>```
This is usually needed when you want to include header.php or whatever page.
In Javascript it's easy especially if you have HTML page and don't want to use php include function but at all you should write php function and add it as Javascript function in script tag.
In this case you should write it without function followed by name Just. Script rage the function word and start the include header.php
i.e convert the php include function to Javascript function in script tag and place all your content in that included file.
I use jquery, I found it easier
$(function() {
$("#navigation").load("navbar.html");
});
in a separate file and then load javascript file on html page
showhide.html
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript">
function showHide(switchTextDiv, showHideDiv)
{
var std = document.getElementById(switchTextDiv);
var shd = document.getElementById(showHideDiv);
if (shd.style.display == "block")
{
shd.style.display = "none";
std.innerHTML = "<span style=\"display: block; background-color: yellow\">Show</span>";
}
else
{
if (shd.innerHTML.length <= 0)
{
shd.innerHTML = "<object width=\"100%\" height=\"100%\" type=\"text/html\" data=\"showhide_embedded.html\"></object>";
}
shd.style.display = "block";
std.innerHTML = "<span style=\"display: block; background-color: yellow\">Hide</span>";
}
}
</script>
</head>
<body>
<a id="switchTextDiv1" href="javascript:showHide('switchTextDiv1', 'showHideDiv1')">
<span style="display: block; background-color: yellow">Show</span>
</a>
<div id="showHideDiv1" style="display: none; width: 100%; height: 300px"></div>
</body>
</html>
showhide_embedded.html
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript">
function load()
{
var ts = document.getElementById("theString");
ts.scrollIntoView(true);
}
</script>
</head>
<body onload="load()">
<pre>
some text 1
some text 2
some text 3
some text 4
some text 5
<span id="theString" style="background-color: yellow">some text 6 highlight</span>
some text 7
some text 8
some text 9
</pre>
</body>
</html>
If your html file resides locally then go for iframe instead of the tag. tags do not work cross-browser, and are mostly used for Flash
For ex : <iframe src="home.html" width="100" height="100"/>
I'm using the JSONEditor (https://github.com/josdejong/jsoneditor) to load a json file, make changes and save the file. This works great but it only saves the JSON file to the folder specified according to your browser settings. Here's the demo code (https://github.com/josdejong/jsoneditor/blob/master/examples/04_load_and_save.html):
<!DOCTYPE HTML>
<html>
<head>
<title>JSONEditor | Load and save</title>
<link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css">
<script src="../dist/jsoneditor.js"></script>
<script src="https://bgrins.github.io/filereader.js/filereader.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2014-11-29/FileSaver.min.js"></script>
<style>
html, body {
font: 11pt sans-serif;
}
#jsoneditor {
width: 500px;
height: 500px;
}
</style>
</head>
<body>
<h1>Load and save JSON documents</h1>
<p>
This examples uses HTML5 to load/save local files.
Powered by FileReader.js and
FileSaver.js.<br>
Only supported on modern browsers (Chrome, FireFox, IE10+, Safari 6.1+, Opera 15+).
</p>
<p>
Load a JSON document: <input type="file" id="loadDocument" value="Load"/>
</p>
<p>
Save a JSON document: <input type="button" id="saveDocument" value="Save" />
</p>
<div id="jsoneditor"></div>
<script>
// create the editor
var editor = new JSONEditor(document.getElementById('jsoneditor'));
// Load a JSON document
FileReaderJS.setupInput(document.getElementById('loadDocument'), {
readAsDefault: 'Text',
on: {
load: function (event, file) {
editor.setText(event.target.result);
}
}
});
// Save a JSON document
document.getElementById('saveDocument').onclick = function () {
// Save Dialog
fname = window.prompt("Save as...");
// Check json extension in file name
if(fname.indexOf(".")==-1){
fname = fname + ".json";
}else{
if(fname.split('.').pop().toLowerCase() == "json"){
// Nothing to do
}else{
fname = fname.split('.')[0] + ".json";
}
}
var blob = new Blob([editor.getText()], {type: 'application/json;charset=utf-8'});
saveAs(blob, fname);
};
</script>
</body>
</html>
I want to be able to save the file to the web server. Is there any way for me to save the edited JSON file to the web server? I searched and tried to integrate this library with JSONEditor but no joy:
https://abandon.ie/notebook/simple-file-uploads-using-jquery-ajax
I'm not restricted to ajax so I'll consider anything that works!
Thanks for your advice.
John
UPDATED: Here's the controller code chunk.
// POST api/values
public async void Post()
{
string json = await Request.Content.ReadAsStringAsync();
File.WriteAllText(
HttpContext.Current.Server.MapPath("~\\App_Data\\somefile.json"),
json
);
}
I tested this using Postman and it works. What I can't seem to do for the life of me is to now send the edited JSON file to the controller. Here's the modified HTML page where I try unsuccessfully to send the json. For brevity, I'll just add the extra/edited code code:
<form id="form1" method="post" enctype="text/plain" action="http://localhost:1651/api/values">
<input type="file" name="json" id="loadDocument" value="Load"/>
<input type="submit" value="Save" />
</form>
Edited javascript where I try to return the edited json to the form:
document.getElementById('saveDocument').onclick = function () {
return editor.getText();
};
Please help! How do I send the json to the controller?
I have this code and for a file to be converted into base64 I have to click on Choose file and then select it. I want to hardcode the file name so it is converted to base64 on page load.
JavaScript:
var handleFileSelect = function(evt) {
var files = evt.target.files;
var file = files[0];
if (files && file) {
var reader = new FileReader();
reader.onload = function(readerEvt) {
var binaryString = readerEvt.target.result;
document.getElementById("base64textarea").value = btoa(binaryString);
};
reader.readAsBinaryString(file);
}
if (window.File && window.FileReader
&& window.FileList && window.Blob) {
document.getElementById('filePicker')
.addEventListener('change', handleFileSelect, false);
} else {
alert('The File APIs are not fully supported in this browser.');
}
};
HTML:
<div>
<div>
<label for="filePicker">Choose or drag a file:</label><br/>
<input type="file" id="filePicker">
</div>
</br>
<div>
<h1>Base64 encoded version</h1>
<textarea id="base64textarea"
placeholder="Base64 will appear here"
cols="50" rows="15">
</textarea>
</div>
</div>
EDIT: Thank you for your answers, they were really helpful.
You simply can't do what you are trying to do. Setting the path for an input element through Javascript is not possible, as a security measure. Please check here: How to resolve the C:\fakepath?
You can launch chromium, chrome browser with --allow-file-access-from-files flag set, use fetch() of XMLHttpRequest() to request file from local filesystem.
fetch("file:///path/to/file")
.then(response => response.arrayBuffer())
.then(ab => {
// do stuff with `ArrayBuffer` representation of file
})
.catch(err => console.log(err));
See also Read local XML with JS
The File API is not good to read local files without user intervention, but the Web API is (of course, within its limitations, like not working in Chromium without explicitly enabling access to local files and whatnot).
So, here it is, in case someone else needs a working example of how to load a local file without user intervention, i.e., without requiring user to push any INPUT button (but still giving the user a means to abort the loading).
Parameters: file name, request type (text, blob etc.), MIME type and a function to be executed after the file is completely loaded. File is loaded in variable X, which is then used to populated an object.
To abort the file reading, just click on the progress bar (also, just an example, not essential for the program to work). Because it is asynchronous, as many files as wanted may be read at the same time (one progress bar is created for each file).
I only created examples for a text file and a video, but it should work with any kind of files.
<html>
<head>
<meta charset="utf-8"/>
<script type="text/javascript">
function LoadFile(FileName,RespType,FileType,RunMe)
{ var AJAXFileReader=new XMLHttpRequest();
// Creates new progress bar.
var ProgressBar=CreateSVGProgBar("ProgressBars");
AJAXFileReader.addEventListener("progress",
function FRProgress(AJAXFREvt)
{ // Calculate progress.
var X=-1;
if (AJAXFREvt.lengthComputable)
X=Math.trunc(AJAXFREvt.loaded/AJAXFREvt.total*100);
ShowProgressBar(ProgressBar,FileName,X);
});
AJAXFileReader.addEventListener("error",function FRFailed()
{ // This will be executed if an error occurs.
console.log("Error:",this.status);
});
AJAXFileReader.addEventListener("timeout",function FRTimeOut()
{ // This will be executed if the reading times out.
console.log("File reading timed out!");
});
AJAXFileReader.addEventListener("abort",
function FRCancel()
{ // This will confirm reading was aborted.
console.log("File reading cancelled by user!");
});
ProgressBar.addEventListener("click",
function KillMe()
{ // Adds an abort command to the object.
console.log(AJAXFileReader.readyState);
if (AJAXFileReader.readyState!=4)
{ console.log("Aborting file reading...");
AJAXFileReader.abort();
}
ProgressBar.removeEventListener("click",KillMe);
},
false);
AJAXFileReader.addEventListener("load",
function Finished()
{ // When reading is finished, send data to external function.
if ((this.readyState==4)&&(this.status==200))
{ ShowProgressBar(ProgressBar,FileName,100);
RunMe(this.response);
//ProgressBar.click();
}
},
false);
AJAXFileReader.open("GET",FileName,true);
AJAXFileReader.overrideMimeType(FileType);
AJAXFileReader.responseType=RespType;
AJAXFileReader.timeout=10000; // Setting time-out to 10 s.
AJAXFileReader.send();
}
function CreateSVGProgBar(AnchorId)
{ // Creates new SVG progress bar.
var Parent=document.getElementById(AnchorId);
var NewSVG=document.createElementNS("http://www.w3.org/2000/svg","svg");
NewSVG.setAttribute("viewBox","0 0 102 22");
NewSVG.setAttribute("width","102");
NewSVG.setAttribute("height","22");
Parent.appendChild(NewSVG);
return NewSVG;
}
function ShowProgressBar(E,N,X)
{ // Show progress bar.
var P=X<0?"???":X+"%";
E.innerHTML="<text x=\"50\" y=\"16\" font-size=\"12\" fill=\"black\" stroke=\"black\" text-anchor=\"middle\">"+N+"</text><rect x=\"1\" y=\"1\" width=\""+X+"\" height=\"20\" fill=\""+(X<100?"#FF0000":"#0000FF")+"\" stroke=\"none\"/><rect x=\"1\" y=\"1\" width=\"100\" height=\"20\" fill=\"none\" stroke=\"black\" stroke-width=\"1\"/><text x=\""+X/2+"\" y=\"16\" font-size=\"12\" fill=\"black\" stroke=\"black\" text-anchor=\"middle\">"+P+"</text>";
}
function TracerOn(X)
{ // This will be executed after the file is completely loaded.
document.getElementById("Tron").innerHTML=X;
}
function PlayIt(X)
{ // This will be executed after the file is completely loaded.
var blob_uri=URL.createObjectURL(X);
document.getElementById("MagicalBox").appendChild(document.createElement("source")).src=blob_uri;
}
function Startup()
{ // Run after the Page is loaded.
LoadFile("example.txt","text","text/plain;charset=utf-8",TracerOn);
LoadFile("video.mp4","blob","video/mp4",PlayIt);
}
</script>
</head>
<body onload="Startup()">
<div id="ProgressBars"></div>
<div id="Tron">Text...</div>
<video id="MagicalBox" width="400" controls>Video...</video>
</body>
</html>