Html Helper in partial view, only adding my script once - c#

I have a view that is rendering multiple partial view inside as follow :
<div>
<table class="EditTable">
#foreach (var view in Model.ViewsToRender)
{
<tr>
<td style="width: 100%;">
#Html.Partial("~/Areas/TC2/Views/Shared/" + view.Name + ".cshtml", view.viewModel)
</td>
</tr>
}
</table>
</div>
Each view is doing almost the same rendering : content and adding a js script to show/hide the block :
#{
var classShow = "show_hide" + Model.Name;
#Html.AddShowScriptConsult(classShow);
}
<div id="viewContent">
<div class="viewTitle">#Model.Name</div>
<i class="#classShow fa fa-minus-circle buttonExtended"></i>
<div>My html content ....</div>
</div>
It is working fine, except that my helper is only called once for the first view, and the other partial view didnt add the script to show/hide the unit. It seems like this line : "#Html.AddShowScriptConsult(classShow);" is only called once for all the partial view, I expected it to be called once for each view, since the call is inside each partial view within "Model.ViewsToRender".
If you need further informations or clarifications don't be afraid to ask, I simplified my code due to company policy but this example represent perfectly my problem.

Related

Blazor child component templated/render fragment issue

I have an oddity with Blazor's templated components that I'm looking for guidance on.
I have two components, one called DataTable and one called DataModal. Both take generic TItem as a type parameter to render a table of items using render fragments for the mark-up.
DataTable renders the table HTML and DataModal is a bootstrap modal wrapper that contains a DataTable component as a child component. The idea is to show a modal dialog with a data table for user selection.
When the DataTable component is used on it's own as part of a page component, it works fine. When the DataModal component is used, passing the same item collection (as TItem) and same render fragment markup I don't get the correct content in the DataTable. Instead I get the fragment and TItem assembly name for the same number of items.
This is the markup for the Data table component embedded on a page:
<DataTable TItem="TicketSummaryModel" PageNumberChanged="OnPageChanged" Class="table table-hover table-striped dataTable responsive no-footer" RowClicked="#OnRowClicked" Items="SearchedTickets.Data"
TotalRecords="#SearchedTickets.RecordsTotal" TotalPages="SearchedTickets.PagesTotal">
<DataTableHeader>
<th>Ticket Number</th>
<th>Updated On</th>
<th>Title</th>
<th>Created By</th>
<th>Category</th>
<th>Status</th>
</DataTableHeader>
<DataRowTemplate>
<td><i class="fas fa-circle mr-1 #context.PriorityClass"></i> #context.TicketNumber</td>
<td>#context.UpdatedOn</td>
<td>#context.Title</td>
<td>#context.CreatedByUser</td>
<td>#context.Category</td>
<td><i class="fas fa-square mr-1 #context.StatusClass"></i> #context.Status</td>
</DataRowTemplate>
This outputs correctly, each property in the render fragment is correctly shown as a element inside the table.
When I do the same with the DataModal component inside a page the problem occurs:
<DataModal #ref="modalRef" TitleClass="bg-primary" ModalSize="ModalSize.ExtraLarge" Title="Test Modal" Items="#SearchedTickets.Data"
TitleIcon="fa-check" TItem="TicketSummaryModel" TableClass="table table-hover table-striped dataTable responsive no-footer"
TotalRecords="#SearchedTickets.RecordsTotal" TotalPages="SearchedTickets.PagesTotal">
<DataTableHeader>
<th>Ticket Number</th>
<th>Updated On</th>
<th>Title</th>
<th>Created By</th>
<th>Category</th>
<th>Status</th>
</DataTableHeader>
<DataRowTemplate>
<td><i class="fas fa-circle mr-1 #context.PriorityClass"></i> #context.TicketNumber</td>
<td>#context.UpdatedOn</td>
<td>#context.Title</td>
<td>#context.CreatedByUser</td>
<td>#context.Category</td>
<td><i class="fas fa-square mr-1 #context.StatusClass"></i> #context.Status</td>
</DataRowTemplate>
</DataModal>
The DataModal component markup is as follows:
#inherits DataModalBase<TItem>
#typeparam TItem
<Modal #ref="#ModalRef">
<ModalContent Size="#ModalSize" IsCentered="true">
<ModalHeader Class="#TitleClass">
<ModalTitle>
#if (Title != null)
{
#if (TitleIcon != null)
{
<i class="#("fal " + TitleIcon) mr-2"></i>
}
#Title
}
</ModalTitle>
<CloseButton Clicked="Close" />
</ModalHeader>
<ModalBody>
#if (Items != null)
{
<DataTable TItem="TItem" Class="#TableClass" Items="#Items">
<DataTableHeader>
#DataTableHeader
</DataTableHeader>
<DataRowTemplate>
#DataRowTemplate
</DataRowTemplate>
</DataTable>
}
else
{
<div class="mr-auto ml-auto mt-4 mb-4">
<div class="lds-hourglass"></div>
</div>
}
</ModalBody>
</ModalContent>
</Modal>
The modal shows a table, the headers are correct from the DataTableHeader render fragment and the number of rows for the items data is correct. The problem is the output of the DataRowTemplate render fragment is now just the assembly names:
Microsoft.AspNetCore.Components.RenderFragment`1[MyProject.Models.Tickets.TicketSummaryModel]
Microsoft.AspNetCore.Components.RenderFragment`1[MyProject.Models.Tickets.TicketSummaryModel]
Microsoft.AspNetCore.Components.RenderFragment`1[MyProject.Models.Tickets.TicketSummaryModel]
Microsoft.AspNetCore.Components.RenderFragment`1[MyProject.Models.Tickets.TicketSummaryModel]
...
Any idea why this is happening? Both the DataModal and the DataTable use the exact same declarations for the collection of items to show:
[Parameter] public IEnumerable<TItem> Items { get; set; } // The data items
[Parameter] public RenderFragment<TItem> DataRowTemplate { get; set; } // The HTML markup for each row
The DataTable renders the DataRowTemplate using the following code which again works when the DataTable is used outside of a parent but not within as a child (inside DataModal):
<tbody>
#if (Items != null)
{
#foreach (var item in Items)
{
<tr #onclick="#(() => OnRowClicked(item))">#DataRowTemplate(item)</tr>
}
}
</tbody>
If you need more information to assist in this issue let me know.

Asp.net MVC Razor #foreach + onclick the data gets listet

I'm working on a Project Tool that lists all the Projects on the Dashboard. Now I want that when I click on the Project that the Data from my Database gets listed on the right site of it.
Problem 1
Code:
#foreach (var item in Model)
{
<tbody>
<tr>
<td>Project Titel</td>
<td>#item.PrjTitel</td>
</tr>
</tbody>
}
With this all the Database Data gets listet, but i just want the Data from one Project not from Project 1,2,3 listet.
How can i make that ?
Problem 2
How can i make that the Data gets listet when the User clicks on a Project.
So if i click on Project 2 the data from Project to gets listet on the right site. See Screenshot -->
Screenshot of the front page
#foreach (var item in Model.Projects) {
<tbody>
<tr>
<td>#Ajax.ActionLink("Select","SelectProjects",new { #id=item.ProjectId},new AjaxOptions { HttpMethod="GET",OnSuccess="LoadProjectsSuccess", OnFailure="LoadProjectsFailur",InsertionMode=InsertionMode.Replace,UpdateTargetId= "Projects" },new { #class="btn btn-info btn-table"})</td>
</tr>
</tbody>}
<div class="row row-equal" id="Privileges"><div>
you can use AjaxHelper if you don't have any information about ajax helper please visit Ajax Helper
public ActionResult SelectProjects(int id)
{
DemoViewModel model = new DemoViewModel()
{
// Your ViewModel
};
return PartialView("_ProjectDetails", model);
}
_ProjectDetails Partial View with data you wont to update

Find the control of dynamically added partial view span content in JQuery

We have partial view View1 as follows:
#using (Html.BeginCollectionItem)
{
<div id = "partialview-content>
<table >
<tr>
<td>
#Html.TextBoxFor(x=>x.Name, new {id = "name", #class = "name-class"})
// Additional controls
</td>
</tr>
<tr class="rowSpace">
<td>Label Text</td>
<td>
<span id="business-key-id">
#Html.DisplayFor(x=>x.BusinessKey)
</span>
</td>
</tr>
</table>
}
</div>
When user clicks on Add New Item in Main View, partial view will be added dynamically.
When user enters some text in name textbox in the dynamically added partial view, BusinessKey DisplayFor should be updated dynamically.
So I added below code in the JQuery:
$(document).ready(function () {
$(".name-class").live('keyup', function (event) {
var name1 = $("#name1").val();
var name2 = $("#name2").val();
var name = $(this).val();
(".business-key-id").html(trustName + ' ' + seriesName + ' ' + trancheName);
});
});
Doing this code is updating the business-key-id of all the dynamically added partial views. How can I get the control of the business-key specific to the keydown event control?
This line is selecting all elements with the class name business-key-id
$(".business-key-id").html(...
Change the selector to select only the next element
$(".name-class").on(...
$(this).next('.business-key-id').html(...
Note .live has been depreciated - you should use .on
Edit
Based on OP's revised html, the selector to choose the coresponding business-key-id should be
$(this).closest('table').find('.business-key-id).html(...
And change the html to use the class attribute, not id attribute (duplicate ID's are invalid html)
<span class="business-key-id">
#Html.DisplayFor(x=>x.BusinessKey)
</span>

How do I pass data from child view to parent view in MVC2?

Using .Net MVC2, I would like to pass information from a child view to its parent view. Initially, I thought I could use the ViewData collection, but this seems to only work in one direction: from the parent to the child.
Below is a simplified version of what I am attempting in an effort to pass data from the child view back to the parent view. When running the Visual Studio debugger, I see the ViewData dictionary while stepping through both the parent and child views. But the statement which should add an item to the dictionary in the child view does not seem to work. After returning to the parent view, the ViewData dictionary appears the same as before calling the child.
In the parent view:
<div>
<%
List<People> ManagerList = ViewData["ManagerList"];
ViewData["Section"] = "Managers";
Html.RenderPartial("OrgTable", ManagerList);
bool didTableRenderAnyRecords = ViewData["TableResult"];
%>
</div>
...
<div>
<%
if (!didTableRenderAnyRecords) {
%>
<p>Sorry, no records found</p>
<%
}
%>
</div>
In the child view
<table>
<thead> ... </thead>
<tbody>
<%
bool validRecordDisplayed = false;
foreach(var manager in Model) {
if (manager != null) {
validRecordDisplayed = true;
%>
<tr> ... </tr>
<%
}
}
ViewData["TableResult"] = validRecordDisplayed;
%>
</tbody>
</table>
I think you can use ViewBag.SomeProperty here. You can also try and use MVC sections (although I am not sure if those are available in MVC2).

ASP.NET MVC Ajax (jQuery): generate code server-side?

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.

Categories