In this article, we are going to see what is Handsontable, how to integrate Handsontable and most importantly, how to handle images in Handsontable cells. Let’s get into it! For starters, let us see
What is Handsontable?
Handsontable is a free and open-source JavaScript plugin, which is a made up of several spreadsheet components for apps and websites. It is written in JavaScript and not constrained by any external framework. With Handsontable, you can easily do all CRUD operations and provide end-users with an Excel-like experience.
Sometime back, I had this requirement to handle images in the table. To be precise, I had to edit the inline table with images. Although Handsontable provides many cool features like Excel, handling images in Handsontable is quite difficult. In my website (project), I used Handsontable to display user data grid with inline edit feature. The exact requirement was to upload an image from a cell. On searching for a solution I got to know that we can customize cell the editor with the Handsontable. With a custom cell editor, I worked on uploading an image and it was successful.
ALSO READ: 10 Useful Tools For Laravel Development
Let me walk you through the steps I followed:
Installing Handsontable:
There are many ways to install Handsontable. For an instant fix, you can work on jSFiddle.
- Install using Bower package manager.
bower install handsontable --save <script src="/dist/handsontable.full.js"></script> <link rel="stylesheet" media="screen" href="/dist/handsontable.full.css"
- Download Handsontable from GitHub.
https://github.com/handsontable/handsontable/archive/master.zip
- Embed script with CDN URL.
<script src="http://handsontable.com/dist/handsontable.full.js"></script> <link rel="stylesheet" media="screen" href="https://docs.handsontable.com/5.0.0/components/handsontable/dist/handsontable.full.css">
Basic Example of Handsontable:
<div id="sample"></div> var data = [ ["", "Audi", "Benz", "Toyota", "Honda"], ["2014", 10, 11, 12, 13], ["2015", 20, 11, 14, 13], ["2016", 30, 15, 12, 13] ]; var container = document.getElementById('sample'); var hot = new Handsontable(container, { data: data, minSpareRows: 1, rowHeaders: true, colHeaders: true, contextMenu: true });
Handling image in Handsontable:
Basically, we can build a new editor from scratch, by creating a new editor class, which inherits from BaseEditor, or if you just want to enhance an existing editor, you can extend its class and override only a few of its methods.
For my process, I will create an UploadEditor which works exactly like regular TextEditor except that it displays an images input instead of the text area. While customising the editor we should override the following methods:
- setValue
- getValue
- focus
- close
Let’s begin with the UploadEditor. Following is the code for the same:
var UploadEditor = Handsontable.editors.TextEditor.prototype.extend(); UploadEditor.prototype.createElements = function() { Handsontable.editors.TextEditor.prototype.createElements.apply(this, arguments); this.TEXTAREA = document.createElement('input'); this.TEXTAREA.setAttribute('type', 'file'); this.TEXTAREA.setAttribute('id', 'filechange' + this.row); this.TEXTAREA.className = 'handsontableInput'; this.textareaStyle = this.TEXTAREA.style; this.textareaStyle.width = 0; this.textareaStyle.height = 0; Handsontable.Dom.empty(this.TEXTAREA_PARENT); this.TEXTAREA_PARENT.appendChild(this.TEXTAREA); hands = this; $('#filechange' + this.row).change(function() { var data = new FormData(); data.append('file', $(this).prop('files')[0]); current = hot.getSourceDataAtRow(hands.row); $.each(current, function(index, value) { data.append(index, value); }); $.ajax({ type: 'POST', processData: false, // important contentType: false, // important data: data, url: "server.php", success: function(data) { $(this).attr('src', data); hands.TEXTAREA.src = data; } }); }); }; UploadEditor.prototype.setValue = function(newValue) { this.TEXTAREA.src = newValue; }; UploadEditor.prototype.focus = function() { this.TEXTAREA.focus(); }; UploadEditor.prototype.getValue = function() { return this.TEXTAREA.src; }; UploadEditor.prototype.close = function() { this.TEXTAREA_PARENT.style.display = 'none'; this.autoResize.unObserve(); if (document.activeElement === this.TEXTAREA) { this.instance.listen(); } };
Here I have created a new editor class, that inherits from TextEditor and then override some of its methods to replace the <textarea> with input:file. But, Handsontable cannot handle file input like <textarea>, so we have written some external script to handle file input and you may notice that it calls internal createElements() method, which creates <textarea> node and appends it to DOM during editor initialization.
ALSO READ: Build A Micro-Frontend Application Using Angular Elements
Here is the code to render custom HTML/image in Table Cell:
function coverRenderer (instance, td, row, col, prop, value, cellProperties) { var escaped = Handsontable.helper.stringify(value), img; if (escaped.indexOf('http') === 0) { img = document.createElement('IMG'); img.src = value; img.setAttribute('width', '120px'); Handsontable.Dom.addEvent(img, 'mousedown', function (e){ e.preventDefault(); // prevent selection quirk }); Handsontable.Dom.empty(td); td.appendChild(img); } else { // render as text Handsontable.renderers.TextRenderer.apply(this, arguments); } return td; }
Here, did you see that I have written custom render function named coverRenderer()? This will add the image URL into the HTML IMG tag so that the required image will be displayed in the table cell.
Following is the script to render the Handsontable that has been created for the purpose:
var data = [ {"car":"Benz","year":"2001","image_url":"[IMAGE_URL]"}, {"car":"Honda","year":"2005","image_url":"[IMAGE_URL]"} {"car":"Audi","year":"2000","image_url":"[IMAGE_URL]"} ]; var columns = [{ data: "car", type: 'text' }, { data: "year", type: "text" }, { data: "image_url", renderer:coverRenderer, editor: UploadEditor } ]; var container = document.getElementById('sample'); var hot = new Handsontable(container, { data: data, minSpareRows: 1, rowHeaders: true, colHeaders: true, contextMenu: true });
To save the image into the local server, inside the server.php,
<?php if(isset($_FILES['file']['tmp_name'])) { $tmp_name = $_FILES['file']['tmp_name']; $name = $_FILES['file']['name']; $type1 = pathinfo($name, PATHINFO_EXTENSION); $data = file_get_contents($tmp_name); $image_data = 'data:image/' . $type1 . ';base64,' . base64_encode($data); list($image_width, $image_height, $image_type, $attr) = getimagesize($tmp_name); $datas = explode(',', $image_data); $decode = base64_decode($datas[1]); $path = "[PATH_TO_UPLOAD]"; $filename = $name.".".$image_type; file_put_contents ( $path.$filename , $decode ); return $path.$filename; } ?>
HTML Code:
<html> <head> <script src="http://handsontable.com/dist/handsontable.full.js"></script> <link rel="stylesheet" media="screen" href="http://handsontable.com/dist/hand sontable.full.css"> </head> <body> <div id="sample"></div> </body> </html>
Conclusion:
As you can see, the CustomEditor is a cool feature available in Handsontable. Using this feature we can create our own editor. The example that we discussed above provides a clearer picture of how to achieve inline editing and customising the Handsontable plugin to handle images in Handsontable. For more information, refer to Handsontable Documents.
Happy Reading!!!