here is the html table I am working on:
<tbody data-bind="foreach: xusers.list">
<tr data-bind="css:{'approved-false' : member()==1 }">
<td data-bind="text: member"></td>
<td data-bind="text: expired"></td>
<td data-bind="text: name"></td>
<td data-bind="text: email"></td>
</tr>
</tbody>
The value of the array item member displays in the table just fine but my css call is not working no matter what syntax I have tried. I just want to apply this class if member is true (member contains either 1 or 0).
What am I missing?
Additional Code - Am I overwriting observable?...Here is the only place anything is written to the array.
if (!data) {
...
}
else {
if (data.length) {
var curItem;
for (var i=0; i<data.length; i++) {
curItem = new xuser();
curItem.name = data[i].name;
curItem.email = data[i].email;
curItem.city = data[i].city;
curItem.region = data[i].region;
curItem.country = data[i].country;
curItem.expires = data[i].expires;
curItem.member = data[i].member;
curItem.expired = data[i].expired;
xusers.list.push(curItem)
totalRecs = data[i].TotalCount;
}
}
} // if (!data)/else
You were close, just had it backward: see http://knockoutjs.com/documentation/css-binding.html
<tbody data-bind="foreach: xusers.list">
<tr data-bind="css:{'approved-false': member() == 1 }">
<td data-bind="text: member"></td>
<td data-bind="text: expired"></td>
<td data-bind="text: name"></td>
<td data-bind="text: email"></td>
</tr>
</tbody>
You are also overwriting your observables, see below (this assumes that all fields on curItem are observables, update your own as needed):
if (!data) {
...
}
else {
if (data.length) {
var curItem;
for (var i=0; i<data.length; i++) {
curItem = new xuser();
curItem.name(data[i].name);
curItem.email(data[i].email);
curItem.city(data[i].city);
curItem.region(data[i].region);
curItem.country(data[i].country);
curItem.expires(data[i].expires);
curItem.member(data[i].member);
curItem.expired(data[i].expired);
xusers.list.push(curItem)
// this should probably be somewhere else
totalRecs = data[i].TotalCount;
}
}
} // if (!data)/else
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 simple mvc table in my cshtml page where I am trying to add a checkbox in one of the columns but I am getting following error wheh I am clicking on the checkbox:
Uncaught TypeError: Cannot read property 'click' of undefined
Now this error is coming from bootstrap.js file:
b.prototype.click = function(b) {
var c = a(b.currentTarget).closest("tr").find(this.options.target)[0];
if (a(b.target)[0] !== c)
if (b.preventDefault(),
c.click)
c.click();
else if (document.createEvent) {
var d = document.createEvent("MouseEvents");
d.initMouseEvent("click", !0, !0, window, 0, 0, 0, 0, 0, !1, !1, !1, !1, 0, null),
c.dispatchEvent(d)
}
}
I can see that the value of "c" is undefined and due to that, it throws the error. If I comment bootstrap.js file from the layout page. Everything is ok.
Here is my table:
<table id="DashboardTab" class="table table-striped rowlink table-hover" data-link="row">
<tr>
<th>
Name
</th>
<th>
Groups
</th>
<th>Active</th>
<th></th>
</tr>
#{var i = 0;}
#foreach (var item in Model)
{
<tr>
<td style="display: none">#item.Id</td>
<td>
#Html.ActionLink(item.Name, "Edit", new { id = item.ID })
</td>
<td>
<i>All</i>
</td>
<td>
#if (item.IsStd)
{
#Html.CheckBox("Active" + i, item.IsActive.Value)
}
</td>
<td style="display: none">#item.IsStandard</td>
<td>
<i class="fa fa-arrows-v" aria-hidden="true"></i>
</td>
</tr>
i++;
}
</table>
What am I doing wrong?
Update:
So the issue is because of "data-link="row". Actually the row is clickable and thus, clicking on checkbox acts like a row click. How can I only make few rows clickable and not all?
So the issue was because of the data-link=row in the table. I needed only few rows to be clickable so I removed data-link=row from table and in the in added onclick() event:
if(item.IsStd){
<tr onclick="location.href = '#Url.Action( "Edit", "Home",new {id = item.ID})'">
}
I want to repeat a dropdownlist that is already bound using a Viewbag property and another textbox when a user click on Add Course.
I have used asp.net mvc and knockout.js based on a tutorial i saw, but the tutorial does not exactly handle using bound controls, please how can i achieve this using asp.net mvc and knockout.js.
Below is my code.
Thanks
<table id="jobsplits">
<thead>
<tr>
<th>#Html.DisplayNameFor(m => m.selectedCourse.FirstOrDefault().FK_CourseId)</th>
<th>#Html.DisplayNameFor(m => m.selectedCourse.FirstOrDefault().CourseUnit)</th>
<th></th>
</tr>
</thead>
<tbody data-bind="foreach: courses">
#for (int i = 0; i < Model.selectedCourse.Count; i++)
{
<tr>
<td>
#Html.DropDownListFor(model => model.selectedCourse[i].FK_CourseId, new SelectList(ViewBag.Course, "Value", "Text", Model.FK_CourseId), "Select Course", new { #class = "form-control", data_bind = "value: courses" })
</td>
<td>
#Html.TextBoxFor(model => model.selectedCourse[i].CourseUnit, new { htmlAttributes = new { #class = "form-control", #readonly = "readonly", data_bind = "value: courseUnit" } })
</td>
<td>
<button type="button" data-bind="click: $root.removeCourse" class="btn delete">Delete</button>
</td>
</tr>
}
</tbody>
</table>
<div class="col-md-4">
<button data-bind="click: addCourse" type="button" class="btn">Add Course</button>
</div>
This is the script section
#section Scripts{
#Scripts.Render("~/bundles/knockout")
<script>
function CourseAdd(course, courseUnit) {
var self = this;
self.course = course;
self.courseUnit = courseUnit;
}
function CourseRegViewModel() {
var self = this;
self.addCourse = function () {
self.courses.push(new CourseAdd(self.course, self.courseUnit));
}
self.courses = ko.observableArray([
new CourseAdd(self.course, self.courseUnit)
]);
self.removeCourse = function (course) {
self.courses.remove(course)
}
}
ko.applyBindings(new CourseRegViewModel());
</script>
}
Edit:
i have been able to get this sample working from: http://learn.knockoutjs.com/#/?tutorial=collections
but it is only an hard-coded observableArray.
I want to be able to populate the select from the database. But it is not getting populated.
This is my sample code below:
<table id="jobsplits">
<thead>
<tr>
<th>Persenger Name</th>
<th>Meal</th>
<th></th>
</tr>
</thead>
<tbody data-bind="foreach: seats">
<tr>
<td>
<input data-bind="value: name" />
</td>
<td>
<select data-bind="options:coursesArray, optionsText:'Text', optionsValue:'Value', optionsCaption: 'Choose...'"></select>
</td>
<td>
<button type="button" data-bind="click: $root.removeSeat" class="btn delete">Delete</button>
</td>
</tr>
</tbody>
</table>
<div class="col-md-4">
<button data-bind="click: addSeat">Add Seat</button>
</div>
This is the adjusted script section:
<script>
function SeatReservation(name, initialMeal) {
var self = this;
self.name = name;
self.meal = ko.observable(initialMeal);
}
function ReservationsViewModel() {
var self = this;
//This is what i want to put in dropdown instead
self.thecourses.subscribe(function () {
getCourses();
});
// Editable data
self.seats = ko.observableArray([
new SeatReservation("Steve", self.thecourses),
new SeatReservation("Bert", self.thecourses)
]);
self.addSeat = function () {
self.seats.push(new SeatReservation("", self.availableMeals[0]));
}
self.removeSeat = function (seat) { self.seats.remove(seat) }
var getCourses = function () {
var collegeCode = $("#Colleges").val();
var departmentCode = $("#Departments").val();
var url = '#Url.Action("GetCourses", "Student")';
$.getJSON(url, { deptId: departmentCode, collegeId: collegeCode }, function (data) {
self.coursesArray(data)
});
}
}
ko.applyBindings(new ReservationsViewModel());
</script>
I just taked the default example from
https://lorenzofox3.github.io/smart-table-website/#section-pipe
but it doesn't work, I code copied from the example, and assigned in the code the app: ng-app="myApp", and a controller: ng-controller="pipeCtrl as mc" to make it work, no errors shown in console
I also added some console.log prints, to know when the specific code lines are executed, and I see the next in console:
pushed it
ctr init
here is the code:
var app = angular.module('myApp', ['smart-table']);
app.controller('pipeCtrl', ['Resource', function (service) {
var ctrl = this;
console.log("ctr init");
this.displayed = [];
this.callServer = function callServer(tableState) {
console.log("callserv");
ctrl.isLoading = true;
var pagination = tableState.pagination;
var start = pagination.start || 0; // This is NOT the page number, but the index of item in the list that you want to use to display the table.
var number = pagination.number || 10; // Number of entries showed per page.
service.getPage(start, number, tableState).then(function (result) {
console.log("getP");
ctrl.displayed = result.data;
tableState.pagination.numberOfPages = result.numberOfPages;//set the number of pages so the pagination can update
ctrl.isLoading = false;
});
};
}]);
app.factory('Resource', ['$q', '$filter', '$timeout', function ($q, $filter, $timeout) {
var randomsItems = [];
function createRandomItem(id) {
var heroes = ['Batman', 'Superman', 'Robin', 'Thor', 'Hulk', 'Niki Larson', 'Stark', 'Bob Leponge'];
return {
id: id,
name: heroes[Math.floor(Math.random() * 7)],
age: Math.floor(Math.random() * 1000),
saved: Math.floor(Math.random() * 10000)
};
}
for (var i = 0; i < 1000; i++) {
randomsItems.push(createRandomItem(i));
}
console.log("pushed it");
//fake call to the server, normally this service would serialize table state to send it to the server (with query parameters for example) and parse the response
//in our case, it actually performs the logic which would happened in the server
function getPage(start, number, params) {
var deferred = $q.defer();
console.log("getting p svc");
var filtered = params.search.predicateObject ? $filter('filter')(randomsItems, params.search.predicateObject) : randomsItems;
if (params.sort.predicate) {
filtered = $filter('orderBy')(filtered, params.sort.predicate, params.sort.reverse);
}
var result = filtered.slice(start, start + number);
$timeout(function () {
console.log("timeout");
//note, the server passes the information about the data set size
deferred.resolve({
data: result,
numberOfPages: Math.ceil(filtered.length / number)
});
}, 1500);
return deferred.promise;
}
return {
getPage: getPage
};
}]);
The page html rendered in asp.net mvc:
#section scripts {
<script src="~/Scripts/angular.js"></script>
<script src="~/Scripts/app1.js"></script>
<script src="~/Scripts/smart-table.js"></script>
}
<div class="row" ng-app="myApp">
<div class="col-md-12">
<h2>Smart Ajax Data Tables</h2>
<p ng-controller="pipeCtrl as mc">
<table class="table" st-pipe="mc.callServer" st-table="mc.displayed">
<thead>
<tr>
<th st-sort="id">id</th>
<th st-sort="name">name</th>
<th st-sort="age">age</th>
<th st-sort="saved">saved people</th>
</tr>
<tr>
<th><input st-search="id" /></th>
<th><input st-search="name" /></th>
<th><input st-search="age" /></th>
<th><input st-search="saved" /></th>
</tr>
</thead>
<tbody ng-show="!mc.isLoading">
<tr ng-repeat="row in mc.displayed">
<td>{{row.id}}</td>
<td>{{row.name}}</td>
<td>{{row.age}}</td>
<td>{{row.saved}}</td>
</tr>
</tbody>
<tbody ng-show="mc.isLoading">
<tr>
<td colspan="4" class="text-center">Loading ... </td>
</tr>
</tbody>
<tfoot>
<tr>
<td class="text-center" st-pagination="" st-items-by-page="10" colspan="4"></td>
</tr>
</tfoot>
</table>
</p>
</div>
</div>
Suppose I have a List of the following model -
public class stock
{
public string modelNo {get;set;}
public List<string> serialNumbers {get;set;}
}
and I want to display it as a table, something like -
Model No | Serial Numbers
----------------------------
Model A | ABC
| DEF
| GHI
----------------------------
Model B | 123
| 456
----------------------------
To display the table I'm using something like the below but I get an annoying green squiggle below the final </tr> -
<table>
<tr>
<th>
Model No
</th>
<th>
Serial Numbers
</th>
</tr>
#foreach (SalesOrderDetail line in Model)
{
int rowSpan = 1;
if (line.serialNumbers.Count() != 0)
{
rowSpan = line.serialNumbers.Count();
}
<tr>
<td rowspan="#rowSpan">
#line.modelNo
</td>
#{
int itemNo = 0;
}
#foreach (string serial in line.serialNumbers)
{
if (itemNo > 0)
{
#:<tr>
}
<td>
#serial
</td>
{
itemNo++;
if (itemNo < rowSpan)
{
#:</tr>
}
}
}
</tr> <- Green squiggle here ("End tag is missing matching start tag")
}
</table>
I know it's a really minor annoyance but does anyone know of a way to handle it trivially?
The problem is that your logic with if (itemNo > 0) cannot be understood by the editor at edit time. In order to avoid the validation error you need to refactor this to have one loop and emit the td elements inside depending on the loop, something like this:
#{
int itemNo = 0;
}
#foreach (string serial in line.serialNumbers)
{
<tr>
if (itemNo == 0)
{
<td rowspan="#rowSpan">
#line.modelNo
</td>
}
<td>
#serial
</td>
{
itemNo++;
}
</tr>
}
Note that this code block is not fully equivalent; it will not render a tr if line.serialNumbers is empty. However, if this is a requirement, you can still add it separately with an if block, like so (this also fixes the possible rowspan="0" bug):
#if (rowSpan > 0) {
#{
bool first = true;
}
#foreach (string serial in line.serialNumbers) {
<tr>
#if (first) {
first = false
<td rowspan="#rowSpan">
#line.modelNo
</td>
}
<td>
#serial
</td>
</tr>
}
} else {
<tr>
<td colspan="2">
#line.modelNo
</td>
</tr>
}