phpsreadsheet create excel from html table - phpspreadsheet

There is no documentation for using phpspreadsheet to form an excel file from a html table.
This is possible using "jquery.table2excel.js" but it seems pretty old; makes old excel files and makes warnings about the file.
phpspreadsheet makes a good excel file, but I just can't find any answers to do the function.

If you are generating an Excel file from pre-rendered HTML content you can do so automatically using the HTML Reader. This is most useful when you are generating Excel files from web application content that would be downloaded/sent to a user.
$htmlString = '<table>
<tr>
<td>Hello World</td>
</tr>
<tr>
<td>Hello<br />World</td>
</tr>
<tr>
<td>Hello<br>World</td>
</tr>
</table>';
$reader = new \PhpOffice\PhpSpreadsheet\Reader\Html();
$spreadsheet = $reader->loadFromString($htmlString);
$writer = \PhpOffice\PhpSpreadsheet\IOFactory::createWriter($spreadsheet, 'Xls');
$writer->save('write.xls');
You can read more in this link

Use the HTML Reader to read the data into a Spreadsheet, then the appropriate writer (xls or xlsx)

You can use sheetJS library to convert custom html table to xslx.
Working Code sample :
<script type="text/javascript" src="//unpkg.com/xlsx/dist/shim.min.js"></script>
<script type="text/javascript" src="//unpkg.com/xlsx/dist/xlsx.full.min.js"></script>
<script type="text/javascript" src="//unpkg.com/blob.js#1.0.1/Blob.js"></script>
<script type="text/javascript" src="//unpkg.com/file-saver#1.3.3/FileSaver.js"></script>
<div id="container2">
<title>SheetJS Table Export</title>
<table id="data-table">
<tr>
<td>ID</td>
<td>Name</td>
</tr>
<tr>
<td>1</td>
<td>Johnny</td>
</tr>
</table>
</div>
<p id="xportxlsx" class="xport"><input type="submit" value="Export to XLSX!" onclick="doit('xlsx');"></p>
<script type="text/javascript">
function doit(type, fn, dl) {
var elt = document.getElementById('data-table');
var wb = XLSX.utils.table_to_book(elt, {sheet:"Sheet JS"});
return dl ?
XLSX.write(wb, {bookType:type, bookSST:true, type: 'base64'}) :
XLSX.writeFile(wb, fn || ('test.' + (type || 'xlsx')));
}
function tableau(pid, iid, fmt, ofile) {
if(typeof Downloadify !== 'undefined') Downloadify.create(pid,{
swf: 'downloadify.swf',
downloadImage: 'download.png',
width: 100,
height: 30,
filename: ofile, data: function() { return doit(fmt, ofile, true); },
transparent: false,
append: false,
dataType: 'base64',
onComplete: function(){ alert('Your File Has Been Saved!'); },
onCancel: function(){ alert('You have cancelled the saving of this file.'); },
onError: function(){ alert('You must put something in the File Contents or there will be nothing to save!'); }
});
}
tableau('xlsxbtn', 'xportxlsx', 'xlsx', 'test.xlsx');
</script>

Related

ASP.NET MVC view with dropzone hangs on the server

I am using ASP.NET MVC to develop my application.
My view is been supported by Dropzone library written in Javascript.
FUNCTION: upload one or multiple files to the controller. It returns an object to the same view with the uploaded file(s), so the user can label each uploaded file with the type of file.
ISSUE: after testing, my conclusion is that the configuration and use of Dropzone.js in my view (see below) for some reason hangs the execution of the application. What I mean, is that the code under the if {} condition in the view is not being rendered.
It looks to me, like the page in the server is never refreshed when the controller calls the cshtml page. So it always produces the same output result, under all conditions.
If I use the code <input type="file" name="files" multiple/> then the app it will work.
CSHTML markup:
<div class="col ml-2">
<table id="UploadedDataTable" border="1" class="blueTable display nowrap" style="width:100%">
<thead>
<tr>
<th scope="col" style="text-align:center" width="65%" title="Uploaded file name">Uplodaded file name</th>
<th style="text-align:center" title="Uploaded file type">Document Type</th>
</tr>
</thead>
<tbody>
#if (Model.UploadedFiles != null && Model.UploadedFiles.Attachments.Count > 0)
{
for (int i = 0; i < Model.UploadedFiles.Attachments.Count; i++)
{
<tr>
<td>#Model.UploadedFiles.Attachments[i].Name</td>
#if (string.IsNullOrEmpty(Model.UploadedFiles.Attachments[i].DocumentType))
{
Model.UploadedFiles.Attachments[i].DocumentType = ISAA.Business.Models.Invoices.InvoicesParameters.getInstance().GetDocumentType()[0].Code;
<td>Doc. Type: #Html.DropDownListFor(m => Model.UploadedFiles.Attachments[i].DocumentType, new SelectList(ISAA.Business.Models.Invoices.InvoicesParameters.getInstance().GetDocumentType(), "Code", "Name"), " - Select Document Type -", new { #class = "form-control form-control-sm", aria_describedby = "shipment-entry-19" })</td>
}
else
{
<td>Doc. Type: #Html.DropDownListFor(m => Model.UploadedFiles.Attachments[i].DocumentType, new SelectList(ISAA.Business.Models.Invoices.InvoicesParameters.getInstance().GetDocumentType(), "Code", "Name"), " - Select Document Type -", new { #class = "form-control form-control-sm", aria_describedby = "shipment-entry-19" })</td>
}
</tr>
}
}
</tbody>
</table>
<small>Define correctly the Document Type</small>
</div>
Javascript (dropzone configuration):
#section scripts {
#Scripts.Render("~/bundles/jquery")
#Scripts.Render("~/bundles/dropzone")
<script type="text/javascript">
$(document).ready(function () {
Dropzone.autoDiscover = false;
$('#myDropzone').dropzone({
//parameter name value
paramName: "files",
//clickable div id
clickable: '#previews',
//preview files container Id
previewsContainer: "#previewFiles",
uploadMultiple: true,
parallelUploads: 100,
maxFiles: 100,
// url:"/", // url here to save file
maxFilesize: 100,//max file size in MB,
addRemoveLinks: true,
dictResponseError: 'Server not Configured',
acceptedFiles: ".cvs,.xls,.xlsx,.pdf",// use this to restrict file type
init: function () {
var self = this;
// config
self.options.addRemoveLinks = true;
self.options.dictRemoveFile = "Delete";
//New file added
self.on("addedfile", function (file) {
console.log('new file added ', file);
$('.dz-success-mark').hide();
$('.dz-error-mark').hide();
});
// Send file starts
self.on("sending", function (file) {
console.log('upload started', file);
$('.meter').show();
});
// File upload Progress
self.on("totaluploadprogress", function (progress) {
console.log("progress ", progress);
$('.roller').width(progress + '%');
});
// On removing file
self.on("removedfile", function (file) {
console.log(file);
});
$('#Submit').on("click", function (e) {
e.preventDefault();
e.stopPropagation();
// Validate form here if needed
if (self.getQueuedFiles().length > 0) {
self.processQueue();
} else {
self.uploadFiles([]);
$('#myDropzone').submit();
}
});
self.on("successmultiple", function (files, response) {
// Gets triggered when the files have successfully been sent.
// Redirect user or notify of success.
});
}
});
})
</script>
}

jQuery UI : Problem with datepicker on smartphones

I created a web site in ASP.NET Core MVC, using bootstrap and jquery-ui. The site works well in a desktop.
However in a smartphone, when I want to pick a date with jquery-ui datepicker, the calendar window appears in the wrong position…, outside of the partial window that contains the date input.
My View is:
#using (Html.BeginForm(FormMethod.Post, new { #class = "form-group" }))
{
<table id="ProdTable" class="table">
<tbody id="ProdTable">
#foreach (var p in Model)
{
<tr id="tableRow" data-key="#p.lineid">
<td><input asp-for="#p.paData" type="date"
class="appDatePickClass" autocomplete="off" /></td>
</tr>
</tbody>
</table>
}
<script type="text/javascript">
// setting the Date Picker that I want.
$(document).ready(function () {
$(".appDatePickClass").attr('type', 'text');
$(".appDatePickClass").datepicker({
dateFormat: "yy-mm-dd"
});
});
</script>
Thank you.
Try this work around to adjust position of datepicker after it opens (please adjust position as per your requirement)
<script type="text/javascript" language="javascript">
$(function(){
$("#appDatePickClass").datepicker({ dateFormat:'yy-mm-dd'});
// bind click event and adjust datepicker position.
$(".hasDatepicker").click(function(e){
$("#ui-datepicker-div").css({'top':e.pageY+20,'left':e.pageX-250});
});
});
</script>
and make sure you have :
at top.

How to open the same jQuery Dialog from dynamically and non-dynamically created controls

I need to open the same jQuery dialog from different input text controls (including those that have been created dynamically)
This is what my page displays when it loads for the first time.
When the user presses the "Add" button a new row is added to the table
So far so good. The problem comes when I have to open the dialog that will let users enter text into the inputs ( the dialog will display upon clicking on them)
At first , I thought it would only be necessary to add a class to all the controls and then using the class selector just call the dialog.
Unfortunately then I learned that with dynamic controls you have to use ".on" to attach them events.
Once overcome these difficulties , I run into one more that I haven't been able to solve yet. This is that if you don't want the dialog to be automatically open upon initialization, you have to set "autoOpen" to false. I did so but the only result I got was that none on the inputs worked.
I have also tried putting all the code ,regarding the dialog, into a function and then calling that function when an input is clicked
I did also try declaring a variable and setting that variable to the dialog , something like this:
var dialog= $( "#dialog" )
But it didn't work either
I have tried some possibles solutions , but no luck as of yet.
EDIT : Here's a fiddle so you can have a better idea of what I'm talking about:
http://jsfiddle.net/3BXJp/
Full screen result: http://jsfiddle.net/3BXJp/embedded/result/
Here is the html code for the aspx page (Default.aspx):
<form id="form1" runat="server">
<div>
<fieldset>
<legend>Expression Builder</legend>
<table id="myTable" class="order-list">
<thead>
<tr>
<td colspan="2">
</td>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: right;">
IF(<input type="text" name="condition1" class="showDialog" />
:
</td>
<td>
<input type="text" name="trueValue" class="showDialog" />
)
</td>
<td>
<a class="deleteRow"></a>
</td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="5" style="text-align: left;">
<input type="button" id="addrow" value="+ Add" />
</td>
</tr>
<tr>
<td colspan="">
ELSE (
<input type="text" name="else" id="else" class="showDialog" />)
</td>
</tr>
</tfoot>
</table>
</fieldset>
<br />
<input type="button" id="btnEnviar" value="Send" />
</div>
<div id="dialog-form" title="Add New Detail">
<p>
All the fields are required.</p>
<table>
<tr>
<td>
<label for="condition" id="lblcondition">
Condition</label>
</td>
<td>
<input type="text" name="condition" id="condition" class="text ui-widget-content ui-corner-all" />
</td>
</tr>
<tr>
<td>
<label for="returnValue" id="lblreturnValue">
Return Value</label>
</td>
<td>
<input type="text" name="returnValue" id="returnValue" class="text ui-widget-content ui-corner-all" />
</td>
</tr>
</table>
</div>
</form>
and here is the javascript code:
<script type="text/javascript">
$(document).ready(function () {
var counter = 0;
$("button, input:submit, input:button").button();
$('input:text').addClass("ui-widget ui-state-default ui-corner-all");
var NewDialog = $("#dialog-form");
NewDialog.dialog({ autoOpen: false });
var Ventana = $("#dialog-form");
$("#addrow").on("click", function () {
var counter = $('#myTable tr').length - 2;
$("#ibtnDel").on("click", function () {
counter = -1
});
var newRow = $("<tr>");
var cols = "";
cols += '<td>ELSE IF(<input type="text" name="condition' + counter + '" class="showDialog1" /> </td>';
cols += '<td>: <input type="text" name="TrueValue' + counter + '" class="showDialog1" />)</td>';
cols += '<td><input type="button" id="ibtnDel" value="-Remove"></td>';
newRow.append(cols);
var txtCondi = newRow.find('input[name^="condition"]');
var txtVarlorV = newRow.find('input[name^="TrueValue"]');
newRow.find('input[class ="showDialog1"]').on("click", function () {
//Seleccionar la fila
$(this).closest("tr").siblings().removeClass("selectedRow");
$(this).parents("tr").toggleClass("selectedRow", this.clicked);
Ventana.dialog({
autoOpen: true,
modal: true,
height: 400,
width: 400,
title: "Builder",
buttons: {
"Add": function () {
txtCondi.val($("#condition").val());
txtVarlorV.val($("#returnValue").val());
$("#condition").val("");
$("#returnValue").val("");
$(this).dialog("destroy");
},
Cancel: function () {
//dialogFormValidator.resetForm();
$(this).dialog("destroy")
}
},
close: function () {
$("#condition").val("");
$("#returnValue").val("");
$(this).dialog("destroy")
}
});
return false;
});
$("table.order-list").append(newRow);
counter++;
$("button, input:submit, input:button").button();
$('input:text').addClass("ui-widget ui-state-default ui-corner-all");
});
$("table.order-list").on("click", "#ibtnDel", function (event) {
$(this).closest("tr").remove();
});
$("#btnEnviar").click(function () {
//Armo el objeto que servira de parametro, para ello utilizo una libreria JSON
//Este parametro mapeara con el definido en el WebService
var params = new Object();
params.Expresiones = armaObjeto();
$.ajax({
type: "POST",
url: "Default.aspx/Mostrar",
data: JSON.stringify(params),
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (data, textStatus) {
if (textStatus == "success") {
loadMenuVar(data);
}
},
error: function (request, status, error) {
alert(jQuery.parseJSON(request.responseText).Message);
}
});
});
$(".showDialog").click(function () {
Ventana.dialog({
autoOpen: true,
modal: true,
height: 400,
width: 400,
title: "Constructor",
buttons: [
{ text: "Submit", click: function () { doSomething() } },
{ text: "Cancel", click: function () { $(this).dialog("destroy") } }
],
close: function () {
$(this).dialog("option", "autoOpen", false);
$(this).dialog("destroy")
}
});
return false;
});
});
This is the closest I've been able to get to the solution, but still can't get the dialog to remain hidden until a input is clicked
Any advise or guidance would be greatly appreciated.
P.S. Sorry for my bad english
I suspect it's because you're using destroy() rather than close() on the dialog. At the moment it looks like you're creating and destroying the dialog each time, don't do that. You should create the dialog once, isolate the dialog functionality to a separate function, and then just use open() and close() on it (you'll have to do some extra work to get the values into the right fields).
You can make your current code work if you style the dialog as hidden it'll stop happening, add this to your HTML (in the <HEAD>):
<style>
#dialog-form {
display: none;
}
</style>
you should probably have a separate style-sheet file you include that has that style in it. Similarly you should put all your JS in a separate file if it isn't already.
But I'd definitely look at re-writing the whole thing to follow the guidelines above, it does look like it can be made a lot simpler which makes it easier to support in the future.
EDIT
This is a simplified version that shows how I would do it.
Script:
var counter = 1; // Counter for number of rows
var currentRow = null; // Current row selected when dialog is active
// Create the dialog
$("#dialog-form").dialog({
autoOpen: false,
dialogClass: "no-close", // Hide the 'x' to force the user to use the buttons
height: 400,
width: 400,
title: "Builder",
buttons: {
"OK": function(e) {
var currentElem = $("#"+currentRow); // Get the current element
currentElem.val($("#d_input").val()); // Copy dialog value to currentRow
$("#d_input").val(""); // Clear old value
$("#dialog-form").dialog('close');
},
"Cancel": function(e) {
$("#d_input").val(""); // Clear old value
$("#dialog-form").dialog('close');
}
}
});
// This function adds the dialog functionality to an element
function addDialog(elemId) {
elem = $("#"+elemId);
elem.on('click', function() {
currentRow = $(this).attr('id');
$("#dialog-form").dialog('open');
});
}
// Add functionality to the 'add' button
$("#addRow").on('click', function () {
counter = counter + 1;
var newId = "in"+counter;
var newRow = "<tr><td><input id='"+newId+"' class='showDialog'></td></tr>";
$('TBODY').append(newRow);
// add the dialog to the new element
addDialog(newId);
});
// add the dialog to the first row
addDialog("in1");
HTML:
<div>
<fieldset>
<legend>Expression Builder</legend>
<table id="myTable" class="order-list">
<tbody><tr>
<td><input id='in1' class='showDialog'></td>
</tr>
</tbody>
</table>
<input type='button' id='addRow' value='add'></input>
</fieldset>
<br />
<input type="button" id="btnEnviar" value="Send" />
</div>
<div id="dialog-form" title="Add New Detail">
<input type="text" id="d_input" />
</div>
Fiddle
This isolates the different functionality into different functions. You can easily expand it to do what you want. If you want the remove functionality I'd consider having a remove button for every row with a given class with a trigger function that removes that row (and the button). Then have a separate count of active rows. At the start use disable() to disable the single button, when you add a row enable() all the buttons of that class. When you remove a row then disable the buttons is existingRows <= 1.

ASP.NET MVC - Iframe Download Dialog not showing up

I need to make a file download that displays a loading icon during the processing of the file (because I don't know how long it is going to take), I decided to use an iframe, the code runs fine, but the problem is that the file download dialog box doesn't show up.
I've tested in IE, Firefox and Chrome and it is not working in any of them.
Here's my code:
View:
<table id="progress" style="visibility:hidden">
<tr>
<td>
<img src="~/Content/Images/ajax-loader.gif" />
</td>
<td>
<h4>please wait.</h4>
</td>
</tr>
</table>
<div class="buttons">
<input type="button" value="Ok" class="button" id="downloadButton">
</div>
<iframe id="iframe" style="visibility:hidden"></iframe>
<script>
$(document).ready(function () {
$('#downloadButton').click(function () {
$('#progress').show();
$('input:button').attr("disabled", true);
$('#iframe').src = "#Url.Action("GenerateFile", "Files", null)";
$('#iframe').load("GenerateFile", function () {
$('input:button').attr("disabled", false);
$('#progress').hide();
});
});
});
</script>
Server side Action:
[HttpGet]
public void GenerateFile(Filters viewModel)
{
var result = GetCustomers().WithName(viewModel.Name);
StringBuilder file = new StringBuilder();
foreach (var customer in result)
{
// fill up the string builder with csv format
}
System.Web.HttpContext.Current.Response.AddHeader("content-disposition","attachment; filename=Customers.csv");
System.Web.HttpContext.Current.Response.ContentType = "application/csv";
System.Web.HttpContext.Current.Response.Write(file);
System.Web.HttpContext.Current.Response.End();
}
Any help would be appreciated, thanks!
I think there are multiple problems with this code. Try this:
public FileResult GenerateFile(Filters viewModel)
{
var result = GetCustomers().WithName(viewModel.Name);
StringBuilder file = new StringBuilder();
foreach (var customer in result)
{
// fill up the string builder with csv format
}
var content = Encoding.UTF8.GetBytes(file.ToString());
return File(content, "application/csv", "Customers.csv");
}
and I think there is no jQuery method called src, so try this also:
$('#iframe').attr('src',url);
I assume you're using Razor syntax, so try this for your View code:
#{
ViewBag.Title = "Test";
}
<table id="progress" style="display: none">
<tr>
<td>
<img src="~/Content/Images/ajax-loader.gif" />
</td>
<td>
<h4>please wait.</h4>
</td>
</tr>
</table>
<div class="buttons">
<input type="button" value="Ok" class="button" id="downloadButton">
</div>
<iframe id="iframe" style="display: none"></iframe>
#section scripts{
<script type="text/javascript">
$(document).ready(function () {
$('#downloadButton').click(function () {
$('#progress').show();
$('input:button').attr("disabled", true);
var url = "#Url.Action("GenerateFile", "Files", null)";
$("#iframe").attr('src', url);
$('#iframe').load("/Files/GenerateFile", function () {
$('input:button').attr("disabled", false);
$('#progress').hide();
});
});
});
</script>
}
And I also believe that you should specify an Action parameter in your jQuery load function, eg. $('#iframe').load("/Files/GenerateFile/parameter"...) because your GenerateFile action takes Filters parameter.

Get value from selected row/celll

I'm creating table like this:
<table>
<tr>
<th>Column</th>
</tr>
#foreach (var item in someList)
{
foreach (var item1 in item)
{
<tr>
<td onclick="myMethod();">#item1.name</td>
</tr>
}
}
</table>
And here is the method which is called when the row is selected:
<script type="text/javascript" language="javascript">
function myMethod() {
var clickedCell = $(this);
alert(clickedCell.text());
}
</script>
But it's not working! How can I get the text from the row/cell which is selected/clicked on?
I also tried:
<script type="text/javascript" language="javascript">
function myMethod() {
alert($(this).html());
}
</script>
and it's giving me null althought the table is full.
I'm inferring from this line that you're using jQuery:
var clickedCell = $(this);
If that's the case, let's take a step back for a moment and separate your JavaScript from your HTML. Instead of this:
<td onclick="myMethod();">#item1.name</td>
which has in-line JavaScript (which is generally frowned upon), try something like this:
<td class="clickableCell">#item1.name</td>
Now it's just markup, which is a bit cleaner. Next you need to attach click events to your rendered cells:
$(document).ready(function() {
$('td.clickableCell').click(function() {
alert($(this).text());
});
});
Now this refers to the element to which jQuery is binding the click event, so it can be easily referenced in the code, as opposed to having to pass a self-reference from the click event being bound within the HTML (which is another approach, but continues down the road of mixing markup with code).

Resources