A very typical application for the variety of components that are part of TX Text Control is the visual creation of templates that are stored in a database. Documents in formats such as PDF are created by merging data into the stored templates.
To store the templates, this sample application uses a file-based database called LiteDB. The templates are created using the Document Editor visual component, and the templates are finally merged using the Mail
╰ DocumentServer Namespace
╰ MailMerge Class
The MailMerge class is a .NET component that can be used to effortlessly merge template documents with database content in .NET projects, such as ASP.NET web applications, web services or Windows services. class.
Template Overview
When you start the application, you will see an overview of all the templates you have created.
Data Excerpt Files
When you create a new template, the Document Editor is opened and dummy JSON data is generated to fill in the drop-down lists that contain the names of the fields that can be used.
A simple invoice structure is used as the data source.
public class Invoice | |
{ | |
public string InvoiceID { get; set; } | |
public Customer Customer { get; set; } | |
public string InvoiceNumber { get; set; } | |
public string InvoiceDate { get; set; } | |
public List<LineItem> LineItems { get; set; } | |
} | |
public class LineItem | |
{ | |
public string LineItemID { get; set; } | |
public string Description { get; set; } | |
public string Quantity { get; set; } | |
public string Price { get; set; } | |
public string Tax { get; set; } | |
public string Total { get; set; } | |
} | |
public class Customer | |
{ | |
public string CustomerID { get; set; } | |
public string Name { get; set; } | |
public string Email { get; set; } | |
public string Phone { get; set; } | |
public string Address { get; set; } | |
public string City { get; set; } | |
public string State { get; set; } | |
public string Zip { get; set; } | |
public string Country { get; set; } | |
} |
The GetDummyInvoiceData method generates a dummy JSON file from the data structure, which is then used in the Document Editor.
public static string GetDummyInvoiceData() | |
{ | |
Invoice invoice = new Invoice | |
{ | |
InvoiceID = "123456789", | |
InvoiceNumber = "123456789", | |
InvoiceDate = "2020-01-01", | |
Customer = new Customer | |
{ | |
CustomerID = "123456789", | |
Name = "John Doe", | |
Email = "" | |
}, | |
LineItems = new List<LineItem> | |
{ | |
new LineItem | |
{ | |
LineItemID = "123456789", | |
Description = "Item 1", | |
Quantity = "1", | |
Price = "100.00", | |
Tax = "10.00", | |
Total = "110.00" | |
}, | |
new LineItem | |
{ | |
LineItemID = "123456789", | |
Description = "Item 2", | |
Quantity = "1", | |
Price = "100.00", | |
Tax = "10.00", | |
Total = "110.00" | |
}, | |
new LineItem | |
{ | |
LineItemID = "123456789", | |
Description = "Item 3", | |
Quantity = "1", | |
Price = "100.00", | |
Tax = "10.00", | |
Total = "110.00" | |
} | |
} | |
}; | |
List<Invoice> invoices = new List<Invoice>(); | |
invoices.Add(invoice); | |
return JsonConvert.SerializeObject(invoices); | |
} |
Creating the Editor
In the controller method Editor, the dummy data is created, and if an existing template is to be opened, the template is retrieved from the database.
public IActionResult Editor(string id = null) | |
{ | |
EditorViewModel model = new EditorViewModel() | |
{ | |
InvoiceData = InvoiceData.GetDummyInvoiceData(), | |
DocumentId = id | |
}; | |
if (id != null) | |
{ | |
// url encoded | |
id = id.Replace("%2F", "/"); | |
model.TemplateData = Storage.GetTemplate(id); | |
} | |
return View(model); | |
} |
In the view itself, the data and template are loaded into a Document Editor instance.
@{ | |
if (Model.TemplateData != null) | |
{ | |
@Html.TXTextControl().TextControl().LoadDataFromJson(Model.InvoiceData).LoadText(Convert.FromBase64String(Model.TemplateData), TXTextControl.Web.BinaryStreamType.InternalUnicodeFormat).Render() | |
} | |
else | |
{ | |
@Html.TXTextControl().TextControl().LoadDataFromJson(Model.InvoiceData).Render() | |
} | |
} |
Template Storage
Once the template with merge fields and repeating blocks is created, the template can be saved using the Save button.
The saveDocument JavaScript function saves the document and posts it to the Home/Save endpoint along with the document ID.
function saveDocument() { | |
TXTextControl.saveDocument(TXTextControl.StreamType.InternalUnicodeFormat, function (content) { | |
$.ajax({ | |
type: "POST", | |
url: "/Home/Save?id=@Model.DocumentId", | |
contentType: "application/json", | |
data: JSON.stringify(content), | |
success: function () { | |
setDirtyFlag(); | |
$("#save").addClass("disabled"); | |
}, | |
error: function () { | |
alert("An error occurred while saving the data."); | |
} | |
}); | |
}); | |
} |
The endpoint calls the Storage.AddTemplate method with the document data and ID.
[HttpPost] | |
public IActionResult Save([FromBody] Content data, string id) | |
{ | |
Storage.AddTemplate(new MemoryStream(Convert.FromBase64String(data.Data)), id); | |
return Ok(); | |
} |
This method uses LiteDB to store the file in the database with the unique identifier.
private static readonly LiteDatabase db = new LiteDatabase(@"Filename=App_Data/documents.db; Connection=shared"); | |
public static void AddTemplate(MemoryStream stream, string id = null, string name = "template.tx") | |
{ | |
var templateId = id ?? "$/templates/" + Guid.NewGuid().ToString(); | |
db.FileStorage.Upload(templateId, name, stream); | |
} |
Mail Merge
When you click Merge, the template is retrieved from the database and merged with the invoice data.
A PDF is created and downloaded directly.
The Merge method retrieves the template from the database by the given ID and uses Mail
╰ DocumentServer Namespace
╰ MailMerge Class
The MailMerge class is a .NET component that can be used to effortlessly merge template documents with database content in .NET projects, such as ASP.NET web applications, web services or Windows services. to merge the invoice data into the template.
public IActionResult Merge(string id) | |
{ | |
// url encoded | |
id = id.Replace("%2F", "/"); | |
var templateData = Storage.GetTemplate(id); | |
using (TXTextControl.ServerTextControl tx = new TXTextControl.ServerTextControl()) | |
{ | |
tx.Create(); | |
tx.Load(Convert.FromBase64String(templateData), TXTextControl.BinaryStreamType.InternalUnicodeFormat); | |
using (MailMerge mailMerge = new MailMerge()) | |
{ | |
mailMerge.TextComponent = tx; | |
mailMerge.MergeJsonData(InvoiceData.GetDummyInvoiceData()); | |
} | |
tx.Save(out byte[] data, TXTextControl.BinaryStreamType.AdobePDF); | |
// return pdf document | |
return File(data, "application/pdf", "document.pdf"); | |
} | |
} |
To see how the database interface works to store templates and merge data into them to generate PDF documents, you can download the full sources of this sample.