ASP.NET MVC Razor engine show three data in each row? - asp.net-mvc

In the ASP.NET MVC Razor engine I want to show three data entries in each row so I write this:
<table width="100%" border="0" cellspacing="22" cellpadding="0" style="line-height:18px;">
<tr>
<td align="center" valign="top">
<table border="0" cellspacing="0" cellpadding="0">
<tr>
#{
int counter = 0;
foreach (MVCTaranehMah.Models.Folder item in ViewBag.items)
{
counter++;
if(counter%3 == 0)
{
<tr>
}
<td width="205" height="180" align="center" valign="top"><br />
<p align="center" valign="top" class="header3">#item.title</p>
</td>
#if(counter%3 == 0)
{
</tr>
}
}
}
</tr>
</table>
</td>
</tr>
</table>
But I get this error
The code block is missing a closing "}" character. Make sure you have a matching "}" character for all the "{" characters within this block, and that none of the "}" characters are being interpreted as markup.
What's the problem and how can I do something like this?

I think the code does not like that you seemingly have unclosed HTML tags.
Place before the tr, #:
Remove # from the front of the other if statement.
For example:
if (counter%3 == 0)
{
#:<tr>
}

Rather than trying to force the list into a table, you could just render it as a list:
<ul class="thumbs">
#foreach (var item in ViewBag.Items)
{
<li>
<a href="galleryDetails?id=#item.id">
<img src="#Url.Content(item.thumb)">
#item.title
</a>
</li>
}
</ul>
Styling the list to display with three items per row is trivial. Start here, and tweak it as needed:
ul.thumbs {
overflow: hidden;
}
ul.thumbs li {
float: left;
width: 205px;
height: 180px;
margin: 22px;
text-align: center;
}
ul.thumbs img {
width: 173px;
height: 173px;
border: 0;
}

Related

Selecting a specific row from a table using two text criteria (Playwright, js)

I'm having trouble using potential unique identifiers to select a specific row from a table.
Given the following table
#events {
font-family: Arial, Helvetica, sans-serif;
border-collapse: collapse;
width: 100%;
margin: 10px 0 20px 0;
}
#events td,
#events th {
border: 1px solid #ddd;
padding: 8px;
}
#events tr:nth-child(even) {
background-color: #f2f2f2;
}
#events tr:hover {
background-color: #ddd;
}
#events th {
padding-top: 12px;
padding-bottom: 12px;
text-align: left;
background-color: #04AA6D;
color: white;
}
<div>
<table id="events" class="table table-striped">
<thead>
<tr>
<th data-qaid="checkbox"><input type="checkbox" /></th>
<th data-qaid="event">Event</th>
<th data-qaid="date">Date</th>
<th data-qaid="location">Location</th>
<th data-qaid="purchase-date">Ticket Purchased</th>
</tr>
</thead>
<tbody>
<tr>
<td data-qaid="checkbox"><input type="checkbox" /></td>
<td data-qaid="event">Movie</td>
<td data-qaid="date">06/06/2022</td>
<td data-qaid="location">Frankfort</td>
<td data-qaid="purchase-date">06/06/2022</td>
</tr>
<tr>
<td data-qaid="checkbox"><input type="checkbox" /></td>
<td data-qaid="event">Concert</td>
<td data-qaid="date">06/06/2022</td>
<td data-qaid="location">Frankfort</td>
<td data-qaid="purchase-date">06/06/2022</td>
</tr>
<tr>
<td data-qaid="checkbox"><input type="checkbox" /></td>
<td data-qaid="event">Park</td>
<td data-qaid="date">06/10/2022</td>
<td data-qaid="location">Memphis</td>
<td data-qaid="purchase-date">06/06/2022</td>
</tr>
<tr>
<td data-qaid="checkbox"><input type="checkbox" /></td>
<td data-qaid="event">Concert</td>
<td data-qaid="date">06/10/2022</td>
<td data-qaid="location">Memphis</td>
<td data-qaid="purchase-date">06/06/2022</td>
</tr>
<tr>
<td data-qaid="checkbox"><input type="checkbox" /></td>
<td data-qaid="event">Sport</td>
<td data-qaid="date">06/12/2022</td>
<td data-qaid="location">Atlanta</td>
<td data-qaid="purchase-date">06/06/2022</td>
</tr>
</tbody>
</table>
</div>
<div id="change-location">
<label>New Location</label>
<input type="text" />
<button>Update Selected</button>
</div>
Using a playwright Locator, I want to be able to select the row for the Concert on 06/10/2022 and then be able to click the checkbox on that row.
I've been able to do this using a single column locator and selecting the first row encountered (using .nth(#)).
const child_locator = page.locator('[data-qaid="Event"]', { hasText: "Concert" }).nth(0);
const row_locator = page.locator("#events tbody tr", { has: child_locator });
row_locator.locator('[data-qaid="checkbox"] input').setChecked();
But this won't work, since my desired row would not be the first encountered row result.
I'd like to have something more robust / dynamic. And I'm having a hard time figuring out how to do this. I've tried various things like combining locators, using the resultant array of Locators to restrict subsequent searches. I think it comes from my understanding of Playwright locators being as complete as it can be. And I am studying the docs, but haven't figured this out yet.
I think my only real solution may be to get the text of the entire row and just regex on that. But this may have issues with false positives if the text being searched for appears in another column on a row. Such as in the given example, if I wanted to choose the Concert with Date of "06/06/2022", my regex would still select the Concert with Date "06/10/2022" since the Ticket Purchased would also match "06/06/2022"
Well, since you don't have any explicit selectors you can bind to, the only option is to reduce:
You collect all of trs.
You pick trs that have tds of kind Concert
From these, you pick trs that have tds appearing on 06/10/2022
You click on collected element(s)
Here's what I came up with:
/**
* options {{page: Page, search_array: [{column_index: number, needle: string}], tr_selector: Locator}}
*/
static async getRowByValues(options) {
// get the table data
const table_data = await options.page.locator(table_selector).allInnerTexts();
let row_index = table_data.findIndex( (row_text) => {
const text_array = row_text.split("\t");
// loop through the search_array data and match to text_array
for (const col_data of options.search_array) {
// fail immediately if false, continue if true.
if (text_array[col_data.column_index] !== col_data.needle) {
return false;
}
}
return true;
});
if (row_index >= 0) {
return options.page.locator(tr_selector).nth(row_index);
} else {
return null;
}
}
And to use this, one could do:
const desired_row = await getRowByValues({
page: page,
search_array: [
{
column_index: 1,
needle: "Concert"
},
{
column_index: 2,
needle: "06/10/2022"
}
],
tr_selector: page.locator('#events tbody tr')
});
if (desired_row) {
await desired_row.locator('[data-qaid="checkbox"] input').setChecked(true);
await expect(desired_row.locator('[data-qaid="checkbox"] input')).toBeChecked();
}

Generating PDF from HTML with tables and rows

I am developing a simple application for creating invoices in Swift for iOS.
For this, I have a simple template HTML with tables and rows (td / tr).
I want to convert this HTML template to a multiple page PDF. It's working like a charm thanks to UIPagePrintRenderer but some rows are duplicated on two pages or the row is cut on the two pages.
I have tried to add css "page-break" on my template. I have a good placement when I print template on a web browser.
But, when I export HTML to PDF (thanks to UIPagePrintRenderer), the CSS styles were not applied on the PDF document, and my elements are duplicated.
I am looking for a better solution to convert HTML to PDF. Any one encountered a similar problem?
UPDATE :
Thanks for response guys, below more information of problem and my code.
First this is my function for convert HTML string to a PDF file.
func createPDF(formatter: UIViewPrintFormatter) -> String {
let render = CustomPrintRenderer()
render.addPrintFormatter(formatter, startingAtPageAt: 0)
formatter.maximumContentHeight = 605.0
let pdfData = NSMutableData()
UIGraphicsBeginPDFContextToData(pdfData, CGRect.zero, nil)
for i in 0...render.numberOfPages {
UIGraphicsBeginPDFPage()
if(i != 0) {
render.setupAfterFirstPage()
}
render.drawPage(at: i, in: UIGraphicsGetPDFContextBounds())
}
UIGraphicsEndPDFContext()
pdfFilename = "\(AppDelegate().getDocDir())/Invoice-\(invoiceNumber!).pdf"
pdfData.write(toFile: pdfFilename, atomically: true)
return pdfFilename
}
Second, this is my CustomPrintRenderer() class for specified printing zone.
class CustomPrintRenderer: UIPrintPageRenderer {
// A4 Gabarit
let A4PageWidth: CGFloat = 595.2
let A4PageHeight: CGFloat = 841.8
let topPadding: CGFloat = 50.0
let bottomPadding: CGFloat = 100.0
let pageInset: CGFloat = 42.5
//let leftPadding: CGFloat = 100.0
//let rightPadding: CGFloat = 100.0
override init() {
super.init()
initFrame()
}
func initFrame() {
// Specify the frame of the A4 page.
let pageFrame = CGRect(x: 0.0, y: 0.0, width: A4PageWidth, height: A4PageHeight)
let printable = CGRect(x: 0.0, y: -topPadding, width : A4PageWidth, height: A4PageHeight - topPadding).insetBy(dx: pageInset, dy: pageInset)
self.setValue(NSValue(cgRect: pageFrame), forKey: "paperRect")
self.setValue(NSValue(cgRect: printable), forKey: "printableRect")
}
func setupAfterFirstPage() {
let printable = CGRect(x: 0.0, y: topPadding, width : A4PageWidth, height: A4PageHeight - topPadding - bottomPadding).insetBy(dx: pageInset, dy: pageInset)
self.setValue(NSValue(cgRect: printable), forKey: "printableRect")
}
}
This is my invoice on HTML (on ios app)
This is my invoice converted to PDF.
You can see on this screenshots than my items are cropped.
So, thanks to "page-break" style in css or other way, i want to display a item in next page if the element can not be placed totally on current page.
UPDATE 2 :
This is my HTML Template :
Home'Invoice - Invoice
body {
max-width:90%;
margin:auto;
padding:30px;
font-size:16px;
line-height:24px;
font-family:'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif;
color:#485C74;
}
/*#media print
{
table { page-break-after:auto; }
tr.items { page-break-inside:avoid; page-break-after:auto; }
td.items { page-break-inside:avoid; page-break-after:auto; }
thead { display:table-header-group; }
tfoot { display:table-footer-group; }
}*/
/*#page {
size: A4;
margin: 0;
}
#media print {
html, body {
width: 210mm;
height: 297mm;
}
}*/
.middle {
width: 50%;
}
.invoice-box table td{
padding:5px;
vertical-align:top;
}
.logo-images img {
width:100%;
max-width:300px;
max-height:150px;
}
.invoice-box .left-pos {
text-align: left;
}
.invoice-box .center-pos {
text-align: center;
}
.invoice-box .right-pos {
text-align: right;
}
.invoice-box table thead.heading td{
background:#fab800;
border-bottom:1px solid #485C74;
font-weight:bold;
}
.invoice-box table{
width:100%;
line-height:inherit;
text-align:left;
}
.invoice-box table tr.top table td{
padding-bottom:20px;
}
.invoice-box table tr.top table td.title{
font-size:45px;
line-height:45px;
color:#485C74;
}
.invoice-box table tr.information table td{
padding-bottom:40px;
}
.invoice-box table tr.details td{
padding-bottom:20px;
}
.invoice-box table tr.item td, .invoice-box table tr.service td{
border-bottom:1px solid #eee;
}
.invoice-box table tr.item.last td, .invoice-box table tr.service.last td{
border-bottom:none;
}
.invoice-box .items-last, .invoice-box .services-last{
border-top:2px solid #485C74;
font-weight:bold;
}
footer {
text-align: center;
}
#media only screen and (max-width: 600px) {
.invoice-box table tr.top table td{
width:100%;
display:block;
text-align:center;
}
.invoice-box table tr.information table td{
width:100%;
display:block;
text-align:center;
}
}
</style>
</head>
<body>
<div class="invoice-box">
<table cellpadding="0" cellspacing="0">
<tbody>
<!-- Header Top section -->
<tr class="top">
<td colspan="5">
<table>
<tbody>
<tr>
<td class="logo-images"> <img src="data:image/png;base64, #LOGO_USER#"> </td>
<td class="right-pos">
Invoice : ##INVOICE_NUMBER#
<br>
Date : #INVOICE_DATE#
<br>
Due Date : #DUE_DATE#
</td>
</tr>
</tbody>
</table>
</td>
</tr>
<!-- Payment section -->
<!-- Informations section -->
<tr class="information">
<td colspan="5">
<table>
<tbody>
<tr>
<td class="middle left-pos"> #SENDER_INFO# </td>
<td class="middle right-pos"> #RECIPIENT_INFO# </td>
</tr>
</tbody>
</table>
</td>
</tr>
<!-- Informations section -->
</tbody>
</table>
</div>
<div class="invoice-box">
<table cellpadding="0" cellspacing="0">
<tbody>
<!-- Payment section -->
<thead class="heading">
<td> Payment Method </td>
</thead>
<tr class="details">
<td class="left-pos"> Payment desired : #PAYMENT_METHOD# <br>
A deposit of #PAYMENT_PERCENT# must be paid when signing "good for the agreement" of this invoice, is #PAYMENT_PERCENT_PRICE#.
</td>
</tr>
</tbody>
</table>
</div>
<div class="invoice-box">
<table cellpadding="0" cellspacing="0">
<tbody>
<!-- Items section -->
<thead class="heading">
<td class="left-pos"> Item / Description </td>
<td class="center-pos"> Reference </td>
<td class="center-pos"> Quantity </td>
<td class="center-pos"> Unit cost </td>
<td class="right-pos"> Total Price (excl. tax)</td>
</thead>
#ITEMS#
<tr class="total">
<td></td>
<td></td>
<td></td>
<td></td>
<td class="right-pos items-last">
Subtotal (excl. tax) : #TOTAL_AMOUNT_HT#
<br>
Sales Tax (#VAT_RAT#) : #VAT_PRICE#
<br>
<br>
Total (incl. tax) : #TOTAL_AMOUNT_TTC#
</td>
</tr>
<!-- Items section -->
</tbody>
</table>
</div>
<footer>
<div class="footer_content">
<hr>
<p>Invoice powered By </p>
<div class="logo-images"> <img src="data:image/png;base64, #LOGO_FOOTER#"> </div>
</div>
</footer>
</body>
</html>
single_item.html :
<tr class="item">
<td class="left-pos">#ITEM_NAME# <br> #ITEM_DESC#</td>
<td class="center-pos">#ITEM_REF#</td>
<td class="center-pos">#ITEM_QUANTITY#</td>
<td class="center-pos">#ITEM_UNIT_COST#</td>
<td class="right-pos">#ITEM_TOTAL_PRICE#</td>
</tr>
last_item.html :
<tr class="item last">
<td class="left-pos">#ITEM_NAME# <br> #ITEM_DESC#</td>
<td class="center-pos">#ITEM_REF#</td>
<td class="center-pos">#ITEM_QUANTITY#</td>
<td class="center-pos">#ITEM_UNIT_COST#</td>
<td class="right-pos">#ITEM_TOTAL_PRICE#</td>
</tr>
UPDATE 3 :
When I added this code on my "item" class, these items have a good page-break but the display is bad. But whitout "display:block;" is still not work :
.item {
display:block;
page-break-inside:avoid;
page-break-after: auto;
}

print specific div from the page position cant controled

i have html page
<table class='table table-responsive table-hover table-responsive sortable draggable' id='print' border='5'>
<thead>
<tr class='warning'>
<td>head1 <a class='delete'>delete</a></td>
<td>head2 <a class='delete'>delete</a></td>
<td>head3 <a class='delete'>delete</a></td>
</tr>
</thead>
<tbody>
<tr>
<td>body1 body1 body1dfsffffffffffffffffffffffff </td>
<td>body2</td>
<td>body3</td>
</tr>
<tr>
<td>body4</td>
<td>body5</td>
<td>body6</td>
</tr>
<tr>
<td>body7</td>
<td>body8</td>
<td>body9</td>
</tr>
</tbody>
<tfoot>
<tr>
<td></td>
<td></td>
<td></td>
</tr>
</tfoot>
</table>
and when i need to print the page i just want to print the table
i used this css ..
#media print
{
body *
{
visibility: hidden;
}
#print, #print *
{
visibility: visible;
}
#print
{
position: absolute;
left: 0;
top: 0;
}
}
and when i print the screen the table come in the center not in the top 0px
how cound i let the table be absolute;
its not working
thank you

how to get tooltip text which is generated dynamic

<tbody>
<tr class="" style="height:65px;">
<tr class="" style="height:65px;">
<td class="dhx_matrix_scell" style="width:99px; height:64px;">Ashmita </td>
<td>
<div class="dhx_matrix_line" style="width:1181px; height:65px; position:relative;">
<div class="dhx_marked_timespan dhx_matrix_now_time" style="height: 64px; left: 105px; width: 1px; top: 0px;"></div>
<div class="dhx_marked_timespan gray_section" style="height: 64px; left: 588px; width: 591px; top: 0px;"></div>
<div class="dhx_cal_event_line Booked" style="position:absolute; top:2px; height: 17px; left:99px; width:28px;" event_id="1374736442513">
<table class="" cellspacing="0" cellpadding="0" style="width:1181px; height:65px;">
</div>
</td>
</tr>
<tr class="" style="height:65px;">
<tr class="" style="height:65px;">
<tr class="" style="height:65px;">
<tr class="" style="height:65px;">
</tbody>
In the above code when I hover the mouse on the element <div class="dhx_cal_event_line Booked" style="position:absolute; top:2px; height: 17px; left:99px; width:28px;" event_id="1374736442513">, I get a tooltip tipsy which is generate dynamically; I can't catch it using firepath. I have tried the action class like
Actions action = new Actions(driver);
WebElement element = driver.findElement(By.xpath(".//*[#id='scheduler']/div[3]/table/tbody/tr[2]/td[2]/div/div[4]"));
action.moveToElement(element).build().perform();
System.out.println("the tool tip text is"+element.getText());
action.moveToElement(element).release().build().perform();
but i get null as element text.
When you do this:
Actions action = new Actions(driver);
WebElement element = driver.findElement(By.xpath(".//*[#id='scheduler']/div[3]/table/tbody/tr[2]/td[2]/div/div[4]"));
action.moveToElement(element).build().perform();
Put a String source = driver.getPageSource(); and then save that source somewhere (or print it to console)
Take a look at the page source, to see what element has the tooltip text in it, and then you can write a selector for it.

A Good Format for a Table in TD

I have an table and needed Ajax form for each row so this is new implementation:
<tbody id="AllPhones">
#foreach(var item in Model.Phones) {
<tr class="gradeA odd" id="TR#(item.Id)">
#{Html.RenderPartial("_PhoneRow", item);}
</tr>
}
_PhoneRow Partial View:
#model MyModel
<td class="TableIncluded" colspan="4">
#using(Ajax.BeginForm("EditPhone","Phone", new { id = Model.Id }, new AjaxOptions {
UpdateTargetId = "TR" + Model.Id,
OnComplete = "CompleteEditPhone"
})) {
<table class="Internal">
<thead></thead>
<tbody>
<tr>
<td>#Html.DisplayFor(modelItem => Model.PhoneNumber)</td>
<td>#Html.DisplayFor(modelItem => Model.PhoneKind)</td>
<td>#if(Model.IsDefault) {<span class="BoolRadio True">Default</span>} else { <span></span>}</td>
<td><input type="submit" value="Edit" class="CallEditPhone" id = "Edit#(Model.Id)" /></td>
</tr>
</tbody>
</table>
}
</td>
As you see I must put form inside of <td> actually the first implementation was:
<td>#Html.DisplayFor(modelItem => Model.PhoneNumber)</td>
<td>#Html.DisplayFor(modelItem => Model.PhoneKind)</td>
<td>#if(Model.IsDefault) {<span class="BoolRadio True">Default</span>} else { <span></span>}</td>
<td><input type="submit" value="Edit" class="CallEditPhone" id = "Edit#(Model.Id)" /></td>
But now all of this <td>s covered in the new table and <td> so with new implementation elements in table are some disordered and I try to fix it with some css:
td.TableIncluded, td.TableIncluded table, td.TableIncluded form {
font-size: inherit;
margin: inherit;
height: inherit;
padding: inherit;
}
td.TableIncluded {
width: 100%;
}
But yet there is some horizontal disorders, This is First Implementation Without Table inside <td>:
And this is second one with table inside <td>
So what is your suggestion to fix the second one like first one ?
The easiest way to fix is, is to give three of the four <td> elements a fixed width. Since the table is 100% wide, the fourth cell will take up the rest of the available width.
<table class="Internal">
<thead></thead>
<tbody>
<tr>
<td>#Html.DisplayFor(modelItem => Model.PhoneNumber)</td>
<td class="phonekind">#Html.DisplayFor(modelItem => Model.PhoneKind)</td>
<td class="phonedefault">#if(Model.IsDefault) {<span class="BoolRadio True">Default</span>} else { <span></span>}</td>
<td class="phoneedit"><input type="submit" value="Edit" class="CallEditPhone" id = "Edit#(Model.Id)" /></td>
</tr>
</tbody>
</table>
table.Internal { width: 100%; }
table.Internal td.phonekind { width: 90px; }
table.Internal td.phonedefault{ width: 90px; }
table.Internal td.phoneedit{ width: 90px; }
If this isn't working as it should, you can just give the four <td> elements the same fixed with as the header cells of the outer table.

Resources