Posting a collection - is empty/null when adding a class on the table row - asp.net

I have a simple ASP.NET MVC application, where our users have a table which has some options to edit some settings.
This table is build dynamically using jQuery since this is some legacy code. The code to make the table is:
function setInvoiceTable(result) {
result.OverduesPaged.forEach(function (item, index) {
var externalName = 'OverduesPaged[' + index + '].ExternalInvoiceGuid';
var debtorName = 'OverduesPaged[' + index + '].Debtor';
var visibleName = 'OverduesPaged[' + index + '].IsSelected';
var externalInvoiceGuidField = '<input type=\'hidden\' value=\'' + item.ExternalInvoiceGuid + '\' name=\'' + externalName+ '\' />';
var debtorField = '<input type=\'hidden\' value=\'' + item.Debtor + '\' name=\'' + debtorName + '\' />';
var invisibleField = '<input type=\'hidden\' value=\'false\' name=\'' + visibleName + '\' id=\'' + visibleName + '\' /></label>';
var visibleField = '<label><input type=\'checkbox\' value=\'true\' name=\'' + visibleName + '\' id=\'' + visibleName + '\' /> Start sag';
var insertStr = "<tr>" +
"<td>" + externalInvoiceGuidField + debtorField + visibleField + invisibleField + "</td>" +
"<td>" + item.InvoiceId + "</td>" +
"<td>" + item.Debtor + "</td>" +
"<td>" + item.DateString +"</td>" +
"<td>" + item.DaysSinceDueString +"</td>" +
"<td>" + item.GrossAmountString + "</td>" +
"<td>" + item.RemainderAmountString + "</td>" +
"</tr>";
$('#accounting_invoices_table').append(insertStr);
});
}
When I POST, this works perfectly for us. We have an endpoint in our controller which has this signature:
[System.Web.Mvc.HttpPost]
public ActionResult StartDebtCollectionCases(UpcomingDashboardViewModel vm)
{
// code
}
The collection I'm building is the OverduesPaged which is a part of our view model:
public class UpcomingDashboardViewModel
{
public List<OverdueUpcomingInvoiceViewModel> OverduesPaged { get; set; }
// more stuff not relevant to question
}
This is my challenge:
I've added a css class to the <tr> row like this:
// new code added
var removeClass = 'ok';
if (item.IsAlreadyCase) {
visibleField = '<label type="text">Allerede startet</label>';
removeClass = 'remove';
} else if (item.IsBlocked) {
visibleField = '<label type="text">Sat i bero</label>';
removeClass = 'remove';
}
else if (item.Currency != "DKK") {
visibleField = '<label type="text">Faktura skal være dansk valuta</label>';
removeClass = 'remove';
}
var insertStr = "<tr class='" + removeClass + "'>" +
"<td>" + externalInvoiceGuidField + debtorField + visibleField + invisibleField + "</td>" +
// rest of code from above
Now I end up with a table exactly like before, but with a class which is either OK or REMOVE.
However, when I now do the POST, the whole collection, OverduesPaged, is null/empty:
I tried to add the class to the <td> instead, but then the collection was null/empty.
Any ideas what is wrong here?

The issue is not related to adding the class name itself, but rather the invalid html that you generating if ant of the code in the if or else if blocks are executed. In those blocks you are creating <label> element with a closing tag, but no input (its not clear if you need the checkbox or not in those cases), so when you combine visibleField + invisibleField you get unbalanced <label> tags (visibleField has opening and closing tags, but invisibleField only has a closing </label> tag.
You code in the if blocks to generate visibleField would need to be similar to what you generate in the original code - i.e. just an opening <label> with the html for the checkbox.
As you have acknowledged in the comments, this is very fragile and error prone code that is difficult to debug. As you are intending to rewrite it, consider returning a partial view in your ajax call (that is strongly bound to the model), or if you need to return Json, then consider a hidden template (outside the <form> tags) that you clone and update in the script, for example
<div id="newrow" style="display:none">
<tr>
<td>
<input class="invoice" type="hidden" name="OverduesPaged[#].ExternalInvoiceGuid value />
<input class="debtor" type="hidden" name="OverduesPaged[#].Debtor value />
....
</td>
....
</tr>
</div>
and then you script becomes
var table = $('#accounting_invoices_table');
result.OverduesPaged.forEach(function (item, index) {
var clone = $('#newrow').clone();
// Update indexer
clone.html($(clone).html().replace(/\[#\]/g, '[' + index + ']'));
// Update values
clone.find('.invoice').val(item.ExternalInvoiceGuid);
....
table.append(clone.html());
});
As a side note, your existing id attributes are invalid because they contain ., [ and ] characters (if you attempted to use these in jQuery selectors, they would fail (for example the . will be interpreted as a class name), so they should be omitted in the html

Related

How can i parse document.write/response.write to use single quotes instead of double quotes for AngleSharp?

I'm working with old html(ASP) files and i need to convert/parse them to work with new browsers.
I'm using AngleSharp, my problem is when it tries to parse response and document.write that uses single quotes for it's values and AngleSharp parse it to double quotes.
Input
Response.Write ("<input type=text name=attrname value='" + sVar + "'>");
Output (AngleSharp)
Response.Write ("<input type="text" name="attrname" value="" + sVar + "">");
Output expected
Response.Write ("<input type='text' name='attrname' value='" + sVar + "'>");
Is there a way to skip parsing or set a different formating for both? Thank you in advance!
The serialization is done by an IMarkupFormatter. By default, this formatter uses double quotes for the attributes (as the formatter does not know that you are inside some ASP code where you use double quotes on the outside).
Easiest way would be to roll your own formatter (example):
class MyMarkupFormatter : HtmlMarkupFormatter
{
protected override string Attribute(IAttr attr)
{
return $"{attr.Name}='{attr.Value}'";
}
}
You could use it like this:
var config = Configuration.Default;
var context = BrowsingContext.New(config);
var input = "<input type=text name=attrname value='\" + sVar + \"'>";
var document = await context.OpenNewAsync();
var formatter = new MyMarkupFormatter();
document.Body.InnerHtml = input;
document.Body.FirstChild.ToHtml(formatter).Dump(); // <input type='text' name='attrname' value='" + sVar + "'>
Note that the implementation of Attribute is only so simple for illustration purposes. You should handle more cases (and potentially take care of transforming contained single quotes etc.).

Change Field STatus

I have a button in a google-app-maker page, it's function is to sending Invoice by email. So once this button clicked, it will do two function.
1. Sending invoice by email.
2. Change status of EmailStatus to 'YES'.
/* var widgets = widget.parent.descendants; */
var to = "webmaster#myemail.com";
var subject = "Prepare Invoice : " + widget.datasource.item.Client_Name;
var msg = "Please Prepare Invoice for " + "\n\nClient Name : " +
widget.datasource.item.Client_Name + "\n\nService : " +
widget.datasource.item.Service + "\n\nCase : " +
widget.datasource.item.Subjects + "\n\nScope :" +
widget.datasource.item.Scope + "\n\nSubject : " +
widget.datasource.item.Subjects + "\n\nStart :" +
widget.datasource.item.Start + "\n\nInterim : " +
widget.datasource.item.Interim + "\n\nStatus :" +
widget.datasource.item.Statusx + "\n\nCA : " +
widget.datasource.item.Client_Ref + "\n\nBilling : " +
widget.datasource.item.Billing + "\n\nFee VS : " +
widget.datasource.item.Fee_VS + "\n\nFee VI" +
widget.datasource.item.Fee_VI + "\n\nNotes : " +
widget.datasource.item.Notes + "\n\nPrep Invoice : " +
widget.datasource.item.Prep_Invoice + "\n\nInvoiced : " +
widget.datasource.item.Prep_Invoice + "\n\nInvoice Number : " +
widget.datasource.item.Invoice_Number;
SendEmail(to, subject, msg);
widget.datasource.modes.create.item.EmailStatus = 'YES';
There's no problem with sending email, but for EmailStatus change to field have problem. It can not change value from NULL to 'YES'. Do you have any idea how to solved it ?
Thanks
Here is a scenario how to handle this assuming that your EmailStatus is just field in the same model/datasource as where you have all of your invoice information.
Delete this line of code:
widget.datasource.modes.create.item.EmailStatus = 'YES';
Change this line of code:
SendEmail(to, subject, message);
to:
SendEmail(to, subject, message, widget.datasource.item);
Change your client send email function to this:
function SendEmail(to, subject, message, item) {
google.script.run
.withSuccessHandler(function() {
item.EmailStatus = 'YES';
})
.withFailureHandler(function(error) {
//include a failure message popup or something here
})
.ServerSendEmailFunction(to, subject, message);
}
Hope this helps and solves your problem.
Is "EmailStatus" a field in the datasource of the widget, or is it a field in a different datasource? If it is actually a field in a different datasource/model, then you have to specify which record in that other datasource you want to connect to (in this case, the record called "Yes").
I'd recommend creating another server script function to set the status to "Yes" - here's the instructions for doing that: https://developers.google.com/appmaker/models/relations#server_script
Then call this new function in your success handler for the SendEmail function.

How can I hide sb.append in email if field is empty in asp.net?

In one of my forms the answers are optional. How can I get it so that only the fields that have been filled in show on the email that the form sends out?
Code example:
sb.Append("<br /><br /><br />Email from: " + txtEmail.Text + "\n");
sb.Append("<br /> <br />Site Name : " + txtSiteName.Text + "\n");
sb.Append("<br />Contract number : " + txtContractno.Text + "\n");
sb.Append("<br />Department : " + txtDepartment.Text + "\n");
If no one puts in their department, I dont want the heading and blank space where the answer should go to appear on the email. However if the department is filled in on the form, then I do want it to appear on the email. What should I do?
Two simplest options would be:
if (!string.IsNullOrWhitespace(txtDepartment.Text))
sb.Append("<br />Department : " + txtDepartment.Text + "\n");
...
or
sb.Append((!string.IsNullOrWhitespace(txtDepartment.Text)) ? "<br />..." : string.Empty);
Of which the first is probably preferable as it skips the call to append completely if the string's not there.

html.partial with dynamic append using script (Razor)

trying to do the below
$('#body').append('<div id=\"'+ name + 'div\"' + '>' + '\'' + #Html.Partial("_ChatWindow") + '\'' + '</div>');
_chatwindow.cshtml is just
<button>test</button>
but i get a run time syntax error at the opening angle bracket of the partial class. Any suggestions?
You need to create a string for partial view content:
$('#body').append('<div id=\"'+ name + 'div\"' + '>' + '\'' + '#Html.Partial("_ChatWindow")' + '\'' + '</div>');

How correctly assign value to field

I am trying to assign value for one edit field(not asp.net control) in asp.net application using JavaScript code. It seems that < character in value string gives problems for ASP.NET. If I remove < and > characters from value everything works fine.
Where is the problem? How to pass <> characters to the field? I don't want to use ServerSide code I want to do it on ClientSide using JS and HTML Edit box.
function loadShareBox(pageTitle) {
document.getElementById("shareHTML").value = '<a href="' + document.location.href + '" target=_blank>' + pageTitle + '</a>';
}
regards,
Tomas
try using these
< corresponds <
> corresponds >
the code would look like this
function loadShareBox(pageTitle) {
document.getElementById("shareHTML").value = '<a href="' + document.location.href + '" target=_blank>' + pageTitle + '</a>';
}
edit: ah, I think there is another problem. You are trying to insert a new element within another element. So you should create a new element and append in shareHTML.
var myLink = document.createElement("a");
myLink.setAttribute("href", "mylink");
var text = document.createTextNode("Link name");
myLink.appendChild(text);
var myElement = document.getElementById("shareHTML")
myElement.appendChild(myLink);
this should do the work

Resources