<%foreach (var indication in Model.FindAll(m => m.Model != null && m.Model.Trx != null).OrderBy(m => m.Model.Trx.PrimarySponsor.Company))
{ %>
<tr>
<td><%= indication.DisplayUser %></td>
<td><%= indication.ActiveIndicationUsers[0].FullName %></td>
<td><%= string.IsNullOrEmpty(indication.Model.Trx.PrimarySponsor.Company) ? "Not Yet Saved" : indication.Model.Trx.PrimarySponsor.Company %></td>
<td><%= indication.TimeOpened.ToString(Chatham.Web.Data.Constants.Format.DateTimeSecondsFormatString) %></td>
<td><%= indication.Model.Trx.ProductCollection[0].ProductTypeFriendlyName %></td>
<td><%= (!indication.Model.Trx.ID.HasValue) ? "Not Yet Saved" : indication.Model.Trx.ID.Value.ToString() %></td>
<td><input type="button" value="Open" name="<%= (!indication.Model.Trx.ID.HasValue) ? "Not Yet Saved" : indication.Model.Trx.ID.Value.ToString() %>" /></td>
</tr>
<%} %>
So that above table, as you can see, is dynamically generated. How do I handle the button click? I also want to pass the name attribute of the button into whatever method handles the button click.
Thanks!
You can use the live function of jQuery.
Try this:
$(function(){
$("td input[type=button][value=Open]").live("click", function(e){
var btn = $(this);
alert(btn.attr("name"));
});
})
The same way you would handle a regular button click. Dynamically create the code to handle regular button clicks in the http code you're generating.
That code is tragic and screaming for refactoring. Just looking at it my eyes hurt. You are not encoding strings thus making this code vulnerable to XSS attacks.
So as always in ASP.NET MVC you start with a view model:
public class MyViewModel
{
public string DisplayUser { get; set; }
public string ActiveIndicationsUserFullname { get; set; }
public string Company { get; set; }
[DisplayFormat(DataFormatString = "{0:dd-MM-yyyy}")]
public DateTime TimeOpened { get; set; }
public string TrxId { get; set; }
}
then you will have a controller action which will fetch the model from the repository and map it to the view model. You could use AutoMapper to simplify this mapping. It's in the mapping layer that you will transform everything to be ready to be directly used by the view so that this views doesn't resemble to a horrible tag soup:
public ActionResult Foo()
{
// it's here that you should do the LINQ queries, etc ...
// not in the view. Views are not supposed to fetch any data
// and to be intelligent. Views should be dumb and only render
// the preformatted data that they have been fed by the controller action
IEnumerable<SomeModel> model = ...
IEnumerable<MyViewModel> viewModel = Mapper.Map<IEnumerable<SomeModel>, IEnumerable<MyViewModel>>(model);
return View(viewModel);
}
next we get to the strongly typed view where we will be using Display Templates:
<table id="myTable">
<thead>
<tr>
<th>DisplayUser</th>
<th>ActiveIndicationsUserFullname</th>
<th>Company</th>
<th>TimeOpened</th>
<th>TrxId</th>
</tr>
</thead>
<tbody>
<%= Html.DisplayForModel()
</tbody>
</table>
and in the corresponding display template (~/Views/Shared/DisplayTemplates/MyViewModel.ascx):
<%# Control
Language="C#"
Inherits="System.Web.Mvc.ViewUserControl<AppName.Models.MyViewModel>" %>
<tr>
<td><%= Html.DisplayFor(x => x.DisplayUser) %></td>
<td><%= Html.DisplayFor(x => x.ActiveIndicationsUserFullname) %></td>
<td><%= Html.DisplayFor(x => x.Company) %></td>
<td><%= Html.DisplayFor(x => x.TimeOpened) %></td>
<td><%= Html.DisplayFor(x => x.TrxId) %></td>
<td>
<input type="button" value="Open" name="<%= Model.TrxId %>" />
</td>
</tr>
and finally you could use jquery to attach to the click of this button and fetch the name:
$(function() {
$('#myTable button').click(function() {
var btn = $(this);
alert(btn.attr('name'));
});
});
Related
I am trying to validate specific divs I have looked all over google and I can't find any examples for the way I am doing my validation. I have 2 divs I want to be able to click a button and validate the first div and then I want that div to hide and validate the second div. I have wrote some jquery code that hides the first div but I only want to do this to happen once that specific div is validated.
MARKUP
<div id="contentone">
<table>
<tr>
<td>game console</td>
<td><%=Html.TextBox("console", ViewData["console"] ?? "") %></td>
</tr>
<tr>
<td>manafacturer</td>
<td><%=Html.TextBox("manaf", ViewData["manaf"] ?? "") %></td>
</tr>
</table>
</div>
<div id="contenttwo">
<table>
<tr>
<td>description</td>
<td><%=Html.TextBox("desc", ViewData["desc"] ?? "") %></td>
</tr>
<tr>
<td>Available games</td>
<td><%=Html.TextBox("games", ViewData["games"] ?? "") %></td>
</tr>
</table>
</div>
<button id="hide" type="button">Test1</button>
<script>
$(document).ready(function(){
$("#hide").click(function(){
$("#contentone").hide();
});
});
</script>
CONTROLLER
[AcceptVerbs("POST")]
public ActionResult ConsoleQues(string console, string manaf, string desc, string games)
{
ViewData["console"] = console;
ViewData["manaf"] = manaf;
ViewData["desc"] = desc;
ViewData["games"] = games;
if (string.IsNullOrEmpty(console))
ModelState.AddModelError("console", "Please enter console name ");
if (string.IsNullOrEmpty(manaf))
ModelState.AddModelError("manaf", "please enter manafactuer name");
if (string.IsNullOrEmpty(desc))
ModelState.AddModelError("desc", "Please enter description name ");
if (string.IsNullOrEmpty(games))
ModelState.AddModelError("games", "please enter game name");
Create function for validating both divs:
function IsValid(divid) {
var $div = $('#' + divid);
var result = true;
$.each($div.find("input[type='text']"), function (i, input) {
if ($(input).val().length == 0 || $.trim($(input).val()) == '') {
result = false;
return;
}
});
return result;
}
Check validity and hide contentone div
if (IsValid('contentone')) {
$('#contentone').hide();
}
Can someone help me databind? I'm new to .net and c# and am following tutorials that are only getting me half way there. The aspx is the following:
<asp:Repeater ID="rptContent" runat="server">
<HeaderTemplate>
<table>
<thead>
<tr>
<th>T</th>
<th>L</th>
<th>S</th>
</tr>
</thead>
<tbody>
</HeaderTemplate>
<ItemTemplate>
<tr>
<td><%# Eval("T") %></td>
<td><%# Eval("L")%></td>
<td><%# Eval("S")%></td>
</tr>
</ItemTemplate>
<FooterTemplate>
</tbody>
</table>
</FooterTemplate>
</asp:Repeater>
But on the back end I don't know how to actually bind the data. If there is a tutorial someone can send me to follow for this part I'd appreciate it or if you can explain that would be great.
public List<Sample> Results()
{
List<Sample> List = new List<Sample>();
myList.Add(new Sample { Title = "Title
1", Link = "/item.aspx?id=1", Summary = "summary
for Item 1" });
return List;
}
public class Content
{
public string T
{
get;
set;
}
public string L
{
get;
set;
}
public string S
{
get;
set;
}
}
Can you bind directly the list of Sample? or you do need to bind it to the class Content?
The important here is: in the markup, when you use Eval(""), you have to provide the exact name of the property of the object you are binding.
If you can use the list of Sample I would do the following
ASPX:
<asp:Repeater ID="rptContent" runat="server">
<HeaderTemplate>
<table>
<thead>
<tr>
<th>T</th>
<th>L</th>
<th>S</th>
</tr>
</thead>
<tbody>
</HeaderTemplate>
<ItemTemplate>
<tr>
<td><%# Eval("Title") %></td>
<td><%# Eval("Link")%></td>
<td><%# Eval("Summary")%></td>
</tr>
</ItemTemplate>
<FooterTemplate>
</tbody>
</table>
</FooterTemplate>
</asp:Repeater>
and in Code-Behind:
protected void Page_Load(object sender, EventArgs e)
{
rptContent.DataSource = Results();
rptContent.DataBind();
}
public List<Sample> Results()
{
List<Sample> List = new List<Sample>();
myList.Add(new Sample { Title = "Title
1", Link = "/item.aspx?id=1", Summary = "summary
for Item 1" });
return List;
}
The collection you assign to the data source of your repeater needs to be a collection of items containing the properties you're intending to bind to.
The individual items in your Results collection do not directly possess L, T, & S properties so in binding this collection to your repeater, the repeater cannot find those properties. In your case, you'll need to bind to a collection of Content objects:
List<Content> contentResults = new List<Content>();
contentResults.Add(new Content(){L="el", T="tee", S="es"});
rptContent.DataSource = contentResults;
rptContent.DataBind();
I am creating a model which is intended to hold a table. The table will hold an arbitrary number of rows defined at run-time. I am wondering if there's an easy way to define this in MVC?
Currently all I have is:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<CableSolve.Web.Models.Orders.ActivityDetailsModel>" %>
<div id="ActivityDisplay">
<table id="ActivitiesGrid">
</table>
<div id="ActivitiesGridPager"></div>
</div>
In a different model, I create a table which had a static number of rows. This was pretty easy:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<CableSolve.Web.Models.Orders.OrderDetailsModel>" %>
<fieldset class="collapsible">
<legend>
<%= Html.DisplayFor(model => model.OrderDetailsLegendName)%>
</legend>
<table id="OrderDetailsContentTable" class="ContentTable">
<tr>
<td><%= Html.DisplayFor(model => model.OrderID.Name)%></td>
<td><%= Html.DisplayFor(model => model.OrderID.Value)%></td>
<td><%= Html.DisplayFor(model => model.Comment.Name)%></td>
<td><%= Html.DisplayFor(model => model.Comment.Value)%></td>
</tr>
...
So, any ideas on how I could go about having an arbitrary number of rows in ActivitiesGrid?
Basically, my controller is going to get some information at run-time and I want to display the retrieved information in a table, but I do not know how many rows of information I am going to receive.
As a light-weight solution without introducing third-party stuff (for now, if it proves necessary I will):
public class ActivityDetailsModel
{
public List<ActivityRow> ActivityRows = new List<ActivityRow>();
public struct ActivityRow
{
public DateTime? Date;
public string Person;
public string OrderOrTaskID;
public string Activity;
public ActivityRow(DateTime? date, string person, string orderOrTaskID, string activity)
{
Date = date;
Person = person;
OrderOrTaskID = orderOrTaskID;
Activity = activity;
}
}
public ActivityDetailsModel(IEnumerable<Activity> activities)
{
foreach(Activity activity in activities)
{
string orderOrTaskID = activity.TaskID != 0
? activity.OrderID + "-" + activity.TaskID
: activity.OrderID.ToString();
string activityDescription = string.Format("OldValue: {0}, NewValue: {1}", activity.OldValue,
activity.NewValue);
ActivityRows.Add(new ActivityRow(activity.UpdateDateTime, activity.UpdateUsername, orderOrTaskID, activityDescription));
}
}
}
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<CableSolve.Web.Models.Orders.ActivityDetailsModel>" %>
<div id="ActivityDisplay">
<table id="ActivitiesGrid">
<%foreach (var activityRow in Model.ActivityRows)
{%>
<tr>
<td><%= Html.DisplayForModel(activityRow.Date)%></td>
<td><%= Html.DisplayForModel(activityRow.Person)%></td>
<td><%= Html.DisplayForModel(activityRow.OrderOrTaskID)%></td>
<td><%= Html.DisplayForModel(activityRow.Activity)%></td>
</tr>
<%}%>
</table>
<div id="ActivitiesGridPager"></div>
</div>
Is this relatively understandable? I hate the mark-up with all the angle-brackets and percent signs, but the project hasn't been developer with the alternative syntax.
Since you're after something dynamic, you can take advantage of existing helpers like MVC WebGrid helper or even MvcContrib Grid. These helpers will take care of generating a table containing the columns you want. There's no need to write the table by hand since it'll be dynamically generated during runtime according to the number of objects present in your datasource.
On the aspx:
<table>
<tr>
<asp:Repeater ID="rptHeader" runat="server">
<ItemTemplate>
<th><%#Eval("Category")%></th>
</ItemTemplate>
</asp:Repeater>
</tr>
<tr>
<asp:Repeater ID="rptContents" runat="server">
<ItemTemplate>
<td valign="top">
<%#Eval("Content")%>
</td>
</ItemTemplate>
</asp:Repeater>
</tr>
</table>
On the code-behind:
protected void Page_Load(object sender, EventArgs e)
{
rptHeader.DataSource = DataSource;
rptHeader.DataBind();
rptContentBlocks.DataSource = DataSource;
rptContentBlocks.DataBind();
}
The problem here is that instead of using Two repeaters, can we use only one?
We actually need the header to be separated from the contents using a different table row...
Edit: changed rptHeader's ItemTemplate's html element from <td> to <th> to be a little clearer. :-)
IMO it's impossible without repeater hacking. Anyway, there is a rather irregular approach that maybe works. Also you can use two foreach statements instead of repeaters.
Code
protected string[] headers = { "A", "B", "C", "D" };
protected string[] contents = { "Alpha", "Beta", "Counter", "Door" };
//string[] headers = { "A", "B", "C", "D" };
//string[] contents = { "Alpha", "Beta", "Counter", "Door" };
//DataList1.RepeatColumns = headers.Length;
//DataList1.DataSource = headers.Concat(contents);
//DataList1.DataBind();
Html markup
<table>
<tr>
<%foreach (string item in headers)
{ %>
<th><%= item %></th>
<% } %>
</tr>
<tr>
<%foreach (string item in contents)
{ %>
<td><%= item %></td>
<% } %>
</tr>
</table>
<!--
<asp:DataList ID="DataList1" runat="server" RepeatDirection="Horizontal">
<ItemTemplate>
<%# Container.DataItem %>
</ItemTemplate>
</asp:DataList>
-->
An HTML table is always declared as cells nested within rows, i.e.
<table>
<tr>
<td>
...
</td>
</tr>
</table>
rather than
<table>
<td>
<tr>
...
</tr>
</td>
</table>
This means you won't be able to write a single Category followed by a single Content. You will have to repeate the Category values and then the Content values as you are already doing.
I see nothing wrong with the approach you are using. The use of 2 repeaters rather than one should be a negligible overhead.
The alternative would be to nest a table within each column. This would allow you to use just a single repeater but the resulting HTML would be rather contrived and bloated. I would not recommend this approach but somehow I can't stop myself from providing an example.
<table>
<tr>
<asp:Repeater ID="rptHeader" runat="server">
<ItemTemplate>
<td>
<table>
<tr>
<td valign="top">
<strong><%#Eval("Category")%></strong>
</td>
</tr>
<tr>
<td valign="top">
<%#Eval("Content")%>
</td>
</tr>
</table>
</td>
</ItemTemplate>
</asp:Repeater>
</tr>
</table>
If it's important to place the content in a table, then you could "rotate" your table into a different structure and bind on that structure. Or if it's not important that the data is in a table, you could place the items in divs and float them so they're side-by-side.
Edit:
Here's what I mean by rotating the data. If your data is currently in a structure like List<MyDataClass>, where MyDataClass is defined as something like:
class MyDataClass
{
public string Category { get; set; }
public string Content { get; set; }
public int OtherField { get; set; }
}
...then the logical layout when iterating through the structure would look like this:
MyDataClass[0]: Category, Content, OtherField
MyDataClass[1]: Category, Content, OtherField
...
When rotating the data, you'd turn those rows into columns and columns into rows. For example, you could populate a List<List<string>> with code such as this:
var rotated = new List<List<string>> {
new List<string>(), new List<string>(), new List<string>(),
};
for each (MyDataClass object in myCollection)
{
rotated[0].Add(object.Category);
rotated[1].Add(object.Content);
rotated[2].Add(object.OtherField.ToString("n0"));
}
Now your data structure looks like this:
rotated[0]: MyDataClass[0].Category, MyDataClass[1].Category, ...
rotated[1]: MyDataClass[0].Content, MyDataClass[1].Content, ...
rotated[2]: MyDataClass[0].OtherField, MyDataClass[1].OtherField, ...
Basically, you transform the data into a form that can be dropped right into your table.
Edit 2:
I actually have to do these sorts of rotations for reports often enough that I made an extension method for IEnumerable that will do the rotation in a somewhat more elegant manner. Here's the extension method:
public static class MyCollectionExtensionMethods
{
public static IEnumerable<IEnumerable<TResult>> Rotate<TOrig, TResult>(
this IEnumerable<TOrig> collection,
params Func<TOrig, TResult>[] valueSelectors)
{
return valueSelectors.Select(s => collection.Select(i => s(i)));
}
}
And here's how I'd use it:
IEnumerable<IEnumerable<string>> rotated = data.Rotate(
i => i.Category, i => i.Content, i => i.OtherField.ToString("n0"))
Correct me if i misunderstood but it sounds to me like you could use only one repeater, integrating your first repeater into a HeaderTeplate tag and the second into the ItemTemplate.
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.