I am having a problem with the <text> tag. The following code will not run due to the </tr> tag near the bottom. If i remove it, it works but it then prints an incorrect table. If i leave it i get the following error: Encountered end tag "tr" with no matching start tag. Are your start/end tags properly balanced?
How can i tell razor to ignore such things?
(I also tried to add a text tag around the /tr and also around all html code but that produces this: Encountered end tag "text" with no matching start tag. Are your start/end tags properly balanced?
#{
int i = 0;
foreach (var item in Model.Model)
{
if (i % 2 == 0)
{
<text><tr class="alternate-row"></text>
}
else
{
<text><tr></text>
}
<td>
<input type="checkbox" />
</td>
<td>
#item.Firstname
</td>
<td>
#item.Surname
</td>
<td>
george#mainevent.co.za
</td>
<td class="options-width">
<a href="" title="Edit" class="icon-2 info-tooltip">
</a><a href="" title="Edit"
class="icon-4 info-tooltip"></a><a href="" title="Edit" class="icon-5 info-tooltip">
</a>
</td>
</tr>
}
}
Update with another question
Why does Razor even test html-tags?
You can do this
<tr#if (i % 2 == 0) { <text> class="alternate-row"</text> }>
or you can set a variable that "holds" your extended html for the <tr> tag like this
int i = 0;
foreach (var item in Model.Model)
{
string ext = "";
if (i % 2 == 0)
{
ext = " class=\"alternate-row\"";
}
<tr#ext>
// ...
Thats the simplest solution, or you can create a custom html helper.
More information: Creating Custom HTML Helpers
Update
Darin said too, what he would create a custom html helper.
I suggest that too, if you need that more than one time.
conclusion
first choice is to create a html helper, second is to use my first
approach (inline if statement) and at last to use a variable.
It does not really depends on "how often" you need that, but if you really need
that only one time, choose the first approach.
Every of the three solutions are correct, its your decision depending on the time
you have.
hope this helps you
<tr#Html.Raw(i % 2 == 0 ? " class=\"alternate-row\"" : "")>
... some tds
</tr>
But personally I would write a custom Html helper to avoid this spaghetti code and have something along the lines of:
#using (Html.Tr(i))
{
<td>
<input type="checkbox" />
</td>
<td>
#item.Firstname
</td>
...
}
I would also refactor and get rid of the foreach loop and replace it with a simple display template call: #Html.DisplayForModel().
I have an alternate approach for you using javascript. Since you are using MVC3, you probably have access to jQuery. Add this little nugget of javascript (See jsFiddle Example)
$(function() {
$('tr:odd').addClass('alternate-row');
})
remove the the <text> blocks from around the tr tag in your conditional
Related
I'm working on a Blazor component with a table where it makes sense to factor out a couple pieces of the template. However it's not rendering correctly and the td elements I'm producing are not ending up inside the tr element, but instead are at the same level.
Below is a simplified version of the code. The body has the problem while the footer renders correctly. What is the correct way to accomplish what I'm trying to here? I know I could avoid all of the Razor syntax and just create a function that returns a raw MarkupString, but that doesn't seem like it should be necessary for a case like this.
<table>
<tbody>
#foreach (var row in data)
{
#:<tr>
RenderRow(row);
#:</tr>
}
</tbody>
<tfoot>
<tr>
#if (footerRow != null)
{
RenderRow(footerRow);
}
</tr>
</tfoot>
</table>
#{
void RenderRow(Row row)
{
<td>#row.RowNum</td>
RenderRowHalf(row.Left);
RenderRowHalf(row.Right);
}
void RenderRowHalf(RowHalf half)
{
<td>#half.Foo</td>
<td>#(Util.ColorNumber(half.Bar))</td>
}
}
A lot to unpick here - using #: before the <tr>, then calling a C# method is switching context and Blazor will auto-close the tag - get rid of the #: - not needed.
Change your methods to return RenderFragment<T> - the Blazor way of creating a fragment of Razor markup. Call them with # prefix to switch back to C#.
The <text> tag helper just provides a way to group markup in the C# code sectiion.
Use #code for your C# code, otherwise it is scoped to each render cycle.
<table>
<tbody>
#foreach (var row in data)
{
<tr>
#RenderRow(row)
</tr>
}
</tbody>
<tfoot>
<tr>
#if (footerRow != null)
{
#RenderRow(footerRow)
}
</tr>
</tfoot>
</table>
#code
{
RenderFragment<Row> RenderRow => row =>
#<text>
<td>#row.RowNum</td>
#RenderRowHalf(row.Left)
#RenderRowHalf(row.Right)
</text>
;
RenderFragment<RowHalf> RenderRowHalf => half =>
#<text>
<td>#half.Foo</td>
<td>#(Util.ColorNumber(half.Bar))</td>
</text>
;
}
I'm developing an web app using C# and MVC. One of the page has multiple <tr> which will contain information but this information gets updated over time (1 month to 6 month) range. So I only want to show the <tr> which include the information. The information is stored in a database, each <tr> has it's own column. The approach I've gone with is I read the data and apply if conditions in the view.
So something like
#if (!string.IsNullOrEmpty(Model.SomePropertyOne))
{
<tr>
<td>#Html.DisplayNameFor(model => model.SomePropertyOne)</td>
<td>#Html.DisplayFor(model => model.SomePropertyOne)</td>
</tr>
}
#if (!string.IsNullOrEmpty(Model.SomePropertyTwo))
{
<tr>
<td>#Html.DisplayNameFor(model => model.SomePropertyTwo)</td>
<td>#Html.DisplayFor(model => model.SomePropertyTwo)</td>
</tr>
}
...
I have to this 8 times. So my question is, is there a better approach than this or am I stuck with using all these if statements?
Please let me know if you require any further information
You can create a DisplayTemplate containing the condition. In /Views/Shared/DisplayTemplates/ create a partial view (say) MyTemplate.cshtml
#model string
#if (!string.IsNullOrEmpty(Model))
{
<tr>
<td>#Html.DisplayNameFor(m => m)</td>
<td>#Model</td>
</tr>
}
and then in the view
#Html.DisplayFor(m => m.SomeProperty, "MyTemplate")
#Html.DisplayFor(m => m.AnotherProperty, "MyTemplate")
.... //etc
The DisplayFor() will generate the html based on the template, so if the value of the property is null or string.Empty, then nothing will be generated for that property.
Side note: You should not be using <table> elements for layout (refer Why not use tables for layout in HTML? and Why Tables Are Bad (For Layout*) Compared to Semantic HTML + CSS). Instead, use css to style you layout. For example, change the DisplayTemplate to
<div class="field">
<div class="field-label">#Html.DisplayNameFor(m => m)</div>
<div class="field-value">#Model</div>
</div>
and add the following css
.field {
position: relative;
margin: 5px 0;
}
.field-label {
position: absolute;
width: 240px;
color: #808080;
}
.field-value {
margin-left: 250px;
}
You can solve your problem via reflection, something like that:
#foreach(var prop in Model.GetType().GetProperties().Where(x => x.PropertyType == typeof(string)))
{
var value = prop.GetValue(Model);
if (value != null)
{
<tr>
<td>#prop.Name</td>
<td><input value="#value.ToString()" name="#prop.Name" /></td>
</tr>
}
}
But, at this case, you should avoid to use #Html helpers, instead - write corresponding html explicitly.
This question already has answers here:
Event handler not working on dynamic content [duplicate]
(2 answers)
Closed 8 years ago.
I have the body of a table which is appended dynamically with ajax to the table element through a partial view in ASP.NET MVC. The partial view looks something like this...
#model IEnumerable<Plan>
#{
Layout = null;
}
#foreach (var plan in Model)
{
<tr>
<td>
#plan.Name
</td>
</tr>
}
...and appended to the table element which is static in the main View...
<table id="myPlanTable">
</table>
I am trying to register an onclick event for each of these anchor elements (there are a lot currently), using the jQuery on() function like this...
jQuery('#myPlanTable').on('click', 'tbody > tr:gt(0) > td > a.jumpToMyPlans', function () {
console.log('click');
});
...but the event refuses to fire. I've checked the DOM traversal in the browser console and it's definitely correct and returns the expected DOM set.
This selection statement worked for me....
jQuery('#myPlanTable').on('click', 'tr:gt(0) > td > a.jumpToMyPlans', function () {
console.log('click');
});
I think the problem was specifying tbody in the selector, which I guess is probably also dynamically generated, though not by me, I guess by the browser or something.
When partial view is render through ajax or jquery then to bind Jquery events use "live" as following:
jQuery('#myPlanTable').live('click', 'tbody > tr:gt(0) > td > a.jumpToMyPlans', function () {
console.log('click');
});
Try this:
jQuery('#myPlanTable').on('click', 'tbody > tr:gt(0) > td > a.jumpToMyPlans', function () {
console.log('click');
});
1) Change a.jumpToMyActionPlans to a.jumpToMyPlans
2) Add ); to close your click handler
I tested this and the click worked:
$(document).on('click', '#myPlanTable a.jumpToMyPlans' , function () {
alert('click');
});
the html i used to test it was:
<table id="myPlanTable">
<tr>
<td>
PAPA
</td>
</tr>
<tr>
<td>
Sapo
</td>
</tr>
</table>
Hope this helps you!
Hi I want to access text present in all section of my application. I cannot use id because in one application there are different tables with different id's. I want to access text name whenever I place mouse on that td cell irrespective of table so I can't use id. Please suggest me a way to do this using JQuery. The text which I want to access are from asp.net aspx page.
In jquery, you can apply a hover event to every td which fetches it's text. put the text in a variable, then pass it on to your .aspx handler with ajax. here is a simple example. its a good idea to put this script block in your ready function, or near the end of your document.
jQuery
$('td').hover(function () {
//mouse over
//get the data
var tdText = $(this).text();
console.log(tdText);
//do something with the data
var jqxhr = $.ajax("handler.aspx?text=" + tdText)
.done(function () {
console.log("success");
//do something
})
.fail(function () {
console.log("error");
//do something else
});
},
function () {
//mouse out
console.log("mouse-out");
}
);
I can only help you with determining if the mouse cursor is above any td element. You will need to modify the code to fit your needs to display something useful.
HTML:
<p id="message"> </p>
<table>
<tr>
<td>Data 1</td>
<td>Data 2</td>
<td>Data 3</td>
</tr>
<tr>
<td>Data A</td>
<td>Data B</td>
<td>Data C</td>
</tr>
</table>
JS:
addEventListener("mouseover", function(event) {
if (event.toElement.localName == 'td')
$('#message').html("You are in a table cell");
else
$('#message').html(" ");
}, false);
I also created a fiddle for you to test: http://jsfiddle.net/m3EmK/
I want to load some html data dynamically from the server (like a grid composed by lots f and ) using jQuery.
At the moment I load it like this:
$("#Ricerca_Div_ContenitoreRisultati table tbody").load("/Segnalazioni/CercaSegnalazioni/3");
and generate it like this:
public ActionResult CercaSegnalazioni(int flag, string sort)
{
[..]
XElement SegnalazioniTrovate = Models.Segnalazioni.Recupera(flag, sortVal);
string ritorno = "";
bool alterna = false;
foreach (XElement segnalazione in SegnalazioniTrovate.Elements("dossier"))
{
ritorno += alterna? "<tr>" : "<tr class = \"alternata\">";
ritorno += String.Format(#"
<td><span style=""white-space: nowrap"">{0}</span></td>
<td><span style=""white-space: nowrap"">{1}</span></td>
<td style =""display : none"">{2}</td>
<td><span style=""white-space: nowrap"">{3}</span></td>
<td><span style=""white-space: nowrap"">{4}</span></td>
<td><span style=""white-space: nowrap"">{5}</span></td>
</tr>",
(string)segnalazione.Element("NUM_DOSSIER") ?? "",
(string)segnalazione.Element("ANAG_RAGSOC_CGN") ?? "",
(string)segnalazione.Element("ID_RIFATT_SEGN0") ?? "",
Tools.DecodificaStatus(int.Parse((string)segnalazione.Element("FLG_STATUS") ?? "")),
Tools.RmuoviTime((string)segnalazione.Element("DT_ACCADIMENTO")?? ""),
(string)segnalazione.Element("COD_RAMO_LUNA") ?? ""
);
alterna = !alterna;
}
return Content(ritorno);
}
Or, simply put, I make up the HTML code server side with a very messy code I don't like and return it back so that it is ready to be used client-side.
Any better / cleaner solution?
Thanks
There's different ways of doing this, and although none of them end up looking perfectly clean, the one that works best for me is to do the HTML construction on the client side. The server can return an object that works well in javascript (let's say, List<Segnalazione>) and then the client-side handler does things like:
$(list).each(function() {
var tr = $('<tr />').append(
$('<td />').css('white-space', 'nowrap').text(this.NUM_DOSSIER)
).append(
$('<td />').css('white-space', 'nowrap').text(this.ANAG_RAGSOC_CGN)
)
$("#Ricerca_Div_ContenitoreRisultati table tbody").append(tr);
});
Obviously, I'm oversimplying your output, but hopefully that gives you the idea.
If nothing else, doing it in jquery gives you the automatic escaping of values within the 'text', 'attr', and 'css' methods rather than the HttpUtility.HtmlEncode, AttributeEncode methods that would clutter up your output in C#
The cleaner solution will be creating separate View and using more CSS:
UPDATED:
In case of Request.IsAjaxRequest() use PartialView:
Controller:
public ActionResult CercaSegnalazioni(int flag, string sort)
{
[..]
XElement SegnalazioniTrovate = Models.Segnalazioni.Recupera(flag, sortVal);
return PartialView("YourPartialView", SegnalazioniTrovate);
}
YourPartialView.ascx:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<XElement>" %>
<% bool alterna = false; %>
<table id="yourTableId">
<% foreach (XElement segnalazione in SegnalazioniTrovate.Elements("dossier")) { %>
<tr class="<%= alterna ? "alternata" : "" %>">
<% alterna = !alterna; %>
<td>
<span><%= (string)segnalazione.Element("NUM_DOSSIER") ?? "" %></span>
</td>
<td>
<span><%= (string)segnalazione.Element("ANAG_RAGSOC_CGN") ?? "" %></span>
</td>
<td class="nodisplay">
<%= (string)segnalazione.Element("ID_RIFATT_SEGN0") ?? "" %>
</td>
<td>
<span><%= Tools.DecodificaStatus(int.Parse((string)segnalazione.Element("FLG_STATUS") ?? "")) %></span>
</td>
<td>
<span><%= Tools.RmuoviTime((string)segnalazione.Element("DT_ACCADIMENTO")?? "") %></span>
</td>
<td>
<span><%= (string)segnalazione.Element("COD_RAMO_LUNA") ?? "" %></span>
</td>
</tr>
<% } %>
</table>
CSS:
table#yourTableId td span {
white-space: nowrap
}
.nodisplay {
display : none
}
Your best bet is probably to de-couple the presentation from the data. This would mean avoiding having any presentation code (ie. HTML generation) in your controller.
There are 2 ways to handle this...
Nested Partial Views
Partial Views can render... other partial views. Consider something like this...
<body> Page
-- <div> Partial View "parent" (does a RenderPartial of these:)
---- <div> Partial View "child" (piece 1) </div>
---- <div> Partial View "child" (piece 2) </div>
The parent partial view simply contains RenderPartials for the children. In addition, each patial view can end up having it's own URL (/controller/parent/, /controller/child-1/, etc.). In jQuery whenever you trap an event that needs to update the UI, you can simply ajax.load the piece you need and plug it into the div.
JSON -> jQuery Render
The other way is you forgo the server creating any presentation code, and you simply have an API that returns JSON. jQuery then accepts the incoming data objects and figures out what to do with them. Depending on the complexity of what needs to be rendered on the client side, this could be easier. This has the advantage of also allowing the same server-side code to be re-used in other ways. The downside is the content won't be indexed by search engines.