I GET a HTML response from AJAX over cors and the response is a table. Each category has its title and sub elements. The title names vary quite a bit and are likely to change in the future. The sub elements in each title change almost on a daily basis, but the DOM structure doesn't.
Is there a way I could get rid of this if statement and replace it with code that isn't element specific? Some way of selecting DOM elements I'm not aware of?
Relevat JS
classifiedFilter: function( response ) {
var Classified = {
ClaAdministrative: [],
Paraeducator: [],
Clerical: [],
Custodial: [],
NonRep: [],
Maintenance: [],
ClaSubstitute: [],
Coaching: []
},
response = $(response).find("table tbody tr td").html();
$(response).find("#isHeadType").remove();
$(response).find("font:contains(Open to all)").parent().parent().remove();
//Filter each span title and classify sub items
$(response).find("span").parents("tr").each( function() {
//Find categories and separate by class
var rowtext = $(this).find("span").text(),
position = "";
position = rowtext.replace(/-/gi, "").replace(/\s/g, "");
$(this).nextAll("tr").addClass(position);
//Push content into Classified
((position === "Administrative") ? $(this).nextUntil(".Paraeducator").each( function() {
Classified.ClaAdministrative.push( $.trim( "<tr>" + $(this).html() + "</tr>" ) );
}) :
((position === "Paraeducator") ? $(this).nextUntil(".Clerical").each( function() {
Classified.Paraeducator.push( $.trim( "<tr>" + $(this).html() + "</tr>" ) );
}) :
((position === "Clerical") ? $(this).nextUntil(".Custodial").each( function() {
Classified.Clerical.push( $.trim( "<tr>" + $(this).html() + "</tr>" ) );
}) :
((position === "Custodial") ? $(this).nextUntil(".NonRep").each( function() {
Classified.Custodial.push( $.trim( "<tr>" + $(this).html() + "</tr>" ) );
}) :
((position === "NonRep") ? $(this).nextUntil(".Maintenance").each( function() {
Classified.NonRep.push( $.trim( "<tr>" + $(this).html() + "</tr>" ) );
}) :
((position === "Maintenance") ? $(this).nextUntil(".Substitute").each( function() {
Classified.Maintenance.push( $.trim( "<tr>" + $(this).html() + "</tr>" ) );
}) :
((position === "Substitute") ? $(this).nextUntil(".Coaching").each( function() {
Classified.ClaSubstitute.push( $.trim( "<tr>" + $(this).html() + "</tr>" ) );
}) :
((position === "Coaching") ? $(this).nextAll().each( function() {
Classified.Coaching.push( $.trim( "<tr>" + $(this).html() + "</tr>" ) );
}) : [] ) ) ) ) ) ) ) );
});
//remove title from array
Certificated.Elementary.shift();
Certificated.MiddleSchool.shift();
Certificated.HighSchool.shift();
Certificated.K12.shift();
Certificated.Substitute.shift();
}
Summarized HTML GET response (added spaces for visual aid)
<table border="0" cellspacing="0" cellpadding="0" style="MARGIN-TOP: 10px;">
<tr>
<td>
<font class="HeadTitle">External Positions: Open to all applicants.</font><br>
</td>
</tr>
<tr>
<td height="20" nowrap="nowrap">
<i><span id="ExternalJobs__ctl1_BargainGroup" class="BodyText">Administrative</span></i>
<br/><br/>
</td>
</tr>
<tr>
<td nowrap="nowrap" style="padding-left:20px;" class="BodyText">
<b><a href='jobs.aspx?id=3660&type=2&int=External'>Administrative Assistant I, Health Tech-Leave Replacement-2 hours - ME1214</a></b>
</td>
</tr>
<tr>
<td height="20" nowrap="nowrap">
<i><span id="ExternalJobs__ctl2_BargainGroup" class="BodyText">Paraeducator</span></i>
<br/><br/>
</td>
</tr>
<tr>
<td nowrap="nowrap" style="padding-left:20px;" class="BodyText">
<b><a href='jobs.aspx?id=3544&type=2&int=External'>Paraeducator, SpEd IP/ELL-6.5hours - MC1223</a></b>
</td>
</tr>
<tr>
<td nowrap="nowrap" style="padding-left:20px;" class="BodyText">
<b><a href='jobs.aspx?id=3603&type=2&int=External'>Special Ed Paraeducator, School Adjustment Program (SA-)-6.5 hours - MK1215</a></b>
</td>
</tr>
<tr>
<td height="20" nowrap="nowrap">
<i><span id="ExternalJobs__ctl3_BargainGroup" class="BodyText">Clerical</span></i>
<br/><br/>
</td>
</tr>
<tr>
<td nowrap="nowrap" style="padding-left:20px;" class="BodyText">
<b><a href='jobs.aspx?id=3481&type=2&int=External'>Admin Assistant IV-8 hours - IT1209</a></b>
</td>
</tr>
<tr>
<td height="20" nowrap="nowrap">
<i><span id="ExternalJobs__ctl5_BargainGroup" class="BodyText">Non-Rep</span></i>
<br/><br/>
</td>
</tr>
<tr>
<td nowrap="nowrap" style="padding-left:20px;" class="BodyText">
<b><a href='jobs.aspx?id=2732&type=2&int=External'>Licensed Practical Nurse (Pool position) - 2012LPNPool</a></b>
</td>
</tr>
<tr>
<td nowrap="nowrap" style="padding-left:20px;" class="BodyText">
<b><a href='jobs.aspx?id=3472&type=2&int=External'>Certified Occupational/Physical Therapist Assistant- POOL - COTA2012Pool</a></b>
</td>
</tr>
<tr>
<td height="20" nowrap="nowrap">
<i><span id="ExternalJobs__ctl7_BargainGroup" class="BodyText">Substitute</span></i>
<br/><br/>
</td>
</tr>
<tr>
<td nowrap="nowrap" style="padding-left:20px;" class="BodyText">
<b><a href='jobs.aspx?id=26&type=2&int=External'>Substitute Food Service Helpers - FSSub</a></b>
</td>
</tr>
<tr>
<td nowrap="nowrap" style="padding-left:20px;" class="BodyText">
<b><a href='jobs.aspx?id=28&type=2&int=External'>Substitute Custodians - MTSub</a></b>
</td>
</tr>
</table>
This seems equivalent to the core of your current code:
$(this).each( function() {
Classified[position].push( $.trim( "<tr>" + $(this).html() + "</tr>" ) );
});
[Edit] I don't see where you declare your arrays, you might actually need this:
$(this).each( function() {
Classified[position]=Classified[position]||[];
Classified[position].push( $.trim( "<tr>" + $(this).html() + "</tr>" ) );
});
[Update] Based on the comments, this loop updates position whenever it hits a span:
var position = "";
$(response).find("tr").each( function() {
var currentTR=$(this);
// catch span if any
var rowtext = currentTR.find("span").text().replace(/-/gi, "").replace(/\s/g, "");
if (rowtext) {
position = rowtext;
Classified[position]=[];
}
// Collect rows
Classified[position].push( "<tr>" + $.trim($(this).html()) + "</tr>" );
});
I think, you can use CSS class names in find function instead of tag names.
Related
I have a data in JSON format and I convert it to a HTML table. Now I want to
change the text from False to True if I check the checkbox. How can I do that?
Here is the code for creating the HTML table:
$.each(result, function (index, value) {
var Data = "<tr>" +
"<td class='' id='stdID' >" + value.StudentID + "</td>" +
"<td class='' id='stdRol'>" + value.RollNo + "</td>" +
"<td class='' id='stdName'>" + value.FirstName + "</td>" +
"<td class='cbx' value='1'><input type='checkbox' id='cc"+index+"'><span id='checkbox-value'> False</span></td>" +
"</tr>";
SetData.append(Data);
This is the result of this: output
To achieve what you require you need to use a delegated event handler, as you dynamically append the rows after the page has loaded, to hook to the change event of the checkboxes. Then you can set the text of the sibling span element based on the checked property. Something like this:
$('table').on('change', ':checkbox', function() {
$(this).next('span').text(this.checked);
});
span.checkbox-value { text-transform: capitalize; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table>
<tr>
<td class="stdID">value.StudentID</td>
<td class="stdRol">value.RollNo</td>
<td class="stdName">value.FirstName</td>
<td class="cbx" value="1">
<input type="checkbox" id="cc1">
<span class="checkbox-value">False</span>
</td>
</tr>
<tr>
<td class="stdID">value.StudentID</td>
<td class="stdRol">value.RollNo</td>
<td class="stdName">value.FirstName</td>
<td class="cbx" value="1">
<input type="checkbox" id="cc2">
<span class="checkbox-value">False</span>
</td>
</tr>
</table>
You should note that your loop is creating multiple elements which have the same id, which is invalid HTML. In the example above I've changed them to classes instead.
Another way around to achieve your desired output
$(document).on('change', '.changeStatus', function() {
var row = $(this).closest('tr');
if($(this). prop("checked") == true){
row.find('.changeValue').html('True');
} else {
row.find('.changeValue').html('False');
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
<tbody>
<tr>
<td>Id</td>
<td>Roll_no</td>
<td><input type="checkbox" class="changeStatus"></td>
<td class="changeValue">False</td>
</tr>
<tr>
<td>Id</td>
<td>Roll_no</td>
<td><input type="checkbox" class="changeStatus"></td>
<td class="changeValue">False</td>
</tr>
<tr>
<td>Id</td>
<td>Roll_no</td>
<td><input type="checkbox" class="changeStatus"></td>
<td class="changeValue">False</td>
</tr>
</tbody>
</table>
I have a div with the ID="ranking" and I'd like to put there some info of a JavaScript array with a table where every row has tow columns: one for dados[i][25] and other for dados[i][26].
My code is this:
function dadosRanking(dados){
document.getElementById("ranking").innerHTML += '<table class="table"><tr><td valign="middle" class="question" colspan=2><h1>RANKING (+ PONTOS)</h1></td></tr><tr><td>PONTOS</td><td>UTILIZADOR</td></tr>'
for(var i=1;i<6;i++)
{
document.getElementById("ranking").innerHTML += '<tr><td>' + dados[i][25] + '</td><td>' + dados[i][26] + '</td></tr>';
}
document.getElementById("ranking").innerHTML += '</table>';
}
The code I expect was this:
<table class="table">
<tr>
<td valign="middle" class="question" colspan=2>
<h1>RANKING (+ PONTOS)</h1>
</td>
</tr>
<tr>
<td>PONTOS</td>
<td>UTILIZADOR</td>
</tr>
<tr>
<td>
100
</td>
<td>
Username
</td>
</tr>
</table>
However, the HTML code script write is this:
<table class="table">
<tr>
<td valign="middle" class="question" colspan=2>
<h1>RANKING (+ PONTOS)</h1>
</td>
</tr>
<tr>
<td>PONTOS</td>
<td>UTILIZADOR</td>
</tr>
</table>
"100Username"
Everytime you update innerHTML the browser will parse it and render it, to do that it will also try to 'fix' your HTML. This can have unintended consequences. Instead of pushing to innerHTML with a partial table definition, collect the HTML in a separate value and push to innerHTML once.
function dadosRanking(dados){
var s = "";
s += '<table class="table"><tr><td valign="middle" class="question" colspan=2><h1>RANKING (+ PONTOS)</h1></td></tr><tr><td>PONTOS</td><td>UTILIZADOR</td></tr>'
for(var i=1;i<6;i++) {
s += '<tr><td>' + dados[i][25] + '</td><td>' + dados[i][26] + '</td></tr>';
}
s += '</table>';
document.getElementById("ranking").innerHTML += s;
}
After
document.getElementById("ranking").innerHTML += '<table class="table"><tr><td valign="middle" class="question" colspan=2><h1>RANKING (+ PONTOS)</h1></td></tr><tr><td>PONTOS</td><td>UTILIZADOR</td></tr>'
innerHTML becomes:
<table class="table">
<tr><td valign="middle" class="question" colspan=2><h1>RANKING (+ PONTOS)</h1></td></tr>
<tr><td>PONTOS</td><td>UTILIZADOR</td></tr>
</table>
Note that the table has been closed!
After
document.getElementById("ranking").innerHTML += '<tr><td>foo</td><td>bar</td></tr>';
innerHTML becomes
<table>..</table>
foobar
<tr> and <td> are not valid outside of a table context so they're removed.
After
document.getElementById("ranking").innerHTML += '</table>';
innerHTML doesn't change because </table> doesn't do anything, there is no table to close.
I have created a jquery function that allows me to click on the UP arrow and it swaps rows in a table. I have rank numbers in each row. But I can only get the clicked number to change. I want both numbers to swap. I know it is something with getting the value in abovecnt. I just can't figure out how to get that value of the row above. Right now it is just undefined.
http://jsfiddle.net/Thread7/2rmowem4/15/
$('.change-rank').click(function() {
var cnt = $(this).attr('cnt');
var direction = $(this).attr('data-direction'),
$original = $(this).closest("tr"),
$target = direction === "up" ? $original.prev() : $original.next();
if ( $target.length && direction === "up" ) {
$original.insertBefore($target);
abovecnt = $original.find('.ranky input[type="text"]').val();
$('#rank_' + cnt).val(cnt-1);
$('#rank_' + abovecnt).val(cnt);
alert('abovecnt=' + abovecnt + '|cnt=' + cnt);
}
else if( $target.length ) {
$original.insertAfter($target);
}
});
Note: I'll eventually want the down arrow to swap also, but right now just trying to get it to work.
I converted your cnt attributes to data attributes for this.
EDIT: updated JS snippet to #tripleb 's recommendation: before and after .. as opposed to doing inserts and changing values of the arrows.
Sample Code Snippet
$('.change-rank.up').click(function(ev) {
var $original = $(this).closest("tr"),
$target = $original.prev();
if ($target.length) {
var cnt = $original.data('cnt'),
targetcnt = $target.data("cnt");
if (targetcnt) {
$original.after($target);
alert(targetcnt);
}
}
});
$('.change-rank.down').click(function(ev) {
var $original = $(this).closest("tr"),
$target = $original.next();
if ($target.length) {
var cnt = $original.data('cnt'),
targetcnt = $target.data("cnt");
if (targetcnt) {
$original.before($target);
alert(targetcnt);
}
}
});
.change-rank.up:after {
content: attr(data-icon);
}
.change-rank.down:after {
content: attr(data-icon);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
<tr>
<td>Rank</td>
<td>Username</td>
</tr>
<tr data-cnt='1'>
<td>
1</td>
<td>Joey</td>
<td>
<input type='text' id='rank_1' class='ranky' value='1' />
</td>
</tr>
<tr data-cnt='2'>
<td>
2</td>
<td>Randy</td>
<td>
<input type='text' id='rank_2' class='ranky' value='2'>
</td>
</tr>
<tr data-cnt='3'>
<td>
3</td>
<td>Bobby</td>
<td>
<input type='text' id='rank_3' class='ranky' value='3' />
</td>
</tr>
<tr data-cnt='4'>
<td>
4</td>
<td>Jesse</td>
<td>
<input type='text' id='rank_4' class='ranky' value='4' />
</td>
</tr>
</table>
JsFiddle: Example
why not this:
if ( $target.length && direction === "up" ) {
$original.after($target)
}
else if( $target.length ) {
$original.before($target);
}
http://jsfiddle.net/2rmowem4/16/
I have a DOM with different nested divs and inputs (with values):
<div id ="div_id1">
<div id ="div_id2">
<table>
<tr>
<td>input 1:</td>
<td><input id="i1" type="text"/></td>
</tr>
<tr>
<td>input 2:</td>
<td><input id="i2" type="text"/></td>
</tr>
<tr>
<td>input 3:</td>
<td><input id="i3" type="text"/></td>
</tr>
</table>
<div id ="div_id3">
<table>
<tr>
<td>input 4:</td>
<td><input id="i4" type="text"/></td>
</tr>
<tr>
<td>input 5:</td>
<td><input id="i5" type="text"/></td>
</tr>
</table>
</div>
</div>
How to make XML string recursively according to this structure?
Like this:
<div_id1>
<div_id2>
<i1>value 1</i1>
<i2>value 2</i2>
<i3>value 3</i3>
<div_id3>
<i4>value 4</i4>
<i5>value 5</i5>
</div_id3>
</div_id2>
UPD:
I tried function like this:
function makeXml(nodes) {
var $result = $('<' + nodes.attr('id') + '>');
$.each(nodes, function(i, node) {
var nodeId = node.getAttribute('id');
var $el = $('<' + nodeId + '>').text($('#' + nodeId).val());
alert(nodeId + $('#' + nodeId).val());
$el.appendTo($result);
var $children = $(node).children();
if ($children.length > 0) {
makeXml($children).appendTo($el);
}
});
return $result;
};
But it does not work properly (does not correctly handle nested divs).
Does anyone have any solution?
One of the options (create a XML-string):
var str = '';
function makeXml(obj) {
var children = obj.children();
if (children.size() != 0) {
$.each(children, function(i, v) {
var $val = $(v), id = $val.attr('id');
if (typeof($val.attr('id')) !== "undefined") {
str += '<' + id + '>' + $('#' + id).val();
makeXml($val);
str += '</' + id + '>';
} else {
makeXml($val);
}
});
}
}
After an ajax call, results is returned in success, then:
var the_data = results;
var buildHTML = [];
buildHTML.push("<tr><td>Department</td><td>Count</td><td>Value</td>");
for (var i = 0; i < the_data.length; i++) {
buildHTML.push("<tr><td>" + the_data[i].department + "</td><td>" + the_data[i].count + "</td><td>£" + the_data[i].value + "</td>");
}
$('.portlet-content').empty().append("<table>" + buildHTML.join('</tr>') + "</table>");
Which builds something like:
<table>
<tr>
<td>
Department
</td>
<td>
Count
</td>
<td>
Value
</td>
</tr>
<tr>
<td>
Marketing
</td>
<td>
10
</td>
<td>
£100,000
</td>
</tr>
<tr>
<td>
Information Technology
</td>
<td>
20
</td>
<td>
£1,000,000
</td>
</tr>
</table>
I know how to add another final row at the bottom of this table, but in that row, I want to display totals, i.e. a total of the count and a total of the value, e.g:
<table>
<tr>
<td>
Department
</td>
<td>
Count
</td>
<td>
Value
</td>
</tr>
<tr>
<td>
Marketing
</td>
<td>
10
</td>
<td>
£100,000
</td>
</tr>
<tr>
<td>
Information Technology
</td>
<td>
20
</td>
<td>
£1,000,000
</td>
</tr>
<tr>
<td>
Total
</td>
<td>
30
</td>
<td>
£1,100,000
</td>
</tr>
</table>
How can this be done at clientside?
Here is a generic solution that will work for any table with a tfoot and tbody:
$("table tfoot td").each(function(columnIndex) {
var totalsElement = $(this);
if (totalsElement.hasClass("sumTotal")) {
var sum = 0.0;
totalsElement.parents("table").find("tbody tr").each(function() {
sum += parseFloat($(this).children("td").eq(columnIndex).html());
});
totalsElement.html(sum);
}
});
You need to mark the computed footer cells with "sumTotal" CSS class. To keep it simple I had to remove the pound characters from the table but it works:
http://jsfiddle.net/fRdpJ/47/
You could simply amend the for loop in your code to get the sums.
...
// vars for sum
var the_count = 0, the_sum = 0;
for (var i = 0; i < the_data.length; i++) {
the_count += the_data[i].count;
the_sum += the_data[i].value;
buildHTML.push("<tr><td>" + the_data[i].department + "</td><td>" + the_data[i].count + "</td><td>£" + the_data[i].value + "</td>");
}
buildHTML.push("<tr><td>Total</td><td>" + the_count + "</td><td>" + the_sum + "</td>");
...
add a class="Count" on the TD for which you want to calculate count and then calculate count using JQuery like this:
http://jsfiddle.net/sv2dg/13/