BoldDesk®Customer service software offering ticketing, live chat, and omnichannel support, starting at $49/mo. for 10 agents. Try it for free.
Hola, estoy implementando Hoja de cálculo para editarla en linea pero no me carga el contenido. Anexo dejo los datos de soporte.
Resumen:
tengo un controlador (documentcontroller), el cual contiene dos métodos esenciales (get( EditExcel ), post(open)) para manejar xlsx, de manera que el método get obtiene un ID correspondiente ax documento el cual con ese id obtiene la ruta y procesa el mismo luego pasa el resultado a la vista y la vista devuelve para el método post en este ultimo paso luego de completado no se renderiza correctamente el contenido el archivo en cuestión, en cambio si lo hago de manera directa si se renderiza correctamente favor ver documentos soportes. Lo que necesito es que en ambas formas se muestre correctamente el contenido del documento que se este manejando en el momento.
Hi Anderson Tyson Calderon,
We noted that you are converting the Excel file to a Base64 string on the server side and then attempting to load the Excel file on the client side using this Base64 string.
We tried replicating your process but encountered issues while processing the generated Base64 string on the client side. Upon investigation, we confirmed that the problem is likely due to the Base64 string being incorrectly formatted or containing invalid characters that are not compatible with the Base64 encoding process (atob action). To address this, I directly handled the file on the server side and converted it to a Base64 string using FileReader. However, we still encountered the same issue during Base64 encoding.
Further validation revealed that these problems might be caused by the presence of HTML entities in the generated Base64 string. To convert these HTML entities back to their normal characters, we created a textarea element, assigned the Base64 string to the textArea innerHTML, and then retrieved the textarea's value. This updated Base64 string, with the HTML entities replaced, worked without any issues, and the file was successfully imported into our spreadsheet using the code snippets provided below.
Code snippet:
created: function () { // Recuperar el contenido base64 y el nombre del archivo desde los ViewData var base64Content = '@ViewData["ExcelContent"]'; var fileName = '@ViewData["FileName"]';
if (base64Content) {
// Replace HTML entities. const textArea = document.createElement('textarea');
textArea.innerHTML = base64Content;
base64Content = textArea.value;
var byteCharacters = atob(base64Content);
var byteNumbers = new Array(byteCharacters.length);
for (var i = 0; i < byteCharacters.length; i++) {
byteNumbers[i] = byteCharacters.charCodeAt(i);
}
//Convert to byte array. var byteArray = new Uint8Array(byteNumbers);
//Convert the byte array to blob. var fileBlob = new Blob([byteArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
//Convert the blob to file to open into Spreadsheet var file = new File([fileBlob], fileName);
// Enviar el contenido base64 al servidor como si fuera un archivo cargado desde el input var formData = new FormData();
formData.append('fileUpload', file);
// Open the file based on saved base64 string. fetch('/Home/Open', { method: 'POST', body: formData }).then((response) => response.json()) .then(result => { // Abre el archivo recibido desde el servidor spreadsheet.openFromJson({ file: result }); }) .catch(error => console.error('Error al abrir el archivo desde el contenido base64:', error)); } } |
For your reference, we have provided the sample along with a video demonstration. Please find the sample and video in the attachment below.
Kindly review the sample and details shared above on your end and let us know if you need further clarification. If you encounter any issues, please provide the version of the "Syncfusion.EJ2.Spreadsheet.AspNet.Core" NuGet package you are using, along with a detailed description of your specific requirements. Based on this information, we will promptly check and provide an improved solution.
Hola, gracias por la actualización, momentos antes de su respuesta ya había logrado cargar la información de otra manera.
Ahorita lo que no he podido lograr es guardar una nueva versión del documento cargado en la herramienta. por ejemplo abro un documento x lo muestro, realizo un cambio y deseo guardar una nueva versión del mismo pero al momento de esta acción no se esta logrando lo esperado.
Cabe destacar que la vista no esta accediendo al metodo para guardar cuando coloco en (
// Capturar el evento de envío del formulario
document.getElementById('editForm').addEventListener('submit', function (e) ) en cambio si en lugar de submit coloco save ahi si accede al metodo correspondiente del controlador que es el metodo proporcionado mas abajo, pero aun asi no me completa la accion de guardar el archivo como lo requiero.
vista
@using Newtonsoft.Json
@model SGCApp.Models.DocumentViewModel
@{
ViewData["Title"] = "Editar Documento Excel";
Layout = "~/Views/Shared/_LayoutSGC.cshtml";
var filePath = ViewData["FilePath"];
}
<h2>Editar Documento Excel</h2>
<input type="hidden" id="documentId" value="@Model.Id" />
<div class="wrapper" style="height: 90vh;">
<ejs-spreadsheet id="spreadsheet" openUrl="Document/Open" saveUrl="Document/Save" created="createdHandler">
</ejs-spreadsheet>
</div>
<!-- Envolver los botones en un formulario -->
<<form id="editForm" method="post" action="@Url.Action("Save", "Document")">
<input type="hidden" id="documentId" name="Id" value="@Model.Id" />
<input type="hidden" id="documentContent" name="Content" />
<div class="button-container">
<button type="submit" class="e-btn e-primary">Guardar</button>
<button type="button" id="cancelButton" class="e-btn e-secondary">Cancelar</button>
</div>
</form>
@section Scripts {
<script src="https://cdn.syncfusion.com/ej2/20.3.52/dist/ej2.min.js"></script>
<script>
function createdHandler() {
var spreadsheet = ej.base.getComponent(document.getElementById('spreadsheet'), 'spreadsheet');
var filePath = @Html.Raw(JsonConvert.SerializeObject(ViewData["FilePath"]));
fetch('/Document/OpenExcelFile', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ FilePath: filePath }),
})
.then(response => response.text())
.then(data => {
spreadsheet.openFromJson({ file: data });
spreadsheet.hideSpinner();
})
.catch(error => console.error('Error al abrir el archivo Excel:', error));
}
// Capturar el evento de envío del formulario
document.getElementById('editForm').addEventListener('submit', function (e) {
e.preventDefault(); // Prevenir el envío por defecto del formulario
var spreadsheet = ej.base.getComponent(document.getElementById('spreadsheet'), 'spreadsheet');
spreadsheet.saveAs({ saveType: 'Excel' }).then(function (blob) { // Usar saveAs si está disponible
var reader = new FileReader();
reader.onload = function () {
var base64String = reader.result.split(',')[1];
document.getElementById('documentContent').value = base64String; // Asignar al campo oculto
// Verificar el valor antes de enviar
console.log('Contenido del archivo:', base64String);
console.log('Valor del campo oculto:', document.getElementById('documentContent').value);
// Enviar el formulario
document.getElementById('editForm').submit();
};
reader.readAsDataURL(blob); // Leer el Blob como Data URL
}).catch(function (error) {
console.error('Error al guardar el archivo:', error);
});
});
// Cancelar la edición
document.getElementById('cancelButton').addEventListener('click', function () {
window.location.rel='nofollow' href = '@Url.Action("Index", "Document")';
});
</script>
}
controller
[HttpPost]
public async Task<IActionResult> Save(int id, DocumentViewModel model)
{
// Encuentra el documento original
var document = await _context.Documents.FindAsync(id);
if (document == null)
{
return NotFound();
}
// Obtén el usuario actual y su departamento
var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
var user = await _context.Users
.Include(u => u.Departament)
.FirstOrDefaultAsync(u => u.Id == userId);
if (user == null || user.Departament == null)
{
return NotFound("Usuario no encontrado o sin departamento asociado.");
}
// Generar un nuevo número de versión
var newVersionNumber = (Int32.Parse(document.CurrentVersion) + 1).ToString("D2");
// Crear la nueva versión del documento
var newVersion = new SGCApp.Models.DocumentVersion
{
DocumentId = document.Id,
VersionNumber = newVersionNumber,
CreatedAt = DateTime.Now,
ModifiedBy = userId
};
// Generar un nuevo nombre de archivo basado en la nueva versión, manteniendo la misma ruta del archivo original
var extension = Path.GetExtension(document.FilePath);
var originalFilePath = Path.GetDirectoryName(document.FilePath); // Obtener la carpeta del archivo original
var originalFileNameWithoutExtension = Path.GetFileNameWithoutExtension(document.FilePath);
var newFileName = $"{originalFileNameWithoutExtension}_v{newVersionNumber}{extension}";
var newFilePath = Path.Combine(originalFilePath, newFileName); // Usar la misma carpeta y solo cambiar el nombre del archivo
// Guardar el contenido modificado del documento en la nueva ubicación
if (!string.IsNullOrEmpty(model.Content))
{
try
{
// Convertir el contenido desde base64 y escribir en la nueva ruta
var contentBytes = Convert.FromBase64String(model.Content);
await System.IO.File.WriteAllBytesAsync(newFilePath, contentBytes);
newVersion.FilePath = newFilePath; // Asegurarse de asignar la ruta correcta
}
catch (Exception ex)
{
// Manejo de errores en caso de que la escritura falle
return BadRequest($"Error al guardar la nueva versión del archivo: {ex.Message}");
}
}
else
{
return BadRequest("El contenido del archivo no puede estar vacío.");
}
// Actualizar el documento original con la nueva versión, sin modificar el archivo original
document.UpdatedAt = DateTime.Now;
document.CurrentVersion = newVersionNumber;
// Actualizar el contexto con el nuevo documento y la versión creada
_context.Update(document);
_context.DocumentVersions.Add(newVersion);
await _context.SaveChangesAsync();
// Redirigir a la vista de índice
return RedirectToAction("Index");
}
Attachment: img_ed172539.rar
Hi Anderson Tyson Calderon,
We have reviewed the details you provided and suspect that after loading your
file, you intend to save the spreadsheet as an Excel file with the updated
changes programmatically at a specific location on the server. To achieve this,
instead of using the default save method, we recommend converting the
spreadsheet data into JSON format using the saveAsJson method. You can then
send this JSON data to the server endpoint for saving using a fetch call, as
illustrated in the code snippet below.
On the server side, you will need to convert the received JSON data into a file stream, then convert this stream into an Excel file. Finally, save the file to your desired server location. If needed, you can also save the stream to your preferred location.
For your convenience, we have provided a sample with both client-side and server-side code snippets for your reference.
Sample: Please
see the attachment.
Code snippet:
var spreadsheet = ej.base.getComponent(document.getElementById('spreadsheet'), 'spreadsheet');
// Convert the spreadsheet workbook to JSON data. spreadsheet.saveAsJson().then((json) => {
const formData = new FormData();
formData.append('FileName', "Saved_File");
formData.append('saveType', 'Xlsx');
// Passing the JSON data to perform the save operation.
formData.append('JSONData', JSON.stringify(json.jsonObject.Workbook));
formData.append('PdfLayoutSettings', JSON.stringify({ FitSheetOnOnePage: false }));
// Using fetch to invoke the save process.
fetch('/Home/SaveExcelFile', {
method: 'POST',
body: formData
}).then((response) => {
alert('Spreadsheet saved as an Excel file named "Saved_File" in the "Files" folder');
})
}); });
{
ExcelEngine excelEngine = new ExcelEngine();
IApplication application = excelEngine.Excel;
try
{ // Save the workbook as Stream.
Stream fileStream = Workbook.Save<Stream>(saveSettings);
// Using XLSIO, we are opening the file stream and saving the file in the server under Files folder.
// You can also save the stream file in your server location.
IWorkbook workbook = application.Workbooks.Open(fileStream);
string basePath = Path.Combine(_env.ContentRootPath, "Files", $"{saveSettings.FileName}.xlsx");
var file = System.IO.File.Create(basePath);
fileStream.Seek(0, SeekOrigin.Begin);
fileStream.CopyTo(file); // to convert the stream to file options.
file.Dispose();
fileStream.Dispose();
return string.Empty;
}
catch (Exception ex)
{
return ex.Message;
}
} |
In the shared sample above, we initially loaded your provided Excel file "Fermentos
Automatizados.xlsx" using the created event. When clicking the button
labeled "Guardar," the spreadsheet is saved as an Excel file named
"Saved_File" in the "Files" folder, using the
process mentioned above. For your reference, we have attached a video
demonstration below.
Video: Please
see the attachment.
For more details regarding this process, we suggest referring to the
documentation linked below for your reference.
https://ej2.syncfusion.com/aspnetcore/documentation/spreadsheet/open-save#save-an-excel-file-to-a-server
Get the spreadsheet as a Blob on the client side:
Additionally, you can get the spreadsheet data as a Blob on the client side. If
need, you can then send this Blob data to the server endpoint for saving
according to your requirements. For more details regarding this, please refer
to the documentation shared below.
https://ej2.syncfusion.com/aspnetcore/documentation/spreadsheet/open-save#save-an-excel-file-as-blob-data
For your convenience, we have provided a sample with the code snippets below.
In this sample, the Blob data is logged to the console for your reference. You
can retrieve the Blob data in the console while saving the spreadsheet as an
Excel file.
Sample: Please
see the attachment.
Code snippet:
<e-spreadsheet-sheets> <e-spreadsheet-sheet name="Price Details"> <e-spreadsheet-ranges> <e-spreadsheet-range dataSource="ViewBag.DefaultData" startCell="A1"></e-spreadsheet-range> </e-spreadsheet-ranges> <e-spreadsheet-columns> <e-spreadsheet-column width="130"></e-spreadsheet-column> <e-spreadsheet-column width="100"></e-spreadsheet-column> <e-spreadsheet-column width="100"></e-spreadsheet-column> </e-spreadsheet-columns> </e-spreadsheet-sheet> </e-spreadsheet-sheets> </ejs-spreadsheet>
<script> function beforeSave(args) { args.needBlobData = true; // To trigger the saveComplete event. args.isFullPost = false; // Get the spreadsheet data as blob data in the saveComplete event. }
function saveComplete(args) { // To obtain the blob data console.log('Spreadsheet BlobData : ', args.blobData); } </script>
{ OpenRequest open = new OpenRequest(); open.File = openRequest.Files[0]; return Content(Workbook.Open(open));
}
public IActionResult Save(SaveSettings saveSettings) { return Workbook.Save(saveSettings); } |
Could you confirm whether you wish to save the spreadsheet as an Excel file on the server location, or if you need it saved in another format? Please share the specifics regarding this.
If we have misunderstood your requirement, please provide a more detailed explanation so we can better understand your needs. Based on the information you provide, we will review and offer a suitable solution promptly.
Listo, ahora si pude realizar la accion con esa actualizacion suministrada.
Muchas gracias.
Se puede colocar funcionalidad para imprimir directamente?
Cual seria el paso a paso?
Hi
Anderson Tyson Calderon,
We are happy to hear that your problems have been resolved.
Query: Se puede colocar funcionalidad para imprimir directamente? Cual
seria el paso a paso?
We
have reviewed your reported requirement and suspect that you are expecting the
print functionality in our spreadsheet. We kindly inform you that the print
functionality is already included in our spreadsheet. For more details
regarding the print functionality, please refer to the links below.
Demo: https://ej2.syncfusion.com/aspnetcore/spreadsheet/print#/fluent2
Documentation: https://ej2.syncfusion.com/aspnetcore/documentation/spreadsheet/print
API link: https://helpej2.syncfusion.com/javascript/documentation/api/spreadsheet/#print
If we have misunderstood your requirement, please provide a more detailed
explanation with step-by-step details to help us better understand your needs.
Based on the information you provide, we will check and provide a better
solution quickly.