Hi community!
Is there way to create button for image so user will be able to download image by pressing the button? ![]()
Hi community!
Is there way to create button for image so user will be able to download image by pressing the button? ![]()
is it work?
what is in template finally?
I didnât found any template having the âdownloadâ tag. ![]()
As I explain in the other post, you need to create a Template column in the data editor. In that template column, add the HTML that includes the âdownloadâ attribute, as explained in the attached link in my other post. Instead of entering a url for the href attribute, set up a replacement value. Maybe something like {url}, and replace it with your actual url.
So the template should look something like this:
<a href="{url}" download>Download File</a>
And all you need to do is set up a replacement for {url}.
Finally display that HTML using a rich text component.
Hi Jeff! What im doing wrong?
upd: corrected video
Upd: yes in this video im showing construct column but using template colemn in act
Youâre using a construct url column. What I explain uses a Template column. You need to build an âa hrefâ HTML tag. Not a url with query parameters.
Exactly Jeff im using template column
I guess the problem is this:
âIn the latest versions of Chrome, you cannot download cross-origin files (they have to be hosted on the same domain).â.
im using Edge not Chrome
@roope257 @slscustom.ru In all fairness, I havenât tried this myself, or at least havenât tried it in a couple of years. If I get a chance, Iâll test it out later tonight.
@slscustom.ru Iâm not sure why you have the extra New Column C template column. The replacement in New Column F could directly refer to the photo column. But either way should give you the same result, so it shouldnât make a difference.
Hi @Jeff_Hager ,
Is there something for user to be able to download video file as well, irrespective of device type, ?
By Using a button which initiates the download?
Also what if there are array of image link? Like carousel ?
Regards,
Dilip
Hi @Jeff_Hager ,
I got it to work by actioning it on a button.
My Approach :
I hosted a html code in GitHub Pages For Zipping the content file (Image or Video) then downloading it.
PS: Zipping is not reducing the quality, its just so that browsers register it to download file.
My HTML code is as follows : It includes loading indicator too
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Download File with Zipping</title>
<!-- Include JSZip Library -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.7.1/jszip.min.js"></script>
<style>
/* Simple spinner styles */
.spinner {
border: 6px solid #f3f3f3; /* Light grey */
border-top: 6px solid #3498db; /* Blue */
border-radius: 50%;
width: 40px;
height: 40px;
animation: spin 1s linear infinite;
display: none; /* Hidden by default */
margin: 20px auto;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
</style>
</head>
<body>
<h1>File Download Trigger with Zipping</h1>
<p id="status">Preparing to download...</p>
<!-- Loading spinner -->
<div class="spinner" id="loadingSpinner"></div>
<script>
window.onload = function() {
const urlParams = new URLSearchParams(window.location.search);
const fileUrl = urlParams.get('fileUrl'); // Get the file URL from the query parameter
const loadingSpinner = document.getElementById('loadingSpinner');
loadingSpinner.style.display = 'block'; // Show the loading spinner
if (fileUrl) {
// Extract the file name from the URL
const fileName = fileUrl.substring(fileUrl.lastIndexOf('/') + 1);
// Fetch the image or file as a blob (binary data)
fetch(fileUrl)
.then(response => response.blob()) // Convert response to a binary blob
.then(blob => {
const zip = new JSZip(); // Create a new JSZip instance
zip.file(fileName, blob, { binary: true }); // Add the binary file to the zip with the correct filename
// Generate the zip file and trigger download
zip.generateAsync({ type: "blob" }).then(function(content) {
loadingSpinner.style.display = 'none'; // Hide the loading spinner once done
const zipLink = document.createElement('a'); // Create a hidden download link
zipLink.href = URL.createObjectURL(content); // Create a URL for the zip
zipLink.setAttribute('download', 'files.zip'); // Name the downloaded zip as "files.zip"
document.body.appendChild(zipLink); // Append the link to the body
zipLink.click(); // Trigger the download
zipLink.remove(); // Clean up by removing the link
// Wait a short delay and attempt to close the tab
setTimeout(function() {
window.close(); // Close the current tab if opened by JavaScript
}, 2000); // Adjust the delay as needed
});
})
.catch(error => {
loadingSpinner.style.display = 'none'; // Hide the spinner in case of error
document.getElementById('status').textContent = 'Error fetching the file. Check the URL.';
});
} else {
loadingSpinner.style.display = 'none'; // Hide the spinner if no URLs are provided
document.getElementById('status').textContent = 'No file URL provided.';
}
}
</script>
</body>
</html>
Then I use template column where I put the url of the page
https://Youraccountname.github.io/Yourrepositoryname/?fileUrl=YourFileURL
Then add a button and on click open link and direct it to this.
Let me know if this is acceptable approach , or you have some suggestions to improve it.
Thank you in advance.
Regards,
Dilip
Two clients asked me this week how I solved this problem, so hereâs my quick take:
I wanted a solution where Glide only provides image URLs without generating ZIP files itself. At the same time, I didnât want to store actual images in the database â just the references. The result is a small but reliable setup:
1. Webhook Endpoint (Supabase Edge Function)
POST https://[project-ref].supabase.co/functions/v1/webhook-receiver
Glide sends: item_id + image_urls array
Supabase stores only the URLs in Postgres (no images)
2. Download Endpoint
GET https://[project-ref].supabase.co/functions/v1/download-images?item_id={item_id}
Fetches images on-demand from original URLs
Builds ZIP in memory
Returns {item_id}_images.zip as file download
3. Glide Template Column
https://[project-ref].supabase.co/functions/v1/download-images?item_id={Row ID}
â User clicks the link â browser downloads {item_id}_images.zip
Table: image_requests
| Column | Type | Description |
|---|---|---|
| id | UUID | Primary key |
| item_id | INTEGER | Product/Row ID from Glide |
| created_at | TIMESTAMP | Request timestamp |
Table: images
| Column | Type | Description |
|---|---|---|
| id | UUID | Primary key |
| request_id | UUID | FK to image_requests |
| image_url | TEXT | Original image URL |
| item_name_numeric | INTEGER | Sort order (0, 1, 2âŠ) |
| status | TEXT | pending/completed/failed |
| created_at | TIMESTAMP | Created timestamp |
webhook-receiver (simplified)
// Receives webhook, stores URLs in DB
const { item_id, image_urls } = await req.json();
// Create request record
const { data: request } = await supabase
.from("image_requests")
.insert({ item_id })
.select()
.single();
// Store each image URL
const images = image_urls.map((url, index) => ({
request_id: request.id,
image_url: url,
item_name_numeric: index,
status: "completed"
}));
await supabase.from("images").insert(images);
download-images (simplified)
// Get newest request for item_id
const { data: requests } = await supabase
.from("image_requests")
.select("id")
.eq("item_id", parseInt(itemId))
.order("created_at", { ascending: false })
.limit(1);
// Get all image URLs
const { data: images } = await supabase
.from("images")
.select("image_url, item_name_numeric")
.eq("request_id", requests[0].id)
.order("item_name_numeric", { ascending: true });
// Create ZIP
const zip = new JSZip();
for (const img of images) {
const response = await fetch(img.image_url);
const blob = await response.blob();
zip.file(`${img.item_name_numeric}.jpg`, blob);
}
return new Response(await zip.generateAsync({ type: "blob" }), {
headers: { "Content-Disposition": `attachment; filename="${itemId}_images.zip"` }
});
Webhook stores only URLs (no files)
Download fetches images live â always the latest version
ZIP is created in-memory and streamed
Old records auto-delete after 90 days (cleanup cron job)
Happy to share. ![]()