prototypeJS, change the row color Im 'using' - prototypejs

I'm using prototypeJS and I want to highlight the row of the record I've clicking on...
However, the issue is when I click on a second row, I want the first row to return to its original state - not I get multipls rows highlighted, but I only want the LAST ONE I CLICKED to be highlighted
HTML has a row id - so I know which row Im using.
<tr id="tblRowThing10434" bgcolor="#DDD">
<td>10434</td>
<td>aaa</td>
<td nowrap="">bbb</td>
<td nowrap=""><input class="btnSubmit"
type="button"
onmousedown="getAvailableResources( 10434, 'test', 'work' );"
value="Pick"
name="pickThing" ></td>
</tr>
<tr id="tblRowThing33434" bgcolor="#FFF">
<td>33434</td>
<td>aaa</td>
<td nowrap="">bbb</td>
<td nowrap=""><input class="btnSubmit"
type="button"
onmousedown="getAvailableResources( 33434, 'test', 'work' );"
value="Pick"
name="pickThing" ></td>
</tr>
SCRIPT looks like this
function getAvailableResources( a, b, c ) {
elem = 'tblRowLoad' + a;
$( elem ).setStyle({ backgroundColor: '#fff' });
//other 'work'
}

You can address all of the <tr>'s siblings and change all the styles and then change the current row background
So change your javascript function from this
function getAvailableResources( a, b, c ) {
elem = 'tblRowLoad' + a;
$( elem ).setStyle({ backgroundColor: '#fff' });
//other 'work'
}
to this
function getAvailableResources( a, b, c ) {
elem = 'tblRowLoad' + a;
$(elem).siblings().invoke('setStyle',{ backgroundColor: '' });
//reset background color by setting to an empty string ''
$( elem ).setStyle({ backgroundColor: '#fff' });
//other 'work'
}

I recommend the usage of a simple css:
.activeRow { background-color:#fff; }
/** in case you are using dirty inline css, add !important here but be ashamed pls */
Comebind with some handy features in your javascript:
function getAvailableResources( a, b, c ) {
elem = $('tblRowLoad' + a);
/** clear all rows */
elem.siblings().invoke('removeClassName', 'activeRow');
/** highlight current row */
elem.addClassName('activeRow');
//other 'work'
}
If this doesn't work - (for example, because you didn't use a class for your background color and can't change this (which you should!)) - add !important after the color code (#fff) to the class .activeRow.

Related

How to properly reverse sort a BackboneJs collection?

I have a table where several items are displayed.
<table>
...
<th scope="col">Priority <a id="sort"><i class="fas fa-chevron-down"></i></a> <a id="sort2">
<i class="fas fa-chevron-up"></i></a></th>
...
</table>
The priorities holds an integer value, 1, 2 and 3 respectively.
I'm trying to sort the items on button click. I managed to sort once by using collection.sort() in my view and it sorts perfectly. How can i reverse sort by clicking sort2 button? Any help regarding this is appreciated. Thank you.
app.views.ShareView = Backbone.View.extend({
el: ".page",
initialize: function () {},
events:{
"click #sort" : "sort",
"click #sort2" : "sort2"
},
sort: function (e){
e.preventDefault();
this.collection.comparator = 'priority_id';
this.collection.sort();
this.render();
},
sort2: function (e){
//reverse sort
}
render: function () {
template = _.template($('#share-template').html());
this.$el.html(template(app.userShare.attributes));
}
});
You need to use the sort comparator function instead of the comparator property. This allows you to specify a comparator function instead of just the property. For example;
this.collection.comparator = function(firstModel, secondModel) {
if(firstModel.priority_id > secondModel.priority_id) { // change to < in order reverse the order
return -1;
}
else if(firstModel.priority_id === secondModel.priority_id) {
return 0;
}
else {
return 1;
}
}
this.collection.sort();
In BackboneJS, it is often possible to use a function in place of a value if you require additional functionality.

computed properties returns undefined

this is code to display students table, i try to use commputed property for students full name but it displays UNDEFINED in the fullname column
<tr v-for="student in students" :key="student.id">
<td>{{ student.id }}</td>
<td><a href="#" class="nav-link">{{ student.index_no | uppercase }}
</a></td>
<td>{{fullname | capitalize}}</td>
<td>{{fullname | capitalize}}</td>
<td>{{student.department | capitalize}}</td>
<td>{{ student.course | capitalize}}</td>
<td>{{ student.regular_or_weekend | capitalize }}</td>
<td>{{ student.nationality | capitalize}}</td>
<td>{{ student.created_at |datetime }}</td>
this is the vuejs code, all the methods works fine with the exception of computed property which displays UNDEFINED. i have excluded the methods
<script>
import { Form, HasError, AlertError } from 'vform'
export default {
data () {
return {
editmode : true, // for edit conditional
students: {}, //student object
// Create a new form instance
form: new Form({
id: '',
index_no:'',
firstname: '',
middlename: '',
lastname: '',
department: '',
course:'',
regular_or_weekend:'',
nationality:''
})
} //end of data()
},
methods:{
}
computed:{
fullname:function(){
return this.firstname+" "+this.middlename+" "+this.lastname;
}
}
}
</script>
It appears you have an array of students which means you cannot use a computed property in this way as this implies there is only a single fullname property when in fact there are multiple (one for each student)
You have a couple possible options here. (code untested)
Option 1
Make a new component called Student, and pass the student object from your v-for into it as a prop like so
<tr v-for="student in students" :key="student.id">
<Student :student="student"/>
</tr>
the Student component would contain all the HTML to render a single student from the list and you could make your computed property similar to how you did originally now that the Student component is only rendering a single Student. This is probably the "best practice" way to do it.
computed:{
fullname:function(){
return this.student.firstname+" "+this.student.middlename+" "+this.student.lastname;
}
}
Option 2
You can use a computed property to simply add a new property to your students array
computed:{
studentsWithFullname: function(){
return this.students.forEach(element => {
element.fullname = element.firstname + " " + element.middlename + " " + element.lastname
});
}
}
then iterate over the "studentsWithFullname" array instead of the students array (or whatever you want to call it) and output fullname
Option 3
Don't bother with any of this and just use student.firstname + " " + student.middlename + " " + student.lastname directly in your template as you have done already
Use a method instead of a computed property, passing in the student.
Template:
<tr v-for="student in students" :key="student.id">
<td>{{getFullName(student) | capitalize}}</td>
JavaScript:
methods: {
getFullName (student) {
return student.firstname + ' ' + student.middlename + ' ' + student.lastname;
}
}

getting error 404 while passing an array through ajax to the controller

i have a loop like this in my view that generates the list of student`s names
<Table id="your_table">
<thead>
<tr>
<th>name</th>
<th>grade</th>
<th>remove</th>
</tr>
</thead>
<tbody>
#foreach (string item in Model)
{
<tr>
<td id="td_name" style="border-left: thin">#item</td>
<td><input type="text" id="txtGrade_#item" onclick="" style="width: 40px;border-left: thin" /></td>
<td><input type="checkbox" id="chkStudent_#item" value="#item" /></td>
</tr>
}
</tbody>
i use the script below to get the text for the first cell of each row :
$('#btnDone')
.click(function() {
//get studentslist
function getFirstCellTextList(tableElement) {
if (tableElement instanceof jQuery) {
// Create an array
var textList = [];
// Iterate over each table row
tableElement.find('tbody tr').each(function () {
// Get the first cells's text and push it inside the array
var row = $(this);
if (row.children('td').length > 0) {
textList.push(row.children('td').eq(0).text());
}
});
return textList;
}
return null;
}
// Get the array
var lststudents = getFirstCellTextList($('#your_table'));
var result = [];
$(lststudents).each(function(index, item) {
result.push(item);
});
alert(result);
$.ajax('/TeacherPages/GetGrades/' + result).done(function () {
alert("done");
});
});
the problem is. when i want to send the created array to the controller i get error 404. there is something wrong with this array. because when i manually add values to the array the ajax works without any problems
this is my action:
[AttributeRouting.Web.Mvc.GET("/TeacherPages/GetGrades/{result}")]
public PartialViewResult GetGrades(string[] result)
{
return PartialView();
}
You cannot just append a javascript array to your url. It just converts the values in the array to a comma separated string whereas you need to generate a url which is
/TeacherPages/GetGrades?result=someValue&result=anotherValue&result=etc...
Change your script to
$.ajax({
url: '#Url.Action("GetGrades", "TeacherPages")', // don't hardcode your url's
type: 'POST',
traditional: true,
data: { result: result },
success: function (response) {
....
}
});
As a side note, your getFirstCellTextList() function is returning the array you want and its pointless to create another identical array from it. You just need
var result = getFirstCellTextList($('#your_table'));

How to calculate a total in a grid with breeze.js extended entities?

I am working on an MVC web application using the MVVM pattern, breeze.js and knockout.js. This is the first time I use these js libraries and I still have to grasp how they work.
One of the pages of the application has a grid where both columns and rows are generated dynamically. I need to add an additional column where for each row I have the total of values displayed in the following row cells. Here an example:
Data type | Comment | Fact 1 | Fact 2 | Total | Value 1 | Value 2 | Value 3 | Value 4
==============================================================================================
Item 1 | any comment | fact 1 | fact 2 | calc. sum | 10 | 20 | 30 | 40
The grid is generated by binding a breeze entity object (planningItems) to templates. The object has the properties DataTypeId, Comment, Member, Total, FactValues. Total is the calculated sum.
<script type="text/html" id="list-planning-template">
<tr data-bind="mouseOverButton: $data">
<td style="text-align: center">
<button class="actionbutton actionbutton-item" data-bind="selectItem: $root.selectedItems, itemId: FactId"></button>
</td>
<td data-bind="text: DataTypeId" />
<td data-bind="text: Comment().Text" />
<!-- ko foreach: FactMembers -->
<td data-bind="text: Member().Code"></td>
<!-- /ko -->
<td data-bind="text: Total" />
<!-- ko foreach: FactValues -->
<td style="width: 50px" data-bind="text: Value"></td>
<!-- /ko -->
</tr>
I have been trying to add the Total property by extending the breeze entity object in the following way:
var FactCtor = function () {
this.Total = ko.computed({
read: function () {
var sum = 0;
if (this.FactValues) {
this.FactValues().forEach(function (fv) {
sum += fv.Value();
});
}
return sum;
},
deferEvaluation: true
}, this);
};
manager.metadataStore.registerEntityTypeCtor("Fact", FactCtor);
Essentially, what this code is supposed to do is to extend the entity by adding a knockout computed observable named Total with deferred evaluation. The function iterates through the breeze observable array FactValues and adds the values. I have been mucking about different versions of this code to no avail. Can anyone give me a hint on what is wrong with this code?
UPDATE:
We were not able to get the code posted in my previous post to work. We were eventually able to overcome the problem by using a custom binding with breeze. Here is the code:
ko.bindingHandlers.getFyTotal = {
update: function (element, valueAccessor) {
var sum = 0;
var fact = valueAccessor();
if (fact.FactValues()) {
fact.FactValues().forEach(function (fv) {
sum += parseFloat(fv.Value());
});
}
$(element).html(sum);
}
};
The custom binding is then referenced in the HTML code the following way:
<td data-bind="getFyTotal: $data" />
Hope this may help others.
REVISED VERSION:
We have updated the above code to take advantage of ko.utils functions:
ko.bindingHandlers.getFyTotal = {
update: function (element, valueAccessor) {
var sum = 0;
var fact = valueAccessor();
if (fact.FactValues()) {
ko.utils.arrayForEach(fact.FactValues(), function (fv) {
sum += parseFloat(fv.Value());
});
}
$(element).html(sum);
}
};
I modeled your code outside of Breeze and it's working:
http://jsfiddle.net/DazWilkin/yGZ7g/7/
I made a small tweak of adding a reference to FactValues (observableArray) on your constructor to overcome what - I believe - is the looping/this issue in JavaScript.
However, I haven't tried this in Breeze and wanted to do something similar. I was unable to get a similar function working and ultimately, created the totals during the 'then' processing of my executeQuery:
...manager.executeQuery(....).then(function(data) {
...
Fact.Total(FactValues()
.map(function(fv){ return fv.Value(); })
.reduce(function (total,curr) { return total+curr; });
...
}
I will try to get back to working on my version of this today and, if I find a better solution, I'll report back.

if else statement in Razor is not functioning

I am using an if else in Razor view to check for null value like this:
#foreach (var item in Model)
{
<tr id="#(item.ShopListID)">
<td class="shoptablename">#Html.DisplayFor(modelItem => item.Name)
</td>
<td class="shoptableamount">
#if (item.Amount == null)
{
Html.Display("--");
}
else
{
String.Format("{0:0.##}", item.Amount);
}
</td>
</tr>
}
However, no matter my model amount is null or having a value, the html rendered do not contain any value in the amount.
I wonder why this is happening. Any idea?
Thanks...
EDIT:
Decided to did it in controller:
// Function to return shop list food item amount
public string GetItemAmount(int fid)
{
string output = "";
// Select the item based on shoplistfoodid
var shopListFood = dbEntities.SHOPLISTFOODs.Single(s => s.ShopListFoodID == fid);
if (shopListFood.Amount == null)
{
output = "--";
}
else
{
output = String.Format("{0:0.##}", shopListFood.Amount);
}
return output;
}
and call at View like:
<td class="shoptableamount">
#Html.Action("GetItemAmount", "Shop", new { fid = item.ShopListFoodID })
</td>
You have to use the #()
#if (item.Amount == null)
{
#("--");
}
else
{
#String.Format("{0:0.##}", item.Amount)
}
As noted in the comments and other answers, the Html.Display is not for displaying strings, but for displaying data from the ViewData Dictionary or from a Model. Read http://msdn.microsoft.com/en-us/library/ee310174%28v=VS.98%29.aspx#Y0
I think you want to display "-----" if amount is null.
#foreach (var item in Model)
{
<tr id="#(item.ShopListID)">
<td class="shoptablename">#Html.DisplayFor(modelItem => item.Name)
</td>
<td class="shoptableamount">
#if (item.Amount == null)
{
#Html.Raw("--")
}
else
{
String.Format("{0:0.##}", item.Amount);
}
</td>
</tr>
}
That's because you are using the Display() method incorrectly. The overload you are using is Display(HtmlHelper, String). If you are looking for "--" to be the text, you should use something like:
#Html.Label("--");
There are actually two other ways to display text from a code block in razor besides the suggested #(""), using a <text> tag and it's shorthand #:
#{
#("--")
<text>--</text>
#:--
}
The code above will display -- three times.

Resources