Changing the background colour of a given row in a table - asp.net-mvc

I need to change the background color of a given row in a table based on a value of a model (boolean) property which is used in the #Html.CheckBox. The model is updated with the new checkbox value in the PostExampleCompleted action method.
<table>
<thead>
<tr>
<th>Item name</th>
<th>Comments</th>
<th>User</th>
<th>Complete</th>
</tr>
</thead>
<tbody>
<tr id="FooRow">
<td>Foo</td>
<td>#Model.FooComments</td>
<td>#Model.FooUserName</td>
<td>
#using (Ajax.BeginForm("PostFooCompleted", "Home", new AjaxOptions { OnBegin = "ShowProcessingMsg", OnComplete = "HideProcessingMsg" }))
{
#Html.CheckBox("FooItemComplete", Model.FooComplete, new { onClick = "$(this).parent('form:first').submit();" })
}
</td>
</tr>
<tr id="WidgetRow">
<td>Widget</td>
<td>#Model.WidgetComments</td>
<td>#Model.WidgetUserName</td>
#using (Ajax.BeginForm("PostWidgetCompleted", "Home", new AjaxOptions { OnBegin = "ShowProcessingMsg", OnComplete = "HideProcessingMsg" }))
{
#Html.CheckBox("WidgetItemComplete", Model.WidgetComplete, new { onClick = "$(this).parent('form:first').submit();" })
}
</td>
</tr>
</tbody>
</table>
What would be the best way to achieve this? Code examples would be appreciated :).
Thanks.

Something like this should do the trick, given that I've understood what you're trying to do correctly.
First here's a css class which I've used to colour a row if a checkbox is checked.
.redBackground
{
background-color: Red;
}
Next, here is some JQuery code to colour the row where the check-box resides if it is checked. I've also added a 'change' handler to each check-box so if any of them are updated, the row colour is updated appropriately (I've just used red for a row where a check-box is checked and no colour where a check-box is not checked).
<script src="http://code.jquery.com/jquery-latest.js"></script>
<script type="text/javascript">
$(function () {
$('input[type=checkbox]').each(function () {
var checkbox = $(this);
// if the checkbox is already checked, colour its row
CheckStatus(checkbox);
//Every time a check-box status changes we
//want to re-evaluate the row colour
checkbox.change(function () {
CheckStatus(checkbox);
});
});
//Method which checks if the check-box is checked. If it's checked
//the row is given the 'redBackground' class, otherwise it is taken away
function CheckStatus(checkbox) {
if (checkbox.attr('checked') == 'checked') {
checkbox.parent().parent().addClass('redBackground');
}
else {
checkbox.parent().parent().removeClass('redBackground');
}
}
});
</script>
Hopefully this makes sense... :)

The code is a little to small to exactly get what your settings are.
From the fact that you have a Element I deduce that you have multiple rows in a table.
Personally I'd object to having a AjaxForm in each of the rows. That seems like a lot of overhead.
You could very easy have a single construct of jQuery code to handle all rows and perform the neccessary tasks by itself.
If you use the live function of jQuery you are even independent of rows being added.
The checkbox or the row need to have an identifier with which you can send the ajax call back to your controller. On success you can evaluate the state of the checkbox and color the row appropriately.
I would have to see more of the code, to really help you with that.

Maybe I'm missing something. This seems like a job for html or css. As far as I can make out, there are several ways to approach this depending on your requirements.
On a row by row basis (i.e., you will never know what the colours are until they are defined somewhere by the app or in a database where storing their value statically is not an option), assign the html style property <tr style='background-color: #Model.Colour'> on the row to set the background-color to the colour you want.
On a type/state basis (i.e., you know what the colours are going to be ahead of time, but not what rows they are going to be assigned to), I'd define a class for each row: <tr class='#Model.Type'> and then assign the background-color in your CSS class with the same name as the value in Model.Type.
To get that colour/type itself, you are going to want to pass it in using your model. You might already have that property on your model, I don't know.
For simple alternating pattens, simply use this technique or the :nth-child(odd) and :nth-child(even) css selectors.
Sometimes the simplest solutions are the best solutions.

Related

Disable entire jqGrid

I have been looking for methods on how to disable a jqGrid and I found some:
Using BlockUI plugin: http://jquery.malsup.com/block/
Using jqGrid options: loadui and set it to 'block'
First option is a great solution (I have not tried yet) and it is clearer maybe but I want to avoid using plugins if I can whenever I can do it by setting object properties so I am trying the second option but it is not working for me, jqGrid continues enabled.
My jqgrid in my asp.net mvc 4 view:
<div id="jqGrid">
#Html.Partial("../Grids/_PartialGrid")
</div>
and _PartialGrid:
<table id="_compGrid" cellpadding="0" cellspacing="0">
</table>
<div id="_compPager" style="text-align: center;">
</div>
so in the view, in script section I perform below on document ready and depending on the status of a property in my model (I disable it if id>0, otherwise I enable it on page reload):
#section scripts
{
#Content.Script("/Grids/CompGrid.js", Url) // Content is a helper javascript loader (see end of this post)
}
<script type="text/javascript">
$(document).ready(function () {
showGrid();
var disableCompGrid = #Html.Raw(Json.Encode(Model.ItemCompViewModel));
setStatusCompGrid(disableCompGrid.id > 0);
}
</script>
CompGrid.js is:
function showGrid() {
$('#_compGrid').jqGrid({
caption: paramFromView.Caption,
colNames: ....
}
function setStatusCompGrid(disabled) {
$('#_compGrid').jqGrid({
loadui: 'block',
loadtext: 'Processing...'
});
}
In the code above, also I have tried to pass as parameter disabled to showGrid function and depending on if it is true or false to set a variable to 'block' or 'enable' respectively and then setting loadui property with this variable but it is not working.
Content.cshtml:
#using System.Web.Mvc;
#helper Script(string scriptName, UrlHelper url)
{
<script src="#url.Content(string.Format("~/Scripts/{0}", scriptName))" type="text/javascript"></script>
}
Any ideas?
It's important to understand that the call $('#_compGrid').jqGrid({...}); converts initial empty <table id="_compGrid"></table> element to relatively complex structure of dives and tables. So you can do such call only once. Such call creates and initialize the grid. In other words the function showGrid has bad name. The function can be called only once. The second call of it will test that the grid already exist and it will do nothing. If you need to change some parameters of existing grid you can use setGridParam method.
In the case you can use absolutely another solution to block the grid. After the call $('#_compGrid').jqGrid({...}); the DOM element of the initial table get some expandos - new property or method. For example $('#_compGrid')[0] will contains grid property which contains beginReq and endReq methods. So you can first create the grid (in the showGrid function) and include options loadui: 'block' and loadtext: 'Processing...' in the list of options which you use. Then if you need to block the grid later you can use
$('#_compGrid')[0].grid.beginReq();
and the code
$('#_compGrid')[0].grid.endReq();
to remove blocking. See the demo which demonstrates this. Alternatively you can show overlays created by jqGrid manually like I described in the answer. The code will be simple enough:
var gridId = "_compGrid"; // id of the grid
...
$("#lui_" + gridId).show();
$("#load_" + gridId).text("Processing...").show();
to show the overlay and
$("#lui_" + gridId).hide();
$("#load_" + gridId).hide();
to hide the overlay. See another demo which works exactly like the first one.
you don't need any plugin. Just add/remove css:
.disabled {
pointer-events: none;
//optional
opacity: 0.4;
}
DEMO

Are dynamically created table rows not targetable by jQuery?

I'm trying to make table rows draggable and then connectToSortable -able.
For some reason, when I put the ID of the tbody ("#sem1") in the selector, it works but obviously drags the whole table-body with all of its rows.
However, when I put "#sem1 tr" in the selector the webpage seems to just ignore that code, meaning the table still shows up correctly, but nothing becomes draggable.
HTML:
<table class = "sem">
<thead>
<th class = "header1">header</th>
<th class = "header2">header</th>
<tr>
<td class = "static1">static1</td>
<td class = "static2">static2</td>
</tr>
</thead>
<tbody id = "sem1">
</tbody>
</table>
Through some JavaScript table rows get added to sem1 like so.
JavaScript:
First pos0[0] (an array) gets populated:
for(var i in setPos[0]){
setPos[0][i]=("<tr><td class = " + String(setClass[i])+ ">" + setPos[0][i].slice(2) + "</td><td class = 'someClass'>"+setThis[i]+"</td></tr>");
}
Then pos0[0][a] gets added to sem1 like this:
for(var a in pos0[0]){
document.getElementById("sem1").innerHTML += pos0[0][a];
}
and when I try to make the rows draggable, it just doesn't work.
jQuery:
$("#sem1 tr").draggable()
Putting just tr in the selector doesn't work either (I don't mind if all the table rows in the whole document are draggable)
**I know that the code says setPos[0] - it's part of a function that does the same thing to pos1, pos2...
Thanks in advance for any help!
My guess is that you are calling the $("#sem1 tr").draggable() line before the code that has inserted the new <tr>'s has been run, so it doesn't see the rows you've added.
Also, have you tried manually inserting some markup to check that the draggable code actually works on a per row basis?
It would help if you could post an example in jsfiddle or something so we can work on this with you.
Finally it could be overkill for this situation but have you looked into using a JavaScript templating engine if you are going to be building chunks of html in your app?

Basic scenario of navigating to another page based on a row clicked in a table

I have a table with a bunch of items. Each row can be clicked (on any columns in this row) and navigate to another page based on the clicked row. I have a javascript file attached to this page where I manage events (clicked row, ...).
In my ASP.NET MVC solution, I would like to choose a goo way to manage this scenario.
Below is the one I think:
My view:
<table>
<tbody>
#foreach (var item in Model)
{
<tr data-url="#Url.Action("General", "Transport", new { transportID = item.TransportID })">
<td>aaaa</td>
<td>bbbb</td>
<td>cccc</td>
</tr>
}
</tbody>
</table>
My js file:
$("table.search-transport tbody tr td:not(:first-child)").live("click", function () {
var url = $(this).parents('tr').data('url');
window.location.href = url;
});
Because we cannot inject server code inside javascript files, I inject the url directly inside each rows inside my view. When a row is clicked, I get this "specific" url and navigate to it from my javascript file.
I would like to know if this solution is steady enough in an MVC project.
Following up from the comments, Nikola is right in saying that this does not impact the usage of the ASP.NET MVC framework. Injecting the URL into a data field in your case is the only option as far as I can see it (but I am open to other suggestions).
For the js part, I would use event delegation to avoid attaching events to every single cell:
$("table.search-transport tbody tr").on("click", "td:not(:first-child)", function () {
var url = $(this).parents('tr').data('url');
// also: $(this).parent().data('url'); will work...
window.location.href = url;
});
This will attach the event to each row but fire only when you click on a td which is not the first child. Alternatively, you could attach the whole event once to the table, thus also having the option of adding rows dynamically and still having the event attached; like this:
$("table.search-transport").on("click", "tr td:not(:first-child)", function () {
[...]
});

jquery attr title removing is not working in Mozilla FF

Cold you plz look the following code,
<table title="Demo1">
<tr>
<td> Test1 </td>
<td> Test2 </td>
</tr>
</table>
Here the both Test1 and Test2 links displays default title "Demo1"
But i do not want the title for both links, for this functionality i am doing as follows
$("#anch1").removeAttr("title");
$("#anch2").removeAttr("title");
or
$("#anch1").attr("title", "");
$("#anch2").attr("title", "");
this code works in IE, but M FF is not working, the title is still displaying, and the table title should be there, we should not remove the table tile,
Could you plz answer..
You need to temporary clear the parent table title when hovering over the links, then restore the title when mouse leave the links. Most simple way is adding id to the table itself then:
var $table = $("#table1");
var originalTitle = $table.attr("title");
$("#anch1, #anch2").hover(function() {
$table.attr("title", "");
}, function() {
$table.attr("title", originalTitle);
});
This way you're not dependent on browser behavior.
If you want this applied to all the links in the table, change the selector from "#anch1, #anch2" to $table.find("a").
Live test case.
Try:
$('table').removeAttr('title');
The title is applied to the table, not the anchors. Also, your table markup is malformed (you need to wrap TDs in TR), and that might confuse the selector engines.

Refresh KnockoutJS Data In DataTables

I have the following table
<table class="datatable zebra-striped">
<thead>
<tr>
<th>Name</th>
<th>Issue</th>
<th></th>
</tr>
</thead>
<tbody data-bind="foreach: Publications">
<tr>
<td><span data-bind="text: Name" /></td>
<td><span data-bind="text: IssueNumber" /></td>
<td><button type="button" class="btn" data-bind="click: $parent.DeletePublication">Delete</button></td>
</tr>
</tbody>
</table>
Here is a snippet of the viewmodel:
function EditReaderViewModel() {
var self = this;
self.Publications = ko.observableArray([]);
self.OnAddPublicationSaveButtonClicked = function () {
//.. code omitted.
self.Publications.push(new Publication(publication.value, publication.label, publication.issueNumber));
};
};
}
and the Publication object binded to the table:
function Publication(id, name, issueNumber) {
var self = this;
self.Id = id;
self.Name = name;
self.IssueNumber = issueNumber;
self.LoadedFromDatabase = false;
}
When the data is first loaded into the table, and the datatable initialisation e.g.
$(".datatable").dataTable({ // blahh });
Everything works fine - the data is loaded in the table, sorting and filtering is working, etc.
Now when I add a new item to the Publications array in the viewmodel things just fall apart. For example, say I originally have 1 item in the Publications array, when I add another item, it will appear in the table until I click on a column heading to sort.
It seems that the datatable has it's own internal data list somewhere which does not include the new Publication I created.
Can someone guide me on how to rebuild the datatable, taking into account that the data is from a KnockoutJS viewmodel?
Please note that I have looked at this binding plugin:
http://www.joshbuckley.co.uk/2011/07/knockout-js-datatable-bindings/
The problem is that when I use this, I get error messages such as:
Requested unknown parameter '0' from the data source for row 0.
EDIT:
I'm looking through the code and I think I see the problem. In jQuery.DataTables.js there is this function function _fnGetCellData( oSettings, iRow, iCol, sSpecific )
In that function there is this line:
if ( (sData=oCol.fnGetData( oData )) === undefined )
which in turn calls:
function _fnGetObjectDataFn( mSource )
Now, in function _fnGetObjectDataFn( mSource ) there is this code which is called:
else
{
/* Array or flat object mapping */
return function (data) {
return data[mSource];
};
}
data is not an array, it's a JSON object which means that the above code will fail (return data[mSource];).
I'm really not sure what to do here.
EDIT - IMPORTANT:
As one of the commentators has noticed, and I've just confirmed, accessing
http://www.joshbuckley.co.uk/2011/07/knockout-js-datatable-bindings
will result in a Trojan warning. So please be aware that this url is now an big NO-NO.
I know that´s an older thread but since I found it when I had the same problem I feel the need to post the solution so others might find it quicker.
When refreshing the Table you can simple .clear() and then .destroy() the table.
After that just reinitialize the table using the already known .DataTable()
Although that's a little messy because you really tear down the structure and rebuild it it work very smoothly.
You just have to add a boolean identifier you set to true the first time you initialize the table. And of course you have to bind the Table to a variable to be able to work the DataTable API magic on the DOM Element.
if (managementLoadedDone){
userTable.clear();
userTable.destroy();
}
Fill data in your Table
userTable = $("#userTable").DataTable({responsive: true});
usersLoaded = true;
You mention that you used datatable plugin and get "Requested unknown parameter '0' from the data source for row 0" error.
In my previous experineces using datatable without knockout plugin i got this error only using more columns than the header definitions or vice versa. You have to check your tbody and thead section and make it sure that both of them is the same size.
Or may be you are using "aoColumnDefs" option when you initialize the table.Again checked the option definiton and make sure that you havent try to reach unknown column :
For example if you have a definition like this
"aoColumnDefs": [{
"bSearchable": false,
"bVisible": false,
"aTargets": [0]
}, {
"bSortable": false,
"bSearchable": false,
"sWidth": "45px",
"aTargets": [2]
}]
and if you have only 2 thead section this will give you that error. Because you are reaching third column with aTargets : [2]
I was experiencing a similar problem as you've described here (and didn't have any intention of exploring the "bindings" link after the Kaspersky warning, even if it is really safe.)
Going a bit on the approach suggested here KnockoutJs - how to use datatables with existing bound table, I ended up taking a route where when using knockout on the table, I added a knockout if statement to test if the observableArray had at least one row of data.
<!-- if Publications.length() > 0 -->
<table class="datatable zebra-striped">
<thead>
<tr>
<th>Name</th>
<th>Issue</th>
</tr>
</thead>
<tbody>
<!-- ko foreach: Publications -->
<tr>
<td><span data-bind="text: Name" /></td>
<td><span data-bind="text: IssueNumber" /></td>
</tr> <!-- /ko -->
</tbody>
</table>
<!-- /ko -->
When loading the View Model, I then called the dataTables function
inside my .ajax success function.
Then the other part to making it work was to make use of dataTables "bStateSave": true,
so that any sorting I had done prior to a refresh would not be lost.

Resources