dileno

Subscribe

Hi! I'm Martin Söderlund, the owner of this blog. I work as a web consultant in Stockholm, Sweden. My main focus areas are .NET development and interface development.
If you've got something on your mind, feel free to contact me.

Close

Thank you for visiting!

Please consider subscribing to the RSS feed or following me on Twitter.

Foolproof Custom File Input

So you wan't a custom file upload button.

It's easy. Just hide it, add a button, a couple of click events and you're fine. Except, you're not. IE is quite strict when it comes to file inputs. Browser backward compatibility issues will make life harder for you.

Here's a working solution tested in IE9 and later, and modern browsers.

  1. Place your input file field in a hidden div.
  2. Wrap a label around the hidden div.
  3. Make the label look like a button.
  4. When the label is clicked, trigger the hidden input field.
  5. When a file is chosen, use the change event to display the file name.
The HTML:

<form action="http://localhost/upload" method="post" enctype="multipart/form-data">
<label class="button upload">Upload file
<div class="hidden">
<input class="uploadfile" type="file" />
</div>
</label>
<input type="submit" class="button" value="Submit">
<span></span>
<form>
The JavaScript:

$('.button.upload').click(function () {
var uploadFile = $(this).find('.uploadfile');
uploadFile.trigger('click');
});

$('.uploadfile').change(function() {
var elm = $(this);
var file = elm.val().split('\\');
var fileName = file[file.length - 1];
$(this).closest('form').find('span').html(fileName);
});

And the basic CSS looks like this:

.hidden { display: none }
.button { border: solid 2px #333 }

Creating an Excel File with EPPlus

EPPlus is a very helpful C# Excel library. You can do almost anything you want with it!

Here's how to create a basic Excel file, fill it with some data, and let a user download it.

First of all, let's create the Excel file. We use a DataTable to create columns and rows with the correct cell information. A DataTable is very convenient to use when you know you're going to export to Excel. You'll see why very soon.

When you've filled your DataTable with the content you want, it's time to create a MemoryStream. We use this MemoryStream as a parameter in a using statement for EPPlus: using (var xlPackage = new ExcelPackage(ms))

You need to create a WorkBook and add a WorkSheet to it. Then we use the LoadFromDataTable method to add data to our Excel cells. Finally we save the Excel file and return the MemoryStream. Now we only need to do something with it :-)

public byte[] ExportExcel(int catalogId)
{
	var dt = new DataTable();
		dt.Columns.Add("ProductId", typeof(string));
		dt.Columns.Add("Price", typeof(string));
	
	var catalog = GetCatalog(catalogId);

	foreach (var product in catalog.Products)
	{
		dt.Rows.Add(product.ProductId, product.Price);
	}

	var ms = new MemoryStream();

	using (var xlPackage = new ExcelPackage(ms))
	{
		var wb = xlPackage.Workbook;
		var ws = wb.Worksheets.Add("WS1");
		ws.Cells.LoadFromDataTable(dt, true);

		xlPackage.Save();
		return ms.ToArray();
	}
	return null;
}

In our MVC controller we call the ExportExcel method and return a FileContentResult, giving the file a name as well:

public ActionResult ExportExcel(int catalogId)
{
	if (catalogId != -1)
	{
		var catalog = _catalogRepository.GetCatalog(Convert.ToInt32(catalogId));
		var file = _exportRepository.ExportExcel(catalogId);

		if (file != null)
		{
			return new FileContentResult(file,
				"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
				{ FileDownloadName = "My Excel File.xlsx" };
		}
	}

	return View("Index");
}

Finally, we need a download button in our View. It calls the ExportExcel action method on our controller and looks like this:

@Html.ActionLink("Download", "ExportExcel", new { catalogId = 7 })

This is all the basics you need to create and fill an Excel file with data using EPPlus.

Find Attached Events with jQuery

For later versions of jQuery, you can use this code snippet to find attached events on specific elements:

$._data($("input")[0]).events

As you can see, jQuery events are stored in a data object called events. This is an undocumented jQuery feature, but it works!

Adding Additional ViewData

Sometimes you want to add additional View Data to your Partial, while retaining your current View Data. The solutions is very easy. Just use this.ViewData in your constructor overload, and add the new View Data as usual:

@Html.Partial("_Product", prod, new ViewDataDictionary(this.ViewData)
{{ "Addons", "Product Addons"},{ "AdditionalCategory", "Category" }})

To the top