Why doesn't IE like Vietnamese characters when using ajax? - javascript

The following markup shows my form:
<div id="category-form">
</div>
The following code is my script:
<script type="text/javascript">
function clicked(o) {
var id = o.getAttribute("data-categoryId");
var name = o.getAttribute("data-categoryName");
var description = o.getAttribute("data-description");
loadFormView("/Admin/_EditCategories?categoryId="+ id + "&categoryName="+name+"&description="+description);
}
function loadFormView(url) {
$.ajax({
url: url,
type: 'GET',
cache: false,
success: function (data) {
$("#category-form").html(data);
alert(data);
}
});
}
</script>
I have also created a controller that passes data to the view:
public PartialViewResult _EditCategories(int categoryId, string categoryName, string description)
{
Category category = new Category();
category.CategoryId = categoryId;
category.CategoryName = categoryName;
category.Description = description;
ViewBag.Action = "Cập nhật";
ViewBag.Task = "Sửa thể loại truyện";
ViewBag.IsEdit = true;
return PartialView("_TaskCategories", category);
}
When the view renders the ViewBag content and it's rendered on IE, the text is garbled whereas on Chrome and Firefox, the text appears correctly, in Vietnamese.
"Truyện cười" is categoryName's value
in textbox on ie: "Truy?n c??i" and.... on ff or chrome: "Truyện
cười"
How can I fix the text rendering in IE? Thank you in advance!

Does your page include a meta tag to indicate encoding? IE might be having a difficult time figuring out which encoding to use. Make sure both of your files are encoded in utf8, and add the meta tag:
<meta charset="utf-8">

I think there's more going on here. I think your normal queries are sending your locale as an HTTP header that the AJAX for some reason isn't sending.
Since jQuery's ajax support allows you to specify your own custom headers, why don't you try setting the locale header explicitly yourself, that ought to rule out some simple HTTP issues.
Add Header in AJAX Request with jQuery

Related

How to download a document generated with python-docx in Django project?

I'm trying to figure how to download a word document generated with python-docx in my django app (I'm still learning and this is the first time I working with documents); with the help of ajax I send all the information needed to the view and call a function that uses that information and returns the document, then I'm trying to send this document as response in order to download it with the help of a "Download" button (or show web browser download dialog) in the same template from where I'm submitting the data, but here is where I'm stuck.
to send this document as response in order to download it with the help of a "Download" button (or show web browser download dialog) in the same template from where I'm submitting the data, but here is where I'm stuck.
What I have until now is:
1) In javascript I'm sending the information as follows:
data = {
categoria: cat,
familia: fam,
Gcas: gcas,
FI: FI,
FF: FF,
Test: test,
Grafica: grafica
},
$.ajax({
type: 'post',
headers: {
"X-CSRFToken": csrftoken
},
url: url,
data: { json_data: JSON.stringify(data) },
success: function (response) {
$('#instrucciones').hide(); //Hide a div with a message
$('#btndesc').show(); //Show the button to download the file generated
}
});
return false;
}
2) In my Django view:
def Documento(request):
if request.method == "GET":
context={}
context['form'] = catForm
return render(request, 'report/report_base.html', context)
if request.method == 'POST':
#Data from ajax
datos = request.POST.get('json_data')
jsondata = json.loads(datos)
Gcas = jsondata['Gcas']
FI = jsondata['FI']
FF = jsondata['FF']
grafica = jsondata['Grafica']
#Using function to create the report
Reporte = ReporteWord(Gcas, FI, FF, grafica)
#Response
response = HttpResponse(content_type='application/vnd.openxmlformats-
officedocument.wordprocessingml.document')
response['Content-Disposition'] = 'attachment; filename = "Reporte.docx"'
response['Content-Encoding'] = 'UTF-8'
Reporte.save(response)
return response
3) My function to create the document looks like:
def ReporteWord( gcas, FI, FF, Chart):
#Cargamos el template
template = finders.find('otros/Template_reporte.docx')
document = Document(template)
#Header
logo = finders.find('otros/logo.png')
header = document.sections[0].header
paragraph = header.paragraphs[0]
r = paragraph.add_run()
r.add_picture(logo)
#Adding title
titulo = document.add_heading('', 0)
titulo.add_run('Mi reporte').bold = True
titulo.style.font.size=Pt(13)
.
Many other steps to add more content
.
.
#IF I SAVE THE FILE NORMALLY ALL WORKS FINE
#document.save(r'C:\tests\new_demo.docx')
return document
I'll be very grateful for any idea or suggestion, many thanks in advance.
NOTE: I've reviewed these answers (and others) without luck.
Q1, Q2, Q3, Q4
UPDATE: Thanks to the feedback received I finally found how to generate the document and show the download dialog:
As was suggested the best way to achieve its using the view and not ajax, so the final updates in the code are:
a) Update view to work as show in feedback
b) JavaScript - Ajax control for POST method was removed and now all is handled directly with python (no extra code needed)
1) View:
def Reporte(request):
if request.method == "GET":
context={}
context['form'] = catForm
return render(request, 'reportes/reporte_base.html', context)
if request.method == 'POST':
#Getting data needed after submit the form in the page
GcasID = request.POST.get('GCASS')
FI = request.POST.get('dp1')
FF = request.POST.get('dp2')
Grafica = request.POST.get('options')
#Function to obtain complete code from GcasID
Gcas = GcasNumber(GcasID)
#Report creation
Reporte = ReporteWord(Gcas, FI, FF, Grafica)
#PART UPDATED TO SHOW DOWNLOAD REPORT DIALOG
bio = io.BytesIO()
Reporte.save(bio) # save to memory stream
bio.seek(0) # rewind the stream
response = HttpResponse(
bio.getvalue(), # use the stream's contents
content_type="application/vnd.openxmlformats-officedocument.wordprocessingml.document",
)
response["Content-Disposition"] = 'attachment; filename = "Reporte.docx"'
response["Content-Encoding"] = "UTF-8"
return response
With those changes now when I press "Create report" (submit button of form) all works as expected (as a plus no more libraries are necessary). At the end as you suggested its easier do it in this way than using ajax.
Many thanks to all for your kind help.
Python-docx's Document.save() method accepts a stream instead of a filename. Thus, you can initialize an io.BytesIO() object to save the document into, then dump that to the user.
Reporte = ReporteWord(Gcas, FI, FF, grafica)
bio = io.BytesIO()
Reporte.save(bio) # save to memory stream
bio.seek(0) # rewind the stream
response = HttpResponse(
bio.getvalue(), # use the stream's contents
content_type="application/vnd.openxmlformats-officedocument.wordprocessingml.document",
)
response["Content-Disposition"] = 'attachment; filename = "Reporte.docx"'
response["Content-Encoding"] = "UTF-8"
return response
This will work if you use a regular link or a form to submit the request, but since you're using $.ajax, you may need to do additional work on the browser end to have the client download the file. It would be easier not to use $.ajax.
Yep, a cleaner options, as stated by wardk would be, using https://python-docx.readthedocs.org/:
from docx import Document
from django.http import HttpResponse
def download_docx(request):
document = Document()
document.add_heading('Document Title', 0)
response = HttpResponse(content_type='application/vnd.openxmlformats-officedocument.wordprocessingml.document')
response['Content-Disposition'] = 'attachment; filename=download.docx'
document.save(response)
return response
Know more

How to send value from jsp page to database without refreshing the page

I am developing a spring+hibernate webapp for practicing translation skill from Russian to English.
In one of my jsp pages I am retrieving all the questions from database and placing them into a table with the following columns: text in Russian, field for user's translation, button for checking the result. The goal is to save user's input into database without refreshing the page. How can I do it?
I tried several options, but none of them worked for me.
I used the solution from Send javascript variables to spring controller in my project, but nothing happened at all.
Part of "firstPage.jsp" ("/first" path in the controller):
<head>
<title>Title</title>
<script>
function searchViaAjax(id) {
var tempId = id;
alert("Start");
$.ajax({
type : "POST",
url : "./search/api/getSearchResult",
data : {id:tempId},
timeout : 100000,
success : function(id) {
alert("success");
console.log("SUCCESS: ", id);
display(id);
alert(response);
},
error : function(e) {
alert("error");
console.log("ERROR: ", e);
display(e);
},
done : function(e) {
alert("done");
console.log("DONE");
}
});
}
</script>
</head>
<body>
<button onclick="searchViaAjax(1)">Simple button</button>
</body>
Controller class:
#Controller
public class DemoController {
#RequestMapping("/first")
public String getFirst(){
return "firstPage";
}
#ResponseBody
#RequestMapping(value = "/search/api/getSearchResult", method=RequestMethod.POST)
public String getSearchResultViaAjax(#RequestParam("id") Integer id) {
System.out.println("come to ajax"+ id);
return "hello";
}
}
The "Start" message gets printed, but other messages from searchViaAjax() don't. And controller method doesn't start.
You can pass id in controller as it is no issue in your 'id', and also you can skip value attribute in #RequestParam.
#ResponseBody
#RequestMapping(value = "/search/api/getSearchResult")
public String getSearchResultViaAjax(#RequestParam("id") integer id) {
System.out.println("come to ajax"+ id);
return "hello";
}
Specify the methodType
#RequestMapping(value = "/search/api/getSearchResult", methodType=RequestMethod.POST)
It is also a good practice to use wrapper instead of primitive
#RequestParam("tempId") Integer id
the problem is in your ajax url attribute.
It should be url : "./search/api/getSearchResult",
Root Cause:
When you are about to hit your controller, it construct the url like this
http://localhost:8080/search/api/getSearchResult
and hence such resource is not available and it causes 404 not found error.
In actual the url should be
http://localhost:8080/contextroot/search/api/getSearchResult
here contextroot refers your project name.
Now if you hit url ./search/api/getSearchResult then ./ refers the base url i,e localhost:8080/contextroot and the entire url will be constructed properly.
I would like to recommend you to create global variable in JavaScript say baseUri and assign./ into it.
<script>
var baseUri="./";
</script>
In your AJAX it becomes
url : baseUri+"search/api/getSearchResult",
Hope this will help
The code from user9634982 was fine, thanks to him. The problem was because I was using slim jQuery version so my browser was giving me "$.ajax is not a function" error. And I didn't see it for hours because I didn't know where to look :facepalm: Thanks again to user9634982 for discovering browser inspector to me :D After replacing slim version to usual it still didn't work because of spring security. I added _csrf token and all worked fine.
.jsp:
<meta name="_csrf" content="${_csrf.token}"/>
<meta name="_csrf_header" content="${_csrf.headerName}"/>
<script>
function searchViaAjax(id) {
var csrfHeaderName = "X-CSRF-TOKEN";
var csrfTokenValue;
var metaTags = document.getElementsByTagName('meta');
for(var i = 0; i < metaTags.length; i++) {
var metaTagName = metaTags[i].getAttribute("name");
if(metaTagName === "_csrf_header")
csrfHeaderName = metaTags[i].getAttribute("content");
if(metaTagName === "_csrf")
csrfTokenValue = metaTags[i].getAttribute("content");
}
$.ajax({
type : "POST",
url : "./addAnsweredQuestion",
data : {id:id},
timeout : 100000,
beforeSend:function(xhr){xhr.setRequestHeader(csrfHeaderName, csrfTokenValue);},
success : function(id) {
alert("success");
console.log("SUCCESS: ", id);
display(id);
alert(response);
},
error : function(e) {
alert("error");
console.log("ERROR: ", e);
display(e);
},
done : function(e) {
alert("done");
console.log("DONE");
}
});
}
</script>
Controller:
#PostMapping(value = "/addAnsweredQuestion")
public void getSearchResultViaAjax(#RequestParam("id") Long id) {
System.out.println("come to ajax"+ id);
}

Downloading MVC FileResult doesn't work in IE or Edge browsers

I am trying to download an excel file generated from data entered through a webpage in an MVC application.
This ajax call is executed when a button is pressed, and calls two methods in my controller. One to generate the excel file and another to download the file:
$.ajax({
type: 'POST',
data: myDataObject,
url: 'MyController/GenerateExcel/',
success: function(data) {
if (data.id != "") {
$http.get('MyController/DownloadExcel?id=' + encodeURIComponent(data.id) + '&name=' + encodeURIComponent(data.name));
return true;
}
}
});
Here is my POST method that generates the excel file and saves it to TempData:
[HttpPost]
public JsonResult GenerateExcel(Object model)
{
var fileName = "myexcel.xlsx";
var fileID = Guid.NewGuid().ToString();
var generatedReport = GenerateCustomExcel(model);
using (MemoryStream memoryStream = new MemoryStream())
{
generatedReport.SaveAs(memoryStream);
generatedReport.Dispose();
memoryStream.Position = 0;
TempData[fileID] = memoryStream.ToArray();
}
return Json(new { id = fileID, name = fileName });
}
Here is my GET method that downloads the saved excel from TempData:
[HttpGet]
public FileResult DownloadExcel(string id, string name)
{
if (TempData[id] != null)
{
byte[] fileBytes = TempData[id] as byte[];
return File(fileBytes, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", name);
}
else
{
return null;
}
}
This works flawlessly in Google Chrome and Firefox browsers. However, when using either Internet Explorer or Microsoft Edge browsers, the file refuses to download.
The debug console doesn't produce any useful errors. I have tried changing the returned File type to an octet stream and using window.location.href instead of a get request to download the file, but nothing appears to work. All of the functions are called and data passed between them correctly, so routes are not the problem.
Does anyone know how I can make the returned FileResult download?
Here is a solution. It uses the same code as in my question except for the changes listed here.
Add an iframe element to your webpage:
<iframe id="iFrameFileDownload" style="display: none;"></iframe>
In the javascript, instead of a call using $http.get(), set the 'src' attribute of the iframe element to the controller function url:
$.ajax({
type: 'POST',
data: myDataObject,
url: 'MyController/GenerateExcel/',
success: function(data) {
if (data.id != "") {
$("#iFrameFileDownload").attr("src", 'MyController/DownloadExcel?id=' + encodeURIComponent(data.id) + '&name=' + encodeURIComponent(data.name));
return true;
}
}
});
Another solution that I considered is using the window.open() function instead of $http.get(). (source: Download a file with mvc) However, that solution uses popups and would require users to enable popups in their browser before downloading the file.

ASP.NET Calling Server Side Method from Client Side on keypress

To put it simply, I need a way for client side code to be able to trigger a server side method in my project. The way that I'm trying to use such functionality is when a user inputs their email address into a textbox, after each character is typed I want the project to trigger the method shown below which uses a class to query my database.
private void EmailCheck()
{
lblEmailError.Text = null;
Customer y = new Customer();
int counter = 0;
y.Email = Email.Text;
counter = y.CheckEmail();
if (counter.Equals(1))
{
lblEmailError.Text = "Email is already in use";
}
else
{
lblEmailError.Text = null;
}
}
I currently have almost no experience of any kind with JavaScript or any form of client side scripting. As I understand, AJAX may be of use to me here but again I am clueless about how I would implement it. I've also heard about onkeydown/press/up but again I am not sure how to alter online solutions to my specific need. Any help?
The most straightforward way would be to make a button in HTML5, use jQuery $.ajax() function to invoke a server side REST API (implementation could be anything C# Web API, Python Flask API, Node.JS API).
In your client side:
<label> Enter something into the textbox </label>
<input type = "text" id = "myTextBox" placeholder="Enter something"/>
<script src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-3.2.1.min.js"></script>
<script>
$(function(){
//On button click query the server
$("#myTextBox").change(function(){
var textBoxValue = $("#myTextBox).val();
var dataToBeSent = {
"data": textBoxValue
};
$.ajax(function(){
url: "http://localhost:9999/api/YourAPIName",
method: "POST",
data: JSON.stringify(dataToBeSent),
success: function(data){
console.log(data);
},
error: function(jqXHR, textStatus, errorThrown){
console.log("Failed because" + errorThrown);
}
}); //end .ajax
}); //end click
}); //end jQuery
</script>
In your Server side (Assuming C#):
Make a model class, with properties the same name as the JSON key you constructed for the [FromBody] attribute to deserialize it correctly.
public class SomeModelClass
{
public string data { get; set; }
}
[HttpPost]
[Route("api/YourAPIName")]
public HttpResponseMessage YourMethod([FromBody] SomeModelClass modelClass)
{
//perform logic and return a HTTP response
}

Is it any limit for POST data size in Ajax?

I'm trying to send an array of data from my page to the MVC Action using jQuery Ajax. Here is my jQuery code:
$('#btnSave').click(
function () {
result = [];
$('#tblMatters tbody tr.mattersRow').each(function () {
if (!($(this).hasClass('warning'))) {
var item = {};
if ($(this).find('td.qbmatter > div.dropdown').length > 0) {
item.QBDescription = $(this).find('td.qbmatter > div.dropdown > a').text();
} else {
item.QBDescription = $(this).find('td.qbmatter').text();
}
var id = $(this).find("td:first > a").text();
item.Narrative = $("#collapse" + id).find("div.scrollCell").text();
item.WorkDate = $(this).find('td.workDate').text();
item.Hours = $(this).find('td.hours').text();
item.Person = $(this).find('td.person').text();
if ($(this).find('td.rate > div.dropdown').length > 0) {
item.Rate = $(this).find('td.rate > div.dropdown > a').text();
} else {
item.Rate = $(this).find('td.rate').text();
}
item.Amount = $(this).find('td.amount').text();
result.push(item);
}
});
var originalRecords = $("#tblSummary tr.summaryTotalRow td.summaryOriginalRecords").text();
var originalHours = $("#tblSummary tr.summaryTotalRow td.summaryOriginalHours").text();
var excludedHours = $("#tblSummary tr.summaryTotalRow td.summaryExcludedHours").text();
var totalHours = $("#tblSummary tr.summaryTotalRow td.summaryTotalHours").text();
$.ajax({
url: "/Home/SaveQBMatter",
type: "POST",
data: JSON.stringify({ 'Matters': result, 'originalRecords': originalRecords, 'originalHours': originalHours, 'excludedHours': excludedHours, 'totalHours': totalHours }),
dataType: "json",
traditional: true,
contentType: "application/json; charset=utf-8",
success: function (data) {
if (data.status == "Success") {
alert("Success!");
var url = '#Url.Action("Index", "Home")';
window.location.href = url;
} else {
alert("Error On the DB Level!");
}
},
error: function () {
alert("An error has occured!!!");
}
});
});
Let me explain a little bit. I have an HTML table that was built dynamically and I need to store this data into a database. In jQuery I have a loop going through the table and I store data of every row in the result array. Then I pass this data using Ajax into MVC Action.
And here is where my problem starts... I've realized that sometimes it goes as it should be, but sometimes I'm getting an error from Ajax alert("An error has occured!!!"); Now I've understood that this error occurs when my result array is getting big. For example: If it contains 100-150 items > everything is good, but when there are more than ~150 > Error.
Is there any POST limit in Ajax? How can I set it up for any sizes? I really need this functionality! Any help please!
My ActionResult Code:
public ActionResult SaveQBMatter(QBMatter[] Matters, string originalRecords, string originalHours, string excludedHours, string totalHours) {
DBAccess dba = new DBAccess();
int QBMatterID = 0;
int exportedFileID = 0;
foreach (QBMatter qb in Matters) {
dba.InsertQBMatter(qb.QBDescription, qb.Narrative, qb.WorkDate, qb.Person, qb.Hours, qb.Rate, qb.Amount, ref QBMatterID);
}
ExcelTranslator translator = new ExcelTranslator();
translator.CreateExcelFile("", Matters, originalRecords, originalHours, excludedHours, totalHours);
return Json(new { status = "Success", message = "Passed" });
}
UPDATE: Found a solution
JSON has a maximum length! I need to increase this value. In web.config add the following:
<appSettings>
<add key="aspnet:MaxJsonDeserializerMembers" value="150000" />
</appSettings>
JSON has a maximum length! I need to increase this value. In web.config add the following:
<appSettings>
<add key="aspnet:MaxJsonDeserializerMembers" value="150000" />
</appSettings>
Is it any POST Limit in Ajax?
No, the HTTP specification doesn't impose a specific size limit for posts. However it depends on the Web Server which you are using or the programming technology used to process the form submission.
In ASP.NET MVC you can try this:
<system.webServer>
<security>
<requestFiltering>
<requestLimits maxAllowedContentLength="1000000" />
</requestFiltering>
</security>
The HTTP spec doesn't defining a limitation of POST data size.
But using ASP.NET MVC, there could be a POST data limitation, try to increase it in your Web.Config file:
<system.webServer>
<security>
<requestFiltering>
<requestLimits maxAllowedContentLength="1000000" />
</requestFiltering>
</security>
From MSDN:
Specifies the maximum length of content in a request, in bytes. The
default value is 30000000.
This solved my problem:
<system.web.extensions>
<scripting>
<webServices>
<jsonSerialization maxJsonLength="2147483647" />
</webServices>
</scripting>
</system.web.extensions>
IF there is a client-side limit then it would be browser specific but the HTTP spec does not define a limitation of POST data size.
Keep in mind that a POST is merely bytes across the network so the more fields you are posting then the longer it can take to upload that data.
A 1MB POST is going to make the user feel like the form is broken and unresponsive if using a traditional form submit.
If there are a lot of fields to serialize() then AJAX could hang up the browser while it collects all of the data. I think browsers do have a memory limit for JavaScript overall so if you hit that limit then the AJAX process will fail.
// wanna have some fun?
var html = '<div></div>';
for(var i = 0; i < 1000000; i++){
html += html;
}
Your best bet is to increase the maximum allowable POST size on the server-side to avoid issues.
Most commonly issues arise when people make an upload script which simply seems to hang while the user is confused why their 3MB pictures are going slow on a 125KB/s upload link.
The limit is set through a server 'max_post_size' or similar naming. Typical default server settings are 2-8 MB in one post.
On the client side, only GET has a maximum limit, generally considered 1500 bytes (minus 30-150 from request headers) and the reason is the MTU in the more lowlevel network hardware
In my case the class I was posting to had 'internal set' on the property.
Changed:
public EnabledDataBundle EnabledDataBundle { get; internal set; }
to:
public EnabledDataBundle EnabledDataBundle { get; set; }

Categories