I have the following block(s) of code that is copy and pasted about 5 different times within a razor view. It basically displays a table for the same model just with different data.
How can I re-write it as an html helper or lambda func so that I can reuse it for n different models that are passed into the view?
// Example for Model.A and Model.B
var cCols = new[] { "val1", "val2"};
// Display the data for A
<div class="group-property">
<div class="group-label">Title A</div>
<table class="collection-table">
<thead>
<tr class="collection-head">#foreach (var col in cCols) {<th scope="col">#col</th>}</tr>
</thead>
<tbody>
#foreach (var item in Model.A)
{
<td>#item.val1</td>
<td>#item.val2</td>
}
</tbody>
</table>
</div>
// Display the data for B
<div class="group-property">
<div class="group-label">Title B</div>
<table class="collection-table">
<thead>
<tr class="collection-head">#foreach (var col in cCols) {<th scope="col">#col</th>}</tr>
</thead>
<tbody>
#foreach (var item in Model.B)
{
<td>#item.val1</td>
<td>#item.val2</td>
}
</tbody>
</table>
</div>
I don't know if I get it right, but why not use #Html.Partial ?
Andrei Neagu
I'm not sure what you've tried, but to make it an helper function you just need to take the pieces that vary and make them parameters to the function:
#helper MyHelperFunction(string title, IEnumerable<ItemClass> items)
{
var cCols = new[] { "val1", "val2"};
<div class="group-property">
<div class="group-label">#title</div>
<table class="collection-table">
<thead>
<tr class="collection-head">#foreach (var col in cCols) {<th scope="col">#col</th>}</tr>
</thead>
<tbody>
#foreach (var item in items)
{
<td>#item.val1</td>
<td>#item.val2</td>
}
</tbody>
</table>
</div>
}
#MyHelperFunction("Title A", Model.A)
#MyHelperFunction("Title B", Model.B)
Related
I am new to ASP.NET Core development. I am looking for something like a built-in way to use loop iteration numbers inside the view of ASP.NET Core.
I did some research and found solutions like creating int variable outside the loop and then increment inside the loop.
I want to index each user.
Here is my code:
#foreach (var item in l_IEnumerableModUserQuery)
{
<tr>
<td>
<!-- Here I want to add Iteration No. here-->
</td>
<td>
<a href="#">
#item.Pr_FullName
</a>
</td>
<td>#item.Pr_Email</td>
<td>#item.Pr_ContactNo</td>
</tr>
}
You could use a simple for loop to get the index:
//use .Count if it is a List or .Count() with Linq to get the boundary.
#for(var i = 0; i < l_IEnumerableModUserQuery.Count; i++)
{
<tr>
<td>
#i.ToString();
</td>
<td>
<a href="#">
#l_IEnumerableModUserQuery[i].Pr_FullName
</a>
</td>
<td>#l_IEnumerableModUserQuery[i].Pr_Email</td>
<td>#l_IEnumerableModUserQuery[i].Pr_ContactNo</td>
</tr>
}
Thomas Levesque has a neat approach on his blog, using an extension method:
public static IEnumerable<(T item, int index)> WithIndex<T>(this IEnumerable<T> source)
{
return source.Select((item, index) => (item, index));
}
Which would result in:
#foreach (var (item, idx) in l_IEnumerableModUserQuery.WithIndex())
{
<tr>
<td>
#idx
</td>
<td>
<a href="#">
#item.Pr_FullName
</a>
</td>
<td>#item.Pr_Email</td>
<td>#item.Pr_ContactNo</td>
</tr>
}
With an eye on the extension methods approach, you could as well amend your views model and include the index as a property in your model inside your controller / handler or whereever your model is created:
var l_IEnumerableModUserQuery =
someSource.Where(x => ...)
.Select((x, index) => new MyModel {
Index = index,
Pr_Email = xxx,
Pr_Contact = xxy,
/* ... rest of model */
});
return l_IEnumerableModUserQuery;
After this you could access the index like any other property in your view:
<a href="#">
#item.Index
</a>
you can findout the index of the item
#{
int indx=0;}
#foreach (var item in l_IEnumerableModUserQuery)
{
<tr>
<td>
#l_IEnumerableModUserQuery.IndexOf(item)
</td>
<td>
<a href="#">
#item.Pr_FullName
</a>
</td>
<td>#item.Pr_Email</td>
<td>#item.Pr_ContactNo</td>
</tr>
}
I have a table with some column in a asp.net mvc core project.
My view file looks like this
<h1>Items</h1>
<div class="panel-body">
<table class="table table-bordered table-responsive table-hover">
<thead>
<tr>
<th>Id</th>
<th>Title</th>
<th>Rating</th>
<th></th>
</tr>
</thead>
<tbody>
#foreach (var item in Model.Items)
{
<tr onclick="location.href='#(Url.Action("ShowItemDetails", "Item", new {Id = item.FilmId}))'">
<td>#item.Id</td>
<td>#item.Title</td>
<td>#item.Rating</td>
<td>#Html.ActionLink("Edit", "Edit", "Show", new { id = item.Id }) | #Html.ActionLink("Rate this", "RateItem", new { id = item.Id }) </td>
</tr>
}
</tbody>
</table>
</div>
The problem is that when i click on a row, the controller method ShowItemDetails is called twice(!).
I can not see from the code above why this happens. Also, clicking on Edit or Rate this calls first ShowItemDetails and then immediately Edit or RateItem method in controller. Any suggestion how this can be solved?
Clicking on Edit or Rate this calls first ShowItemDetails and then immediately Edit or RateItem method because Edit is under a table row and on tablerow, you have called showitemdetails action.so, when you click on td , it gets first executed row action then td action.that's why it get called twice.
I hope, you want to show details and edit options with data of table and Edit is controller name.
Tweak your table code like below:
<tbody>
#foreach (var item in Model.Items)
{
<tr>
<td>#Html.ActionLink("Show Details","ShowItemDetails","Item",new {Id = item.FilmId})</td>
<td>#item.Id</td>
<td>#item.Title</td>
<td>#item.Rating</td>
<td>#Html.ActionLink("Edit", "Edit", "Show", new { id = item.Id }) | #Html.ActionLink("Rate this", "RateItem", new { id = item.Id }) </td>
</tr>
}
</tbody>
The problem seems to be caused be something i thought was irrelevant
having a null image cause the method to be called twice. Setting it to
solves this.
Need to add code to check for Model.Image != null
Very strange!!
I have a DataTable in OrderDetails.aspx.vb
Public Outlets As New DataTable
Outlets = objOrdersData.GetOnlineConfigCall()
In my OrderDetails.aspx
<script>
var Outlets = '<%=Outlets%>';
</script>
I want to display outlets details in a html table using AngularJS
I defined my html table as
<table class="table">
<thead>
<tr> <th>Outlets</th>
</tr>
</thead>
<tbody>
<tr data-ng-repeat="outlet in Outlets">
<td><a >{{outlet.PartnerName}}</a></td>
</tr>
</tbody>
</table>
but it's not working.
Provided that Outlets is a valid js array, you just need to assign it to scope variable in your controller like:
OrderApp.controller("OrderCntrl", ['$scope', function ($scope) {
$scope.outlets = Outlets;
}]);
and then bind your data in the template like:
<tr ng-repeat="outlet in outlets">
<td><a >{{outlet.PartnerName}}</a></td>
</tr>
I have created a form that has multiple sections that are hidden. A tab strip hides/shows the sections to create a page with a smaller footprint. While this makes the page a lot cleaner, it makes it hard to show errors to the user after validation. I want to make an indicator in the tabs that shows that the content in the specified tab has errors.
Main View:
<div>
<ul class="contentTabs">
<li onclick="switchTab(this)" class="selected">Contact</li>
<li onclick="switchTab(this)">Information</li>
<li onclick="switchTab(this)">Software</li>
<li onclick="switchTab(this)">Hardware</li>
<li onclick="switchTab(this)">Classification</li>
<li onclick="switchTab(this)" class="last">Solution</li>
</ul>
<div class="content">
<div id="contact" class="contentPane">
#Html.Partial("_Contact")
</div>
<div id="information" class="contentPane" style="display: none;">
#Html.Partial("_Information")
#Html.Partial("_Notes")
</div>
<div id="notes" class="contentPane" style="display: none;">
#Html.Partial("_Notes")
</div>
<div id="software" class="contentPane" style="display: none;">
#Html.Partial("_Software")
</div>
<div id="hardware" class="contentPane" style="display: none;">
#Html.Partial("_Hardware")
</div>
<div id="classification" class="contentPane" style="display: none;">
#Html.Partial("_Classification")
</div>
<div id="solution" class="contentPane" style="display: none;">
#Html.Partial("_Solution")
</div>
</div>
</div>
Partial View (Contact):
#code
Dim notifyTypes As ListItemCollection = DirectCast(ViewData("NotifyTypes"), ListItemCollection)
Dim callerTypes As ListItemCollection = DirectCast(ViewData("CallerTypes"), ListItemCollection)
Dim reportingTypes As ListItemCollection = DirectCast(ViewData("ReportingTypes"), ListItemCollection)
Dim myIncident As Library.BusinessLayer.Incident = DirectCast(Model, Library.BusinessLayer.Incident)
End Code
<table class="tableBorderless" style="width: 99%; margin: 0px auto">
<tr>
<td class="right">User Location</td>
<td class="left">
#Html.DropDownList("LocationId", DirectCast(ViewData("Locations"), SelectList), New With {.style = "width: 200px"})<br />
#Html.ValidationMessage("LocationId", New With {.class = "red"})
</td>
<td class="right">Notify</td>
<td class="left">
#For Each notificationType As ListItem In notifyTypes
#<input type="radio" name="Notify" value="#notificationType.Value" #IIf(notificationType.Selected, "checked", "") />#notificationType.Text
Next
</td>
</tr>
<tr>
<td class="right">Caller Type</td>
<td colspan="3" class="left">
#For Each callerType As ListItem In callerTypes
#<input type="radio" name="CallerType" value="#callerType.Value" #IIf(callerType.Selected, "checked", "") />#callerType.Text
Next
</td>
</tr>
<tr>
<td class="right">User Network ID</td>
<td class="left">
#Html.TextBox("UserId", myIncident.UserId, New With {.onchange = "UserId_onchange(this)", .maxlength = "30"})
</td>
<td class="right">User Name</td>
<td class="left">
#Html.TextBox("UserName", myIncident.UserName, New With {.maxlength = "50"})<br />
#Html.ValidationMessage("UserName", New With{.class = "red"})
</td>
</tr>
<tr>
<td class="right">User Email</td>
<td class="left">
#Html.TextBox("UserEmail", myIncident.UserEmail, New With {.maxlength = "50"})<br />
#Html.ValidationMessage("UserEmail", New With{.class = "red"})
</td>
<td class="right">User Phone</td>
<td class="left">
#Html.TextBox("UserPhone", myIncident.UserPhone, New With {.maxlength = "50"})
</td>
</tr>
<tr>
<td class="right">Reporting Type</td>
<td colspan="3" class="left">
#For Each reportingType As ListItem In ReportingTypes
#<input type="radio" name="ReportedByType" value="#reportingType.Value" #IIf(reportingType.Selected, "checked", "") />#reportingType.Text
Next
</td>
</tr>
<tr>
<td class="right">Reported by (Network ID)</td>
<td class="left">
#Html.TextBox("ReportedByUserId", myIncident.ReportedByUserId, New With {.onchange = "ReportedByUserId_onchange(this)", .maxlength = "30"})
</td>
<td class="right">Reported by Name</td>
<td class="left">
#Html.TextBox("ReportedByName", myIncident.ReportedByName, New With {.maxlength = "50"})<br />
#Html.ValidationMessage("ReportedByName", New With {.class = "red"})
</td>
</tr>
<tr>
<td class="right">Reported by Email</td>
<td class="left">
#Html.TextBox("ReportedByEmail", myIncident.ReportedByEmail, New With {.maxlength = "50"})<br />
#Html.ValidationMessage("ReportedByEmail", New With {.class = "red"})
</td>
<td class="right">Reported by Phone</td>
<td class="left">
#Html.TextBox("ReportedByPhone", myIncident.ReportedByPhone, New With {.maxlength = "50"})
</td>
</tr>
</table>
<script type="text/javascript">
function UserId_onchange(textField) {
var parms = {UserName: textField.value};
$.ajax({
url: '#Url.RouteUrl(New With{.Controller = "Users", .Action = "Get"})',
type: 'POST',
dataType: 'json',
data: parms,
success: function (data) {
$("#UserName").val(data.Name);
$("#UserEmail").val(data.Email);
$("#UserPhone").val(data.PhoneWork);
}
});
}
function ReportedByUserId_onchange(textField) {
var parms = { UserName: textField.value };
$.ajax({
url: '#Url.RouteUrl(New With{.Controller = "Users", .Action = "Get"})',
type: 'POST',
dataType: 'json',
data: parms,
success: function (data) {
$("#ReportedByName").val(data.Name);
$("#ReportedByEmail").val(data.Email);
$("#ReportedByPhone").val(data.PhoneWork);
}
});
}
</script>
You could check whether appropriate tab's div has any "input-validation-error" class applied (taken you use standard DataAnnotations). Combine this into jQuery function which would run through all needed divs (probably all divs specified in your li elements) and if length of elements with "input-validation-error" class is more than 0, as #rivarolle suggested apply "error" class to li element to highlight it in your preferred way.
This would be a possible script:
$( "li" ).each(function( index ) {
var searchPattern = ("#"+$(this).text()+" .input-validation-error");
if ($(searchPattern.toLowerCase()).length > 0){
$(this).addClass("error");
}
});
css:
.error {
background-color: red;
}
Give your li elements IDs
<li onclick="switchTab(this)" id="softwareTab">Software</li>
Then pass the collection of validation objects, or, better a list of affected tab names in your ViewModel, and store the list in one or more hidden fields. Then use jQuery to parse the list and add the error class as suggested by rivarolle...
$("#softwareTab").addClass("error")
You may have to clean up later with removeClass().
There are many ways to do this, all a bit kludgy, but sometimes that is the price of a good looking page...one hidden field with a comma seperated list, one hidden field per tab with a boolean value...or pseudo-boolean.
I think, The page should be divided into partial views. Each partial view needs to be validated before proceeding to next step. For that we can write a helper Method. When user fills the data and post the section, then controller checks and fills your custom validation error collection and it can be passed on as model metadata i.e. buddy class in your model. This way , you will render the errors. i.e. we are using model-metadata to send validation errors.
If you don't want to use model approach then you need to use ViewBag collection which is dynamic collection.
Hope this helps.
What you will probably need to do is use the visibility of the various validation messages.
The way I'd approach this is by adding a custom class to the validation messages for use within jquery:
#Html.ValidationMessage("UserName", New With{.class = "red validationMesssage"})
Then in the switchTab function do something like this:
function switchTab(el)
{
var tabId=$(el).text(); //Get the tab to be searched
var isValid=true; //Set default as valid
$("#"+tabId).find(".validationMessage:visible").each(function(){
isValid=false; //this should only fire if the validation message is visible
});
if(!isValid)
$(el).addClass("errors"); //If invalid..add error class to li element.
}
You can try #Html.ValidationSummary(false) at the top MAIN view. Its better from usability perspective as well.
You could change the color of the tab headers that contain errors to red for instance.
To do this, I would switch the css of the tags.
To take the Information tab:
No error:
--> <li onclick="switchTab(this)">Information</li>
Error:
--> <li onclick="switchTab(this)" class="error">Information</li>
The CSS class "error" will change the color to red or append an image to indicate validation failure.
In a declarative dojox.grid.datagrid, am using onresizecolumn in table tag.
onresizecolumn="columnResize(this.id,this.cellIdx)"
onresizecolumn calls a function. on resizing particular column i want to get the cellIdx.
<div class="claro" id="eterte" name="dataGrid" onclick="getConnect('inner__eterte');setWidgetproperty(this.id,'xy','inner__eterte');" ondblclick="editCustomGrid(this.id)" onmouseup="setDocStyle(this.id)" style="height:200px; left:39px; position:absolute; top:251px; width:950px;">
<table class="claro" dojotype="dojox.grid.DataGrid" id="inner__eterte" onresizecolumn="columnResize(this.id,this.cellIdx)" rowselector="10px" style="height: 180px; width: 400px;">
<thead>
<tr>
<th field="Column1" id="Column1_6" width="159px">
Column1
</th>
</tr>
</thead>
</table>
<input id="hidden__eterte" name="dataGrid" style="display:none;" type="hidden">
</div>
function columnResize(id,index){
alert();
alert(id);
alert(index);
}
By reading the API documentation I come to the conclusion that Dojo automatically sends the Cell index to the event handler. So the solution is by simply providing the following attribute onResizeColumn="myFunction" and then you define a function like this:
function myFunction(cellDx) {
alert(cellDx);
}
This should work, I even made a JSFiddle to test it. By the way, is there any reason why you would like to do all of it in a declarative way? As far as my experience goes, it's a lot easier to write most of this in JavaScript.
I can get it working this way, not sure if it's a best practice.
http://jsfiddle.net/gE8rH/6/
HTML (removed onresizecolumn attribute):
<div class="claro" id="eterte" name="dataGrid" onclick="getConnect('inner__eterte');setWidgetproperty(this.id,'xy','inner__eterte');" ondblclick="editCustomGrid(this.id)" onmouseup="setDocStyle(this.id)" style="height:200px; width:950px;">
<table dojotype="dojox.grid.DataGrid" id="inner__eterte" rowselector="10px" style="height: 180px; width: 400px;">
<thead>
<tr>
<th field="Column1" id="Column1_6" width="109px">Column1</th>
<th field="Column2" id="Column1_7" width="109px">Column2</th>
<th field="Column2" id="Column1_8" width="109px">Column3</th>
</tr>
</thead>
</table>
</div>
JS (using Dojo 1.7+ module names), assign to the widget's onResizeColumn property:
require(["dojo/parser", "dijit/registry", "dojox/grid/DataGrid"], function (parser, registry) {
parser.parse().then(afterParse);
function afterParse() {
var d = registry.byId("inner__eterte");
console.log(d);
d.onResizeColumn = function (colIdx) {
console.log("columnResize");
console.log("args", arguments);
console.log("this", this);
console.log("colIdx", colIdx);
};
}
});
Outputs this when resizing the first column:
columnResize
args [0]
this [Widget dojox.grid.DataGrid, inner__eterte] { _attachPoints=[4], _attachEvents=[1], _connects=[0], more...}
colIdx 0