I'm working on a Asp.Net MVC 5 Web Pages project, where one of the partial views generates an Html table. It of course mixes the Razor syntax in with Html.
Now I need to implement this table as a Kendo UI Grid, where the HTML table is used as the DataSource (see this as a reference - http://demos.telerik.com/kendo-ui/grid/from-table).
Great so far - and yes, my new Kendo grid does in fact render nicely.
ex/
Only problem is that the Kendo Grid now seems to be overwriting the <tr> data-id attributes I'm injecting into each row.
So how would I turn this into a Kendo rowTemplate ?
Before implementing the Kendo Grid, here is the Html table as rendered:
<table id="summary-table" class="table table-hover table-extra-condensed">
<tr data-id="80" data-nodes="2008-08-08" data-title="EUREX IRS" data-subtitle="All">
<td class="hidden">80</td>
<td><i class="fa fa-chevron-right"></i> EUREX IRS</td>
<td class="text-right">USD</td>
</tr>
<tr data-id="50" data-nodes="2008-08-08" data-title="EUREX IRS" data-subtitle="IRS-EUR">
<td class="hidden">50</td>
<td><span class="indent">IRS-EUR</span></td>
<td class="text-right">USD</td>
</tr>
</tbody>
</table>
Here is the new table, now rendered as a Kendo grid (Kendo added data-uid but I lost my custom 'data-' row attribs):
<table id="summary-grid" class="table table-hover table-extra-condensed" data-role="grid" role="grid">
<tr data-uid="fcc1ffab-f1e7-4ea4-9b79-7c4149bbbfa3" role="row">
<td style="display:none" role="gridcell">80</td>
<td role="gridcell"><i class="fa fa-chevron-right"></i> EUREX IRS</td>
<td role="gridcell">USD</td>
</tr>
</table>
Here's the partial.cshtml file snippet:
#model IEnumerable<WhatifSummaryViewModel>
#{
string guid = Guid.NewGuid().ToString();
}
<table id="summary-grid" class="table table-hover table-extra-condensed">
<thead>
<tr>
<th data-field="id" hidden class="hidden">Id</th>
<th data-field="product">#Settings.Whatif.SummaryPortfolioName1 - #Settings.Whatif.SummaryPortfolioName2</th>
<th data-field="currency" class="text-right">Currency</th>
<th data-field="margin" class="text-right">#Settings.Whatif.SummaryCurrentExposureName</th>
<th data-field="wi" class="text-right hidden-xs">What-If</th>
<th data-field="impact" class="text-right">Impact</th>
<th data-field="chart" class="text-center hidden-xs">View</th>
</tr>
</thead>
<tbody>
#for (int i = 0; i < Model.Count(); ++i)
{
string title;
if (Model.ElementAt(i).SubTitle.Equals("ALL", StringComparison.OrdinalIgnoreCase))
{
title = "<i class='fa fa-chevron-right'></i> " + Model.ElementAt(i).Title;
}
else
{
title = "<span class='indent'>" + Model.ElementAt(i).SubTitle + "</span>";
}
<tr data-id="#Model.ElementAt(i).PortfolioId" data-nodes="#String.Join(",", Model.ElementAt(i).NodeDates)" data-title="#Model.ElementAt(i).Title" data-subtitle="#Model.ElementAt(i).SubTitle">
<td class="hidden">#Model.ElementAt(i).PortfolioId</td>
<td>#Html.Raw(title)</td>
<td class="text-right">#Model.ElementAt(i).Currency</td>
<td class="text-right">#String.Format("{0:#,0}", Model.ElementAt(i).Utilisation)</td>
<td class="text-right hidden-xs">#(Model.ElementAt(i).WhatIfRun ? String.Format("{0:#,0}", Model.ElementAt(i).WhatifExposure) : "")</td>
<td class="text-right">#(Model.ElementAt(i).WhatIfRun ? String.Format("{0:#,0}", Model.ElementAt(i).ImpactToExposure) : "")</td>
<td class="text-center actions hidden-xs"><i class="fa fa-bar-chart"></i></td>
</tr>
}
</tbody>
</table>
and finally, the Kendo grid which is configured in my onReady javascript function:
(NOTE: the rowTemplate below is commented, and certainly does cause a scripting error if uncommented).
// Kendo UI grid
$("#summary-grid").kendoGrid({
resizable: true,
toolbar: ["pdf","excel"],
columns: [
{ field: "PortfolioId", hidden: true },
{ field: "title"},
{ field: "Currency", title: "Currency" },
{ field: "Utilisation", title: "Margin" },
{ field: "WhatifExposure", title: "What-if"},
{ field: "ImpactToExposure", title: "Impact" },
{ field: "Chart", title: "View" }
]
#*rowTemplate: '<tr data-uid="#= uid #" data-id="#= #Model.ElementAt(i).PortfolioId #" data-title="#= #" >'*#
});
In the end, I'd like to add my custom data- row attribs. I was thinking that the kendo template would work, but I can't figure it out in this Web Pages Razor context.
Help is appreciated...
Bob
Related
I want to add one more field to my view. So basically, after displaying a town in the dropdown menu, I want to display the (*ABR) field as seen here.
As you can see from the picture, after Advance Ortopedical, I just want to add a filed called *ABR.
<table class="table datatable-responsive datatable-medical-map" id="medProviders" style="width:100%">
<thead>
<tr class="bg-info">
<th>Medical Provider (* Choose one)</th>
<th>Distance (miles)</th>
<th>Duration</th>
</tr>
</thead>
<tbody>
#{
int i = 0;
foreach (var item in medProviders)
{
<tr class="sortList" style="cursor:pointer" id="increment-#i" data-id="#item.Id" data-lat="#item.Latitude" data-long="#item.Longitude">
<td>#item.Firstname</td>
<td id="distance-#i"></td>
<td id="duration-#i"></td>
</tr>
i++;
}
}
</tbody>
</table>
<p id="medicalValidation"></p>
Any suggestions or comments on how to do this in a simple way?
Please use this code. This will add 1 more field at the end of table.
#{
int i = 0;
foreach (var item in medProviders)
{
<tr class="sortList" style="cursor:pointer" id="increment-#i" data-id="#item.Id" data-lat="#item.Latitude" data-long="#item.Longitude">
<td>
#item.Firstname
<br>*ABR</br>
</td>
<td id="distance-#i"></td>
<td id="duration-#i"></td>
</tr>
i++;
}
}
</tbody>
I Have a table, there i have a details hyperlink on click of which i m showing a new table on same page in other div. The details Hyperlink has 3 input parameters based on which a service method gets triggered and I get data in the data. Now i have this task to show the 2nd grid on a new page. I m not sure how to do it.
Please help.
<table class="table table-bordered table-condensed table-hover ">
<thead>
<tr style="white-space: nowrap;">
<th>Date</th>
<th>Organization No</th>
<th>Contract No</th>
<th>Company Name</th>
<th>Plan No</th>
<th>Status</th>
<th>View Detail</th>
</tr>
</thead>
<tr ng-repeat="mas in vm | startFrom:currentPage*pageSize | limitTo:pageSize" data-ng-class="{active1:$index==selectedRow}" data-ng-click="rowHighilited($index)">
<td>{{mas.startDate | amDateFormat:'YYYY-MM-DD'}} </td>
<td>{{mas.organizationNumber}}</td>
<td>{{mas.contractNumber}} </td>
<td>{{mas.name}}</td>
<td>{{mas.planNumber}} </td>
<td>{{mas.description}} </td>
<td><span>Details</span></td>
</tr>
</table>
//getErrorDetailBySearch(mas.productAccountOid,mas.planNumber,mas.migrationRunID)it calls the function to bring data an binds it to the below div.//
<div ng-show="IsVisible">
<div ng-show="vm1.length > 0 && !loading">
<h2>Error Detail</h2>
<br />
<div class="row">
<div class="col-sm-12 col-md-12 col-lg-12 table-responsive">
<table class="table table-bordered table-condensed table-hover table-striped">
<thead>
<tr style="white-space: nowrap;">
<th>Contract Number</th>
<th>Plan Number</th>
<th>Business Error Message</th>
<th>System Error Details</th>
</tr>
</thead>
<tr ng-repeat="mas in vm1">
<td>{{mas.contractNumber}} </td>
<td>{{mas.planNumber}} </td>
<td>{{mas.businessErrorMsg }} </td>
<td>{{mas.systemErrorMsg}} </td>
</tr>
</table>
</div>
</div>
I am able to call a new page Called as ErrorDeatils but i dont know how to pass data b/w the pages.
This is controller written for 1st page
$scope.getErrorDetailBySearch = function (productAccountOid, planNr, migrationrunid) {
var path = "/Utilities/Error";
$location.path(path.replace(/\s+/g, ""));
};
var onSuccess = function (response) {
$scope.vm1 = response;
if ($scope.vm1 < 1) {
messageService.noDataFound();
}
}
$scope.getErrorDetailBySearch = function (productAccountOid, planNr,migrationrunid, skipFormValidate) {
if (skipFormValidate || b360FormsService.validateForm($scope.ViewErrorDetail)) {
errorService.globalproductAccountOid = productAccountOid;
errorService.globalplanNr = planNr;
errorService.globalmigrationrunid = migrationrunid;
$scope.loading = true;
repositoryService.getErrorDetailBySearch(productAccountOid, planNr, migrationrunid).$promise.then(onSuccess, onError).finally(function () {
$scope.loading = false;
});
}
}
Hi you can pass data both as query parameters or route params
Query Parameters
Lets say you have path "/errorDetails" and you want to pass "param" with value "10", then you can use $location.path() as follows:
$location.path("/errorDetails").search({param: 10});
and you can access value of "param" on resultant page's controller as:
$location.search().param;
Route Parameters
For using route params you will need to change your route configurations and you path will be like:
$routeProvider
.when('/errorDetails/:param', {
title: 'Error Details',
templateUrl: 'path/to/errorDetails.html'
});
Now you can send param using $location.path as follow:
$location.path("/errorDetails/"+param);
And you can access route parameter on resultant page's controller as follows:
$routeParams.param
I'm creating a project using MVC, knockoutJS, Web API, Bootstrap and so forth, the database in use is MSSQL Server 2012. It's all working very well, the controllers have properly created CRUD operations. The data from DB is show in a grid table in the UI, and every row is clickable, and opens up a modal in which the data about that exact element is shown. The problem I'm experiencing is the inability to pass a certain value of the row, in this case an ID, to ViewModel as a parameter for getting a single result in modal. I can do it manually, and put some value in the ViewModel, and the data will show, but I'm unable to send the value from the View.
Here's the code for ViewModel:
var regionsModel = {
regionId: ko.observable(),
companyId: ko.observable(),
name: ko.observable(),
companyName: ko.observable()
};
var regionsListModel = {
regions: ko.observable()
};
function getRegions() {
get(apiUrl + "Regions/GetRegions", {}, function (data) {
regionsListModel.regions(data);
});
}
function getRegion() {
get(apiUrl + "Regions/GetRegion", { aiId: regionsModel.regionId() }, function (data) {
regionsModel.regionId(data.RegionID);
regionsModel.companyName(data.CompanyName);
regionsModel.companyId(data.CompanyID);
regionsModel.name(data.Name);
});
}
function viewRegion() {
$("#ViewRegionModal").modal('show');
//regionsModel.regionId($('#ViewRegion').val());
getRegion();
return false;
}
Here's the code for the View:
<table class="table table-striped table-bordered responsive" id="dtable">
<thead>
<tr>
<th style="width: 20px;">ID</th>
<th>Region Name</th>
<th>Company Name</th>
</tr>
</thead>
<tbody data-bind="foreach: regionsListModel.regions">
<tr id="ViewRegion" data-toggle="modal" data-bind="click: viewRegion, value: RegionID">
<td data-bind="text: RegionID"></td>
<td data-bind="text: Name"></td>
<td data-bind="text: CompanyName"></td>
</tr>
</tbody>
</table>
aiId parameter is for the GetRegion method in Controller.
This is the code for the View in which shows the data for a certain element:
<table class="table table-striped" data-bind="with: regionsModel">
<tbody>
<tr>
<th>Region ID:</th>
<td><span data-bind="text: regionsModel.regionId"></span></td>
</tr>
<tr>
<th>Region Name:</th>
<td><span data-bind="text: regionsModel.name"></span></td>
</tr>
<tr>
<th>Company Name:</th>
<td><span data-bind="text: regionsModel.companyName"></span></td>
</tr>
</tbody>
</table>
Any help would be appreciated!
Knockout adds the current bound object as first argument when it calls the event handler.
The second argument is the event object.
So the only thing you need to do is add a parameter to the viewRegion function.
function viewRegion(region) {
var regionID = region.RegionID;
// get data
return false;
}
I hope it helps.
I am using knockout js to acheive a task. My model is like:
var ServiceLevelRates = function(data, availableClasses) {
return {
TaxTypeID: ko.observable(data.Key),
TaxTypeName: ko.observable(data.Name),
ExtendedTaxTypeName: data.Name.replace(/\s+/g, ''),
ApplyAfter: ko.observable(-1),
TaxClasses: ko.observableArray(availableClasses)
};
};
var TaxClass = function(data, availableServices) {
return {
ServiceClassID: data.ServiceClassID,
ServiceClassName: ko.observable(data.ServiceClassName),
TaxServices: ko.observableArray(availableServices)
};
};
var TaxService = function(data) {
return {
ServiceID: ko.observable(data.ServiceID),
ServiceName: ko.observable(data.ServiceName),
ServiceRate: ko.observable(data.ServiceRate > 0 ? data.ServiceRate : "").extend({ numeric: 2 })
};
};
and my html is like:
<tbody data-bind="foreach: ServiceLevelRates">
<tr>
<td style="width:100%;">
<table width="100%">
<tr>
<td style="width:2%;">
<img src="../../Images/del_up.gif" onclick="HideMyChilds(this);" />
</td>
<td data-bind="text: TaxTypeName">
</td>
</tr>
<tr>
<td></td>
<td>
<table width="100%">
<tr>
<td style="width:20%;">
<label id="lblApplyAfter" myId="lblApplyAfter" runat="server">Apply After</label>
</td>
<td></td>
</tr>
<tr>
<td>
<select id="sltApplyAfter" SkinID="drpFields" name="sltApplyAfter" runat="server" myId="sltApplyAfter">
<option value="-1">Charge</option>
</select>
</td>
<td>
<input type="checkbox" />Apply for All Services<input type="text" onkeypress="ValidateDecimalValue(event,this)"; onblur="ApplyForAllServices(this);" data-bind="attr: { 'class': ExtendedTaxTypeName }" /> %
</td>
</tr>
<tr>
<td colspan="2">
<table width="100%">
<tbody data-bind="foreach: TaxClasses">
<tr>
<td style="width:2%;">
<img src="../../Images/del_up.gif" onclick="HideMyChilds(this);" />
</td>
<td style="width:100%;" class="tdRepeaterHeaderBG" data-bind="text: ServiceClassName">
</td>
</tr>
<tr>
<td></td>
<td>
<table width="100%">
<thead>
<tr>
<td style="width:1%;">
<td style="width:24%;" class="tdRepeaterHeaderBG">Service Name</td>
<td style="width:75%;" class="tdRepeaterHeaderBG">Amount</td>
</tr>
</thead>
<tbody data-bind="foreach: TaxServices">
<tr>
<td style="width:1%;">
<td style="width:24%;" data-bind="text: ServiceName"></td>
<td style="width:75%;">
<input type="text" data-bind="value: ServiceRate, attr: { 'class': $parents[1].ExtendedTaxTypeName, 'id': $parents[1].ExtendedTaxTypeName + ServiceID }" />%
</td>
</tr>
<tr>
<td></td>
<td colspan="2">
<div style="font-size: 11px; width:98%;height:5px; border-top: 1px dotted gray;"> </div>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</tbody>
The problem is when I provide ServiceRate for a taxservice in one class, it is updated into text field of same service in all other classes. Any help on it will be great.
Your code have several issues.
First, mostly a cosmetic one. You are using tables for layout. They should only be used when you truly need tabular data. Div's or lists are much better in most cases, and if you need to layout something, you could use css margins.
You are mixing, and mixing up, different object schemes.
One is to return an object literal:
function Foo() {
return {
Property: ko.observable(),
}
}
This schema could, but shouldn't, be called with the new operator.
The other one is prototype-based:
function Foo() {
var self = this;
self.Property = ko.observable();
}
This schema must be called with the new operator.
It is easiest to stick to one schema. With knockout, the latter is easier to use in some cases.
You are not using observables for all properties. It is a little confusing to be using observables for some properties, and not for others. You have to go back to the source-code to confirm for each property.
Your object model does not take into account object reuse. You are passing the same objects to each ServiceLevelRate, so when you are updating one TaxService, the same TaxService in all other TaxClass will also be updated.
One simple solution for this, is to factor out the fields that needs updating into mapping objects.
// This part is constructed once, based on server data.
function TaxService(data) {
var self = this;
self.ServiceID = ko.observable(data.ServiceID);
self.ServiceName = ko.observable(data.ServiceName);
}
// This part is constructed for each TaxClassMapping
function TaxServiceMapping(svc) {
var self = this;
self.TaxService = ko.observable(svc);
self.ServiceRate = ko.observable("");
}
Lastly; To conditionally update the rates based on the check-box, you can bind the it with the checked-binding. In the subscription for the ServiceLevelRate-wide rate, you just check if the check-box was checked, before proceeding to update the other fields.
self.ApplyForAll.subscribe(function (newValue) {
if (self.ApplyForAllCheckBox()) {
ko.utils.arrayForEach(self.Classes(), function (clsMapping) {
ko.utils.arrayForEach(clsMapping.ClassServices(), function (svcMapping) {
svcMapping.ServiceRate(newValue);
});
});
}
});
Here is an updated fiddle:
http://jsfiddle.net/MizardX/V8DTj/
I scaled down the models to the essential parts, to make them easier to work with.
To make the TaxServices show only for certain TaxClasses, you could filter which TaxService-objects you want to include for each TaxClass.
function TaxClassMapping(taxClass, availableServices) {
var self = this;
self.TaxClass = ko.observable(taxClass);
var classID = taxClass.ServiceClassID();
var filtered = ko.utils.arrayFilter(availableServices, function (svc) {
// svc.ServiceClassID is a new property in TaxService
return svc.ServiceClassID() === classID;
});
var mapped = ko.utils.arrayMap(filtered, function (svc) {
return new TaxServiceMapping(svc);
});
self.ClassServices = ko.observableArray(mapped);
}
It does not seem to like #{index++;} , I have tried
#{int index++}, #(index++), #(int index++;)
This code didn't throw errors when used with MVC 2.
Here's it's giving me
ambiguity warnings about index.
#model CartTest.Models.Cart
#{
ViewBag.Title = "Index";
}
<h2>Cart Index</h2>
<table width="80%" align="center">
<thead><tr>
<th align="center">Quantity</th>
<th align="left">Item</th>
<th align="right">Price</th>
<th align="right">Subtotal</th>
</tr></thead>
<tbody>
#{int index = 0;}
#foreach (var line in Model.Lines)
{
<tr>
#Html.Hidden("Lines.Index", index);
<td align="center">#Html.TextBox("Lines[" + index + "].Quantity",line.Quantity)</td>
<td align="left">#line.Product.Name</td>
<td align="right">#line.Product.Price</td>
<td align="right">#(line.Quantity * line.Product.Price)</td>
<td align="right">#Html.ActionLink("Remove", "RemoveItem", new { productId = line.Product.ProductID }, null)</td>
</tr>
#{index++;}
}
</tbody>
<tfoot>
</tfoot>
</table>
Try like this:
#{int index = 0;}
#foreach (var line in Model.Lines)
{
<tr>
...
</tr>
index++;
}
Now that's just to make the Razor compiler happy. It's not a solution I recommend. The real solution I would recommend you is to use editor templates:
<table width="80%" align="center">
<thead>
<tr>
<th align="center">Quantity</th>
<th align="left">Item</th>
<th align="right">Price</th>
<th align="right">Subtotal</th>
</tr>
</thead>
<tbody>
#Html.EditorFor(x => x.Lines)
</tbody>
<tfoot>
</tfoot>
</table>
and inside the corresponding editor template of a Line (~/Views/Shared/EditorTemplates/LineViewModel.cshtml) which will be rendered for each element of the Line collection:
#model LineViewModel
<td align="center">
#Html.TextBoxFor(x => x.Quantity)
</td>
<td align="left">
#Html.DisplayFor(x => x.Product.Name)
</td>
<td align="right">
#Html.DisplayFor(x => x.Product.Price)
</td>
<td align="right">
#Html.DisplayFor(x => x.CalculatedTotalPrice)
</td>
<td align="right">
#Html.ActionLink("Remove", "RemoveItem", new { productId = Model.Product.ProductID }, null)
</td>
See, no more ugly loops, weakly typed helpers, dealing with some indexes, etc... Everything works by conventions.