I am working on a project that dynamically creates an html table with javascript. Once this table is created I need to be able to export it to excel through a button click. I have tried a few things already, but they haven't worked for me.
I tried doing a simple export from javascript by creating the Active X object, but that setting is locked down in IE so our browsers will not work with Active X.
I tried exporting to excel from a code behind function using the HttpContext class but since the table is created dynamically, the server doesn't see it.
My final method, and I was sure that this was going to work, was I used AJAX via a pagemethod to export the table to excel. I was going to create an array of the table in javascript and pass it to the pagemethod. But before I got to this step, I created a pagemethod that exported a simpe "Test" file to excel. It worked as a method called from a button click, so I figured it would from a pagemethod as well. It didn't :( It runs and completes the pagemethod, but doesn't open excel or export anything. No errors and the success function is executed.
Here is the code:
<System.Web.Service.WebMethod()>
Public Shared Function exportTable(ByVal title As String) As String
HttpContext.Current.Response.ClearContext()
HttpContext.Current.Response.AddHeader("content-disposition", "attachment; filename="TEST.xls")
HttpContext.Current.Response.ContentType = "application/vnd.ms-excel"
HttpContext.Current.Response.Write("<?xml version='1.0'?>")
HttpContext.Current.Response.Write("<ss:Workbook xmlns:ss='urn:schemas-microsoft-com:office:spreadsheet'>")
HttpContext.Current.Response.Write("<ss:Worksheet ss:Name='sheet1'>")
HttpContext.Current.Response.Write("<ss:Table>")
HttpContext.Current.Response.Write("<ss:Row>")
HttpContext.Current.Response.Write("<ss:Cell><ss:Data ss:Type='String'>TEST</ss:Data></ss:Cell>")
HttpContext.Current.Response.Write("</ss:Row>")
HttpContext.Current.Response.Write("</ss:Table>")
HttpContext.Current.Response.Write("</ss:Worksheet>")
HttpContext.Current.Response.Write("</ss:Workbook>")
HttpContext.Current.ApplicationInstance.CompleteRequest()
Return 0
End Function
My page method call is:
function exportToExcel(title) {
PageMethods.exportTable(title, exportSuccess, exportFailure)
}
The exportSuccess function is a simple alert, which is firing. I take that to mean that the pageMethod is executing without errors, but that it can't open excel or ... something.
I eventually want to pass in an array and loop through it to add the rows and data. I've done this with a non dynamic table and it works. I'm also going to use the title to define the filename, but for testing reasons, I've named it TEST.xls.
I copied and pasted the HttpContext code into a button click event and it worked fine with a static table, so I don't think there are any problems with that. But I have been known to be wrong.
I guess my question is can a PageMethod export to excel or use the HttpContext class? Is there a better/easier way to do this?
Please keep in mind that I cannot use ActiveX objects and all customers are required to use IE.
Thanks for your help, and I'm sorry if this has already been covered. I searched but didn't find anything. If it has, could you please point me to the post?
If you send out the Excel MIME header, followed by an HTML table, EXCEL should load it as it it were a spreadsheet.
Well, I've buckled under pressure and decided to do it a different way. I think that ajax does not play well with response.write.
I created an asp:hiddenfield control. Then when the ajax was called to generate the table, I populated it's value with a pipe delimeted string representing the rows and columns of the table. So cell1|cell2||cell1|cell2||cell1|cell2.
Then I created an on_click method for a button and was able to use the same code from the function above. To populate the table I just replace the "TEST" by parsing the hiddenfield value.
I decided to post this just in case anyone else was having an issue with it.
Related
This Javascript Function..
function ClearTotals() {
document.getElementById("total1").value = "";
document.getElementById("total2").value = "";
}
sets resets the values in two form fields. However when I move this function, unchanged, to an external Javascript and reference it in the HTML page as below:
<script src="http://xxxxxxx.org/pkjs/js1.js/"></script>
it doesn't work.
Do I need to pass some reference to the document which is used in the function, or is there some other reason why this doesn't work. Thanks
The problem is js1.js - as the error message made clear ! For some reason only the first function was being read even though I can see no problems with the structure of the file. If I delete all the other functions, and test the function by typing the url in the browser, I see the javascript code for ClearTotals().
And when I submit the HTML form, the field values clear as they should. That's really good - there are no issues with putting internal js code into an external file. Thanks again to everyone for their input and apologies that the problem seems down to me !
I am currently trying to convert a lot of backend code to front end (to lighten the load on a small system).
The code at the moment calls a PHP function to return specific information. (e.g. image locations, strings, styling)
I am converting this code to its js equivalent, the content from Mysql was converted to JSON and stored in a read only file and I am accessing that file using this code:
<script>
function jsread(tag) {
$.getJSON("/strings.json", function(result){
document.write(result[tag]['value']);
});
}
</script>
I want the function to "print" where ever it is invoked. document write writes the value to the page but stops all other loading and write only the value.
Let me be very clear on this: I DO NOT want to use anything that needs extra calls or references out side of this function, that will take months of work so no getting elements by their IDs I have already view many questions on this subject and none are what I can work with. I need something that can be applied to every situation. Other wise I will just have to read the JSON using PHP as a middle compromise.
The problem here is, document.write()'s behaviour is crazy across all the browsers, because, it directly modifies the document object and messes up with the events attached. So it is always better to avoid this function as each browser defines it differently and has a different effect on the same code, with different browsers.
Is there a way to use them without a direct reference?
Solution
The wise thing is, as I said in the comments, it is better to use one of the jQuery functions safely, which create a textNode and insert it the right way, without affecting the others:
<script>
function jsread(tag) {
$.getJSON("/strings.json", function(result){
$("body").append(result[tag]['value']);
});
}
</script>
In case, if you wanna do something like having a placeholder and doing stuff, then you can try giving something like this:
$(function () {
var data = "Dummy Data, that would probably get returned from the getJSON";
// Inside the Success function, do this:
$("span.placeholder-of-the-json").replaceWith(data);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<span class="placeholder-of-the-json">This gets replaced</span>
Let's say you have a VB.Net web method with the following prototype:
Public Function HelloWorld() As DataTable
Let's say you have that returned to you in ordinary JavaScript/Ajax. How would you get individual rows out of it, and how would you get individual fields out of those rows (at least assuming it comes from an SQL query - I'm not sure if it makes a difference)? I'm not casting it into any particular type before it gets passed to the success function. To illustrate what I'm talking about, it would be kind of like doing this in AS3:
for each (var table:Object in pEvent.result.Tables) {
for each (var row:Object in table.Rows) {
ac.addItem(row["id"]);
}
}
except that I'm not necessarily looking to loop through them like that - I just want some way to get the information out of them. Thanks!
EDIT: For example, say you have the following function in a VB.Net web service:
<WebMethod()> _
Public Function Test() As DataTable
Return DBA.OneTimeQuery("SELECT id FROM visits WHERE id = 13")
// returns a one-row, one-column DataTable with the id field being set to 13
End Function
How would you be able to get 13 out of it once it gets into the JavaScript that's calling the web method? Everything I try just says "[object]".
You do not want to return a DataTable object in your web method. The best approach would be to develop a REST web method that returns JSON that represents the data you want to return, as JavaScript will be able to work with JSON directly. Here is a QA the directs you on how to do this. This is if you are using WCF, which it appears you are. I find it better to use ASP.NET Web API for RESTful web services.
From an ATK4 page, i can call jqplot using a javascript helper file like this
on the page
$chart = $p->add('jqplot', null, 'chart1');
$chart->setSeries(array(10,20,15));
define a jqplot.php like this
class jqplot extends View {
function render()
{
$plot=$this->js(true)->univ()->jqplot($this->series, $this->opts);
parent::render();
return $this;
}
}
and in a js helper file, link the php call to the javascript
$.each({
jqplot: function(series, opts){
console.log('jqplot series',series);
console.log('jqplot options',opts);
$plot=$.jqplot(this.jquery.attr("id"), series, opts);
return $plot;
}
}
If i have one chart on a page and reload it with an ajaxec call, it works fine but if i have several charts next to each other, only the first one is ok and the one next to it completely disappears if i call reload.
What i really want to do is call the jqplot replot function on the chart and pass it new data from the page but how can i do this ? The $plot object in the jshelper holds a javascript object and i need this object to call replot on it.
I am thinking maybe i can store the object when first created in a javascript associative array and then when i call replot, lookup the id and if found, call replot on the object but not sure what this code looks like or whether i have the right approach so any help appreciated.
Thanks in advance for you assistance.
It probably would be quite difficult to achieve this. First you need to properly handle destruction of jqPlot. You'll need a proper jQuery UI widget capable of restoring everything through a de-constructor. Then you might get it to work.
As far as Agile Toolkit is concern, it destroys the element containing your jqPlot using JavaScript, re-loads HTML and re-executes JavaScript.
We are building large ASP.NET applications for the intranet use in multiple languages/cultures. We utilize the Globalization with RESX files and use GetResourceText on the server side to get the localized texts.
Lately we are doing more and more client side logic with JQuery.
How do I get the RESX texts to be used in Javascript?
e.g. texts used for validation, dynamic messages etc.
All our Javascripts are in .JS files, we do not want to mix HTML in the ASPX page and Javascript blocks.
Thanks for your help.
Unfortunately, in an external JS file the server side code is not being processed by the server. However I have seen a workaround where you can set your translated values in hidden fields on the page - this way your javascript will be able to read the values in.
For example:
<%-- This goes into your page --%>
<input type="hidden" id="translatedField" name="translatedField" value="<%=Resources.Resources.translatedText %>" />
and use this inside your javascript file:
// This is the js file
$(document).ready(function() {
alert($("#translatedField").attr("value"));
});
You will be able to separate the values and still see it in your external JS file.
There is also another workaround that creates a .aspx file that only outputs Javascript instead of HTML. Check out the link below:
Using server side method in an external JavaScript file
Always separate functionality from human readable strings.
If you're creating jQuery-plugins you should be able to pass an array of localized strings as parameter when you call your different jQuery functions. The array could be defined as inline javascript directly on the page calling the different jQuery plugins or you could load the from external resource in the format /scripts/localization/strings.js?ci=en-US and register a Generic ASP.Net Handler in web.config that would respond to scripts/localization/strings.js
The DatePicker control is a fine example of how to localize text for the jQuery datepick control - this js file is dynamically created from resource files (resx) and when included on a page it will make sure the calendar control will have danish text.
Create a HttpHandler (.ashx file), and return JSON with your text resource strings.
You may also "publish" it to global namespace, i.e.
Response.Write("window.Resources=");
Response.Write((new JavaScriptSerializer()).Serialize(strings));
set up HTML like:
<script src="Resx.ashx?lang=en-US" />
<button class="LogoutButtonResourceId OtherButtonClasses">(generic logout text)</button>
<a href="#"><span class="SomeLinkTextResourceId OtherClasses">
(generic link text)
</span></a>
and apply texts like this:
$(document).ready(function() {
for(var resId in Resources){
$("."+resId).html(Resources[resId]);
}
});
If you don't want to use ASP.NET to generate your main JavaScript, here are two other options:
Use ASP.NET to generate a script file that contains variable-to-string assignments, such as var mystring = 'my value';. Your main script would then reference the localized text with variables names rather than as embedded values. If that's still too "dirty" for you, you could encode the strings as JSON rather than as variable assignments, using an HttpHandler rather than straight .aspx.
Have your JavaScript code issue an Ajax call to retrieve an array or list of localized strings from the server. The server-side part of the call would retrieve the text from your resx files.
Have you considered using $.ajax in combination with ASP.NET WebMethods? It's hard to suggest a more concrete solution to this problem without understanding how your JavaScript/jQuery would consume/process the resources. I assume that they're organized into logical groups (or could be) where you could return several resource strings that belong on a single page.
Assuming that, you could write a very simple C# class -- or use a Dictionary<string, string> -- to return data from your ASP.NET WebMethod. The results would look something like:
[WebMethod]
public Dictionary<string, string> GetPageResources(string currentPage)
{
// ... Organizational stuff goes here.
}
I always separate out my AJAX calls into separate .js files/objects; that would look like:
function GetPageResources (page, callback)
$.ajax({ // Setup the AJAX call to your WebMethod
data: "{ 'currentPage':'" + page + "' }",
url: /Ajax/Resources.asmx/GetPageResources, // Or similar.
success: function (result) { // To be replaced with .done in jQuery 1.8
callback(result.d);
}
});
Then, in the .js executed on the page, you should be able to consume that data like:
// Whatever first executes when you load a page and its JS files
// -- I assume that you aren't using something like $(document).ready(function () {});
GetPageResources(document.location, SetPageResources);
function SetPageResources(resources) {
for (currentResource in resources) {
$("#" + currentResource.Key).html(currentResource.Value);
}
}
I know it's to late but want share my experience in this task)
I use AjaxMin. It can insert resx key values into js file on build event.
It's not common way but it keeps html without unneeded script blocks and can be done during minification process if you have it.
It works like this:
ajaxmin.exe test.js -RES:Strings resource.resx -o test.min.js
Also you need to do the same for ech locale if you have many.
Syntax to write resource keys in js (and also css) is written here:
Js localization
Css localization
How about injecting it as part of a javascript control initialization? what i do is as follows:
I have a self-contained javascript control - call it CRMControl, which has an init method called setupCRMControl, to which i pass a settings object. When i initialize it, i pass an object containing all the resources i need inside javascript as follows:
CRMControl.setupCRMControl({
numOfCRMs: 3,
maxNumOfItems: 10,
// then i pass a resources object with the strings i need inside
Resources: {
Cancel: '#Resources.Cancel',
Done: '#Resources.Done',
Title: '#Resources.Title'
}
});
Then, inside this javascript control:
var crmSettings = {};
this.setupCRMControl(settings) {
crmSettings = settings;
};
and whenever i want to show a resource, i say (for example, show an alert saying 'Done'):
alert(crmSettings.Resources.Done);
You can call it "R" to make it shorter or something, but this is my approach. Maybe this may not work if you have a whole bunch of strings, but for manageable cases, this may work.