How to download part of a React Component? - javascript

I am creating a website builder using React and I want to be able to download the content of this component under the preview-container class.
MainWebsite contains multiple descendants and components.
export default function PreviewContainer({
selectItem
}) {
return (
<div className="preview-container" >
<div className="preview">
<MainWebsite selectItem={selectItem}/>
</div>
</div>
)
}
I tried using
function onClick() {
var pageHTML = document.querySelector('.preview-container');
var tempEl = document.createElement('a');
tempEl.href = 'data:attachment/text,' + encodeURI(pageHTML);
tempEl.target = '_blank';
tempEl.download = 'thispage.html';
tempEl.click();
}
This downloads a page that just says [object HTMLDivElement] in its content
Note though that I want to download this component with the css and js included

You can't download an abstract element.
You'll need the inner or outer HTML of the element, depending on your requirements. (You could also use ReactDOMServer.renderToString().)
Additionally, you should use a blob URL, since the HTML could be quite large and thus awkward to put in a data URL.
If you use a blob URL, it needs to be revoked (to release memory). Some browsers require an anchor element to be in the DOM when "clicked", so that needs to be removed too. Since there's no event for "download complete", there's a simple timeout for 2 seconds.
function onClick() {
const pageHTML = document.querySelector(".preview-container").outerHTML;
const blob = new Blob([pageHTML], { type: "text/html" });
const url = URL.createObjectUrl(blob);
const tempEl = document.createElement("a");
document.body.appendChild(tempEl);
tempEl.href = url;
tempEl.download = "thispage.html";
tempEl.click();
setTimeout(() => {
URL.revokeObjectUrl(url);
tempEl.parentNode.removeChild(tempEl);
}, 2000);
}

Related

When importing an external HTML page and appending it to a div in Angular, the associated JavaScript does not function properly

I need to append an external HTML page to a div in my Angular app. To achieve this, I'm making an HTTP call to fetch the entire HTML content along with the associated CSS and JavaScript. I'm extracting the styles and scripts separately and using Renderer2 to append them to the document properly.
However, it appears that the script is not working properly. There is a slider in the HTML page that did not load correctly. I've created a StackBlitz app to demonstrate this issue. Here is the link:
app
Inside the Angular app, this slider is missing.
Code sample:
app.component.ts
<p>Place your website url to load into Angular</p>
<div style="margin:20px auto; width:80%" [innerHtml]="htmlContent"></div>
and inside the .ts file:
ngOnInit() {
let styleElement: HTMLElement;
let scriptElement: HTMLElement;
this.http
.get(
'https://cdn.cohora-test.com/t/T_T062ob1/TEMPLATE/0/P07Znp1/cf742d62-fb59-49d4-81b1-f027ac6b5649.html',
{ responseType: 'text' }
)
.subscribe((html) => {
const doc = new DOMParser().parseFromString(html, 'text/html');
console.log('onTemplateSelect ~ doc', doc);
const styleTag = doc.querySelector('style');
const scriptTag = doc.querySelector('script');
let styleRules = '';
let scriptCode = '';
if (styleTag) {
styleRules = styleTag.innerHTML;
}
if (scriptTag) {
scriptCode = scriptTag.innerHTML;
}
// Append the style rules to the head of the document
styleElement = this.renderer.createElement('style');
const styleText = this.renderer.createText(styleRules);
this.renderer.appendChild(styleElement, styleText);
this.renderer.appendChild(document.head, styleElement);
// Append the script to the body of the document
scriptElement = this.renderer.createElement('script');
const scriptText = this.renderer.createText(scriptCode);
this.renderer.appendChild(scriptElement, scriptText);
this.renderer.appendChild(document.body, scriptElement);
// Sanitize and assign the HTML content to the component property
const safeHtml = this.sanitizer.bypassSecurityTrustHtml(
doc.documentElement.outerHTML
);
this.htmlContent = safeHtml;
});
}
What have a done wrong here? can someone please help?
Please use the app link in the stack blitz for coding samples.

how to add a (click) function inside the .ts

I am working on a solution to rewrite links in an HTML element.
I get HTML information via a JSON string 'spanClass1'. In this string I need to rewrite a class to a link. This works wonderfully. Unfortunately, I use hash routing in Angular and can only link further via the toDocument() function. It doesn't work via a normal link name tag
Via span.className.replace(/\D/g, '') I get the ID I need to link to the page.
Unfortunately I was not able to define an Angular (click) function including the ID to the page.
Also, I can't manipulate the code in the .html, only in the .ts.
document.ts
var div = document.createElement('div');
div.innerHTML = spanClass1;
div.querySelectorAll('[class^=doc-]').forEach(function (span) {
var anchor = document.createElement('a');
anchor.href = '/suche#/document/' + span.className.replace(/\D/g, '');
anchor.href = span.className.split('doc-')[1];
anchor.innerHTML = span.innerHTML;
span.parentNode.replaceChild(anchor, span);
});
spanClass1 = div.innerHTML;
toDocument(id) {
window.open('/suche#/document/' + id);
}
JSON
"spanClass1": "blablablablabla <span class=\"doc-158 \">Radleuchter,</span> blablablabla"
How do I add a (click)="toDocument(123)" function to the <a> tag inside the Component.
It seems that you want to add a event listener to a div you are creating at run time. A possible approach is to use the Renderer2 API, as provided by the Angular Team.
In this case, your code would look like the following:
In the constructor:
construct(private _renderer2: Renderer2, ...) { ... };
In the method where you create the div:
var div = document.createElement('div');
this._renderer2.listen(div, 'click', (event) => {
// Code to be run here or callback.
}
div.innerHTML = spanClass1;
...
Furthermore, I would advise some caution on changing the DOM directly. It's best to use the renderer for this since it comes with built it methods that are far safer and expose less risks.
You want to add an event listener to each a and listen for the click event. There are a few pieces of your code that I don't fully understand, but it's basically this:
function toDocument(id) {
window.open('/suche#/document/' + id);
}
var div = document.createElement('div');
div.innerHTML = spanClass1; // what is this?
div.querySelectorAll('[class^=doc-]').forEach(function (span) {
var anchor = document.createElement('a');
var id = span.className.split('doc-')[1];
anchor.href = '/suche#/document/' + span.className.replace(/\D/g, '');
anchor.innerHTML = span.innerHTML;
anchor.addEventListener('click', function() {
toDocument(id);
})
span.parentNode.replaceChild(anchor, span);
});
spanClass1 = div.innerHTML;

Using html2canvas action is working just once and i need the code works multiple times

im creating a web app using some html2canvas, the idea is: an user uploads a photo then choose a png image from a library to place over the image and the the user can download the image with the sticker aplied. Everything is working fine the first time, but when i try to use the download button a second time nothing happens. The console shows the following error:
Uncaught TypeError: Cannot set property 'id' of null at HTMLButtonElement.capture (index.html:82)
The line number 82 is: body.id = 'CapturaPantalla';
How could i reset the code everytime so the user could download the image multiple times?
This is the code:
<script>
const capture = () => {
const body = document.querySelector('#ImagenLista');
body.id = 'CapturaPantalla';
html2canvas(document.querySelector("#CapturaPantalla")).then(canvas => {
document.body.appendChild(canvas);
}).then(() => {
var canvas = document.querySelector('canvas');
canvas.style.display = 'none';
var image = canvas.toDataURL("image/jpg").replace("image/jpg", "image/octet-stream");
var a = document.createElement("a");
a.setAttribute('download', 'YoSoyYVoyA.jpg');
a.setAttribute('href', image);
a.click();
});
};
const btn = document.getElementById('DescargaImagen');
function FuncionDescarga() {
btn.addEventListener('click', capture);
}
</script>
Thanks everyone in advance.
First, you are getting an element:
const body = document.querySelector('#ImagenLista');
Then, you change the ID of the element:
body.id = 'CapturaPantalla';
So when you go to select the element again, it has a different ID, therefore returning null.
The solution should be obvious, but if for some reason you have to keep line 82, you can do this:
if (body) {
body.id = 'CapturaPantalla';
}
And a more compressed version:
body && (body.id = 'CapturaPantalla');

Returned JavaScript value wont render inside a div element

This a basic question (Posting this again, as it was not re-opened after I updated the question). But I couldn't find any duplicates on SO.
This is a script I intend to use in my project on different pages. The purpose is to override the default ID shown in a span element to the order number from the URL parameter session_order. This doesn't affect anything and only enhances the UX for my project.
scripts.js (loaded in the header):
function get_url_parameter(url, parameter) {
var url = new URL(url);
return url.searchParams.get(parameter);
}
And in my HTML template, I call the function this way,
<div onload="this.innerHTML = get_url_parameter(window.location.href, 'session_order');">24</div>
Also tried this,
<div><script type="text/javascript">document.write(get_url_parameter(window.location.href, 'session_order'));</script></div>
When the page is rendered, nothing changes. No errors or warnings in the console either for the first case.
For the second case, console logged an error Uncaught ReferenceError: get_url_parameter is not defined, although script.js loads before the div element (without any errors).
Normally, I'd do this on the server-side with Flask, but I am trying out JavaScript (I am new to JavaScript) as it's merely a UX enhancement.
What am I missing?
Try this:
// This is commented because it can't be tested inside the stackoverflow editor
//const url = window.location.href;
const url = 'https://example.com?session_order=13';
function get_url_parameter(url, parameter) {
const u = new URL(url);
return u.searchParams.get(parameter);
}
window.onload = function() {
const el = document.getElementById('sessionOrder');
const val = get_url_parameter(url, 'session_order');
if (val) {
el.innerHTML = val;
}
}
<span id="sessionOrder">24</span>
Define the function you need for getting the URL param and then on the window load event, get the URL parameter and update the element.
Here you go. Try to stay away from inline scripts using document.write.
function get_url_parameter(url, parameter) {
var url = new URL(url);
return url.searchParams.get(parameter);
}
window.addEventListener('load', function() {
const url = 'https://yourpagesdomain.name/?session_order=hello'; //window.location.href;
const sessionOrder = get_url_parameter(url, 'session_order');
document.getElementById('sessionOrder').innerText = sessionOrder;
});
<div id="sessionOrder"></div>
The order of your markup and script matters...
<div></div>
<script>
function get_url_parameter(url, parameter) {
var url = new URL(url);
return url.searchParams.get(parameter);
}
</script>
<script>
document.querySelector('div').innerHTML = get_url_parameter('https://example.com?session_order=2', 'session_order');
</script>

How to get input values from html to text file

I have tried so many examples but none of them works
t
(function() {
var textFile = null,
makeTextFile = function(text) {
var data = new Blob([text], {
type: 'text/plain'
});
// If we are replacing a previously generated file we need to
// manually revoke the object URL to avoid memory leaks.
if (textFile !== null) {
window.URL.revokeObjectURL(textFile);
}
textFile = window.URL.createObjectURL(data);
return textFile;
};
var create = document.getElementById('create'),
textbox = document.getElementById('textbox');
create.addEventListener('click', function() {
var link = document.getElementById('downloadlink');
link.href = makeTextFile(textbox.value);
link.style.display = 'block';
}, false);
})();
<textarea id="textbox">Type something here</textarea>
<button id="create">Create file</button>
<a download="info.txt" id="downloadlink" style="display: none">Download</a>
here is a code which is working good but i need to download automatically without using link
is it possible?
You could use the following script to create and save automatically a file from the browser to your operating system. This code works only on latest version of Chrome.
What the script does?
It creates a temporary URL containing the specified File object or Blob object - Programmatically click the link just created so the file will be download by the browser.
Immediately after remove the link from the page.
var saveDataToFile = function (data, fileName, properties) {
window.URL = window.URL || window.webkitURL;
var file = new File(data, fileName, properties),
link = document.createElement('a');
link.href = window.URL.createObjectURL(file);
link.download = fileName;
document.body.appendChild(link);
link.click();
var timer = setTimeout(function () {
window.URL.revokeObjectURL(link.href);
document.body.removeChild(link);
clearTimeout(timer);
}, 100);
};
If you deconstruct this problem, there's a few key points:
Initially, when the user hasn't typed text into the textarea, the button should not be visible. (I may be wrong here though)
When the user starts typing, the button has to appear.
Whatever is inside the textarea after that, has to be downloadable per click on the button.
So, it's a matter of two event listeners.
The first one is "focus": when the textarea received focus, its value is an empty string, and the button appears. The user hasn't yet started typing, but there's actually no need to force them to.
The second one is "change": per every change in the field, we need to update the value of href attribute of the link, so that when the user clicks that element, file download happens, and the content is precisely what's inside the textarea. Good thing, a function passed to "change" event listener is executed with the first argument instance of Event, which means you can do event.target.value to get the new value per every change. It means, the whole text from within textarea.
Summing up, it's
<textarea id="textbox" placeholder="Type something here"></textarea>
<a download="info.txt" id="create" href="#" style="display: none;">Create file</a>
and
(function() {
var textFile = null,
makeTextFile = function(text) {
var data = new Blob([text], {
type: 'text/plain'
});
// If we are replacing a previously generated file we need to
// manually revoke the object URL to avoid memory leaks.
if (textFile !== null) {
window.URL.revokeObjectURL(textFile);
}
textFile = window.URL.createObjectURL(data);
return textFile;
};
var create = document.getElementById('create');
var textbox = document.getElementById('textbox');
textbox.addEventListener('focus', function (event) {
create.style.display = 'block';
create.href = makeTextFile(''); // initially, the text is empty.
});
textbox.addEventListener('change', function (event) {
create.href = makeTextFile(event.target.value); // per every change, update value of href attribute of #create
});
})();
Take note that only a element can have href assigned with Blob value. Using a button element would be a little bit more complicated, so it might be easier to just make the a element look like a button.
See the Codepen to make sure it works as you expect, or feel free to edit it otherwise.

Categories

Resources