jQuery append and remove not working with dynamically columns - javascript

I am working with Ajax and jQuery, I am working on sorting (without data tables), I am getting correct result but just want to display sorting icons (up, down), I want whenever I click on any column (name or symbol) for sort then "down" icon should display and after click on "down" icon should replace with "up" and whenever I click on another column both icons should remove and display on another
column for sort like previous. How can I do this ? I tried with following code but icons appending (showing multiple times), where I am wrong?
Here is my html:
<table border='1' width='100%' style='border-collapse: collapse;' id='postsList'>
<thead>
<tr>
<th>S.no</th>
<th class="column_sort" id="name" data-order="desc" href="#">Title</th>
<th class="column_sort" id="symbol" data-order="desc" href="#">Symbol</th>
</tr>
</thead>
<tbody></tbody>
</table>
And here is my script code:
$(document).ready(function(){
var timesClicked = 0;
$(document).on('click', '.column_sort', function(event){
event.preventDefault();
var column_name = $(this).attr("id");
timesClicked++;
if (timesClicked % 2 == 1) { // after first click(even clicks)
$('#'+column_name+'').append('<img src="<?=base_url()?>/assets/img/DownArrow.png"/>');
$('#'+column_name+'').remove('<img src="<?=base_url()?>/assets/img/UpArrow.png"/>');
var order = "ASC";
}else{
var order = "DESC"; // after second click(odd clicks)
$('#'+column_name+'').remove('<img src="<?=base_url()?>/assets/img/DownArrow.png"/>');
$('#'+column_name+'').append('<img src="<?=base_url()?>/assets/img/UpArrow.png"/>');
};
var arrow = '';
var PageNumber= $("#pagination").find("strong").html();
$(".column_sort").removeClass("active");
$.ajax({
url:'<?=base_url()?>/Main/fetch_details/',
method:"POST",
data:{column_name:column_name, order:order ,PageNumber:PageNumber},
success:function(data) {
$("#postsList tr:not(:first)").remove();
$("#postsList2").show();
$('#'+column_name+'').addClass('active');
return false;
}
})
});
});

If you check your browser's devtools console, I think you will see errors.
If you check the docs for .remove(), it removes the matched element - in your case, it is trying to remove the whole <th>. If you pass a parameter, it should be a selector (not HTML), and it will filter the matched elements, not find nested elements. Because you are passing HTML, the .remove() call is generating an error and failing, so the img is never removed. Next time you click, a new one is added to the one that is already there.
So you really want something like:
$('#' + column_name + ' img').remove();
This will match the <img> element inside the <th>, and remove it.
Next problem - the order you add and remove elements is important. Eg: for the first click, you add a down arrow. If we now do the removal, the selector will match any image. That means we'll remove both the old and the newly added images!
So we need to take care to 1) Remove the old image first; 2) Add a new image.
Here's a working snippet - click the Run button to see it in action. I don't have your images of course, so instead of <img> elements I used <span>s, but the idea is exactly the same.
I also removed your AJAX code as that is not relevant to the problem.
$(document).ready(function(){
var timesClicked = 0;
$(document).on('click', '.column_sort', function(event){
event.preventDefault();
var column_name = $(this).attr("id");
timesClicked++;
if (timesClicked % 2 == 1) {
$('#' + column_name + ' span').remove();
$('#' + column_name).append('<span> v</span>');
} else {
$('#' + column_name + ' span').remove();
$('#' + column_name).append('<span> ^</span>');
};
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table border='1' width='100%' style='border-collapse: collapse;' id='postsList'>
<thead>
<tr>
<th>S.no</th>
<th class="column_sort" id="name" data-order="desc" href="#">Title</th>
<th class="column_sort" id="symbol" data-order="desc" href="#">Symbol</th>
</tr>
</thead>
<tbody></tbody>
</table>
PS: as an alternative to adding and removing elements on every click, it might be a neater solution to simply toggle visibility of elements already on the page. Eg both arrow images are already on the page on page load, but with a "hidden" class. Every click then just toggles that class on/off. Maybe something like:
$('#' + column_name + ' img').toggleClass('hidden');

How you display the arrow icons is up to you, for my example I simply used html entities. Wrap the up and down arrows into separate tags (span in my example) and include those within the TH tags for each column header.
<th class="column_sort" id="name" data-order="desc" href="#">
Title
<span>↑</span><span>↓</span>
</th>
Hide all the spans by default and we'll target the others specifically by toggling between two other classes we'll add to the TH that already has column_sort class.
.column_sort{cursor:pointer}
.column_sort span{display:none;}
.sort_asc span:first-child{display:inline;}
.sort_desc span:nth-child(2){display:inline;}
Then for the javascript:
$(document).on('click', '.column_sort', function(event){
var $x = $(event.target);
var ascending = $x.hasClass('sort_asc') ? true : false;
// Remove arrows from any columns currently displaying them
$('.column_sort.sort_asc').removeClass('sort_asc');
$('.column_sort.sort_desc').removeClass('sort_desc');
// Show the appropriate arrow
if (ascending){
$x.addClass('sort_desc');
}else{
$x.addClass('sort_asc');
}
});
https://jsfiddle.net/176hj8s0/
Since you already have logic in place to handle ascend and descend order, you can just piggyback off that to determine which class is added.

You can also use fontawesome icons instead of img for display of up and down arrows. Here's a working example of how I do:
Step 1. Use tag after column name
<tr>
<th>S.no</th>
<th class="column_sort" id="name" data-order="desc" href="#">
Title <i class="fas fa-angle-down rotate-icon pr-10"></i>
</th>
<th class="column_sort" id="symbol" data-order="desc" href="#">
Symbol <i class="fas fa-angle-down rotate-icon pr-10"></i>
</th>
2.Jquery : First check which column is clicked and find class of icon tag and toggle it.
<script type="text/javascript">
$(document).on('click', '.column_sort', function(event) {
event.preventDefault();
if ($(this).find(".fas").hasClass('fa-angle-down')) {
$(this).find(".fas").removeClass('fa-angle-down');
$(this).find(".fas").addClass('fa-angle-up');
} else {
$(this).find(".fas").removeClass('fa-angle-up');
$(this).find(".fas").addClass('fa-angle-down');
}
});

Related

Showing Hidden Row in Table

I am using some code based on the following JSFiddle. The intention is to show more information when the user clicks the "Show Extra" link.
The problem that I'm having is that when the link is clicked on all but the bottom row of the table the hidden element is shown briefly and then closes.
I am populating my table using template strings in javascript. Here is the code that I use to add rows to the table:
this.addRecordToTable = function(bet, index, id){
console.log(index);
console.log($.data(bet));
var butId = id.toString();
if (bet.bookies == null){
bet.bookies = "";
}
if (bet.bet == null){
bet.bet = "";
}
var newRow = `
<tr>
<td>${bet.date}</td>
<td>${bet.bookies}</td>
<td>${bet.profit}</td>
<td><button id=${butId}>Delete</button></td>
<td>Show Extra</td>
</tr>
<tr>
<td colspan=\"5\">
<div id=\"extra_${index}\" style=\"display: none;\">
<br>hidden row
<br>hidden row
<br>hidden row
</div>
</td>
</tr>
`
console.log(newRow);
console.log("#"+butId);
$(newRow).appendTo($("#betTable"));
$("#"+butId).click(
function()
{
if (window.confirm("Are you sure you want to delete this record?"))
{
var rec = new Records();
rec.removeRecordAt(index);
$("#betTable tbody").remove();
var c = new Controller();
c.init();
}
});
$("a[id^=show_]").click(function(event) {
$("#extra_" + $(this).attr('id').substr(5)).slideToggle("slow");
event.preventDefault();
});
}
EDIT:
I had to change $("a[id^=show_]").click to $("a[id=show_"+index).click..., as the event handler was being added to each element every time I added a new element. Thanks to #freedomn-m.
This code:
$("a[id^=show_]")
adds a new event handler to every existing link as well as the new one as it's not ID/context specific so all the show a's match the selector.
You need to add the context (newRow) or use the existing variable(s) as part of the loop that are already defined, eg:
$("a[id^=show_]", newRow)
$("a#show_" + index)
(or any other variation that works).
An alternative would be to use even delegation for the dynamically added elements, eg:
$(document).on("click", "a[id^=show_]", function...
in which case you'd only need to define/call the event once and it would be fired for new elements (ie put that outside the new row loop).

Use jQuery ID Selector with CSS

I'm actually creating a list with streamers and checking if they're online, if so they'll get a green background color.
Now I want to create an additional list next to my "team list" which includes every streamer.
For this I'm trying to use the same method like the one I'm using for the background color.
$(".".concat(user)).css("background-color","lightgrey");
(to color every background color for the streamers)
But now I want to just hide the streamers in one list and not everywhere.
So I can't use this:
$(".".concat(user)).css("display", "none");
(would hide every offline streamer in every list)
I already tried to apply the ID but actually I don't know how.
If I use this:
$("#online".concat(user)).css("display", "none");
nothing happens.
(I named my ID online)
<tr class="header" id ="online">
(I already tried to apply the id to a new , to the and now to the but nothing works)
TL;DR:
I want to hide offline streamers in a new list but I can't use the same ID selector as I used before. How can I do it?
Not much to start with, but if you have a structure like
<table>
<tr class="header Peter" id ="onlinePeter">
<td>Peter</td>
</tr>
<tr class="header John" id ="onlineJohn">
<td>John</td>
</tr>
<tr class="header Michael" id ="onlineMichael">
<td>Michael</td>
</tr>
<tr class="header Bob" id ="onlineBob">
<td>Bob</td>
</tr>
<tr class="header Daniel" id ="onlineDaniel">
<td>Daniel</td>
</tr>
</table>
and a script like
var user = "John";
$("#online".concat(user)).css("display", "none");
user = "Daniel"
$(".".concat(user)).css("background","lightgrey");
It works. the row that contains John disappears
On the other piece of code where you try to change the background color, you are calling an element with the class = user, but the HTML you provided only has the class "header", once the class is added, the background changes as well.
I looked at the jsfiddle you linked and got a better understanding of what is happening.
The server returns an empty stream all the time, so the code never goes into the "true" part of the statement. Furthermore, in the "false" part of the statement, the code changes the background color and then hides the table cell.
function colorize(user){
$.getJSON('https://api.twitch.tv/kraken/streams/'+user, function(channel) {
/*
* Stream always returns as null
*/
console.log(channel["stream"]); // returns null in all tests
var data = channel["stream"]; // data == null
var boolAnswer = ((typeof(data) !== 'undefined') && (data !== null));
console.log(data);
if ( boolAnswer === true) {
$( ".".concat(user) ).css("background-color", "lightgreen");
/*
* boolAnswer is always null, so this piece is skipped all the time
*/
}
else if ( boolAnswer === false){
/*
* First it changes the color and then it hides it
*/
$(".".concat(user)).css("background-color","lightgrey");
$(".".concat(user)).css("display", "none");
}
}).success(function(response){
console.log(response);
});
}
colorize('jankos'); //hides the cell of jankos
colorize(); // doesn't do anything
if you comment the line that says
$(".".concat(user)).css("display", "none");
colorize('jankos'); //changes the color of the cell of jankos
colorize() // still doesn't do anything

Jquery nested div datatable click event

This is my first post as I usually find answers (or similar ones) to my questions easily via Google and StackExchange sites. However, I've tried researching various methods, but I am not finding one that meets what I am trying to do. Hopefully someone smarter than me can help me figure this out.
My main page has a "InitiativeContainer" DIV. This DIV loads content into sub DIV containers ListDetails and InitiativeDetails. These sub containers are separate pages loaded into the sub DIVs so that the entire main page is not reloaded, only these content containers. The mainpage loads with the ListDetails DIV populated and is a seperate page with a DataTable named tblDetails. I want to grab the ID of the row that is clicked on in the Datatable, and return that ID as a variable to the parent page so that it can be passed to the InitiativeDetails page.
Right now, I can achieve an alert with getKeyValue, but only after 2 clicks. The 1st click does nothing, but the second and following clicks provide the ID in an alert. The 2 clicks is not user friendly and has to be corrected. It is as if the ListDetails container is not being "initialized" or the "focus" set and the first click initializes/sets the focus of the DIV and the second click does what it is supposed to. Code Below:
Main Page snippet:
<div class="InitiativeContainer">
<div id="ListDetails"></div>
<div id="InitiativeDetails"></div>
</div>
<script type="text/javascript">
$(document).ready(function() {
ListDetails.onload=ListLoad();
});/*End (document).ready*/
</script>
<script>
function ListLoad() {
var urlListDetails = './cfm/Initiative_List.cfm';
var ListDetails = $('#ListDetails');
$.ajax({
beforeSend: function() {
ListDetails.html('<b>Loading...</b>');
},
success: function(html) {
ListDetails.html(html);
},
url: urlListDetails
}); /*End Ajax*/
}; /*End ListLoad*/
ListLoad();
function DetailLoad(InitiativeID) {
var InitiativeID = 1
var urlInitiativeDetails = './cfm/Initiative_Info.cfm?InitiativeID=' + InitiativeID;
var InitiativeDetails = $('#InitiativeDetails');
$.ajax({
beforeSend: function() {
InitiativeDetails.html('<b>Loading...</b>');
},
success: function(html) {
InitiativeDetails.html(html);
},
url: urlInitiativeDetails
}); /*End Ajax*/
} /*End DetailsLoad*/
function getKeyValue(key){
var keyValue = key
alert('key Value: '+keyValue)
}
$('#ListDetails').on('click',function(event) {
// Get project_key
$('#tblDetail tbody tr').on('click',function(event){
var k2 = $(this).find('td').first().text();
event.stopPropagation();
getKeyValue(k2);
return false;
});
return false;
});
</script>
Initiative_List.cfm page Snippet:
<div id="ListDetails" align="center" style="width:100%;">
<table id="tblDetail" class="title display compact cell-border dataTable_pointer" cellpadding="0" cellspacing="0" border="0">
<thead>
<tr>
<th>ID</th>
<th>Prospect</th>
<th>Status</th>
<th>ClientType</th>
<th>Effective</th>
<th>Approved</th>
<th>Consultant</th>
<th>Audit Request</th>
<th>Completed</th>
</tr>
</thead>
<tbody>
<cfoutput query="qryListDetails">
<tr>
<td>#qryListDetails.ID#</td>
<td>#qryListDetails.Prospect#</td>
<td>#qryListDetails.ProspectStatus#</td>
<td>#qryListDetails.ClientType#</td>
<td>#dateFormat(qryListDetails.EffectiveDate,"yyyy-mm-dd")#</td>
<td>#qryListDetails.Approved#</td>
<td>#qryListDetails.Consultant#</td>
<td>#dateFormat(qryListDetails.AuditRequestDate,"yyyy-mm-dd")#</td>
<td>#qryListDetails.Completed#</td>
</tr>
</cfoutput>
</tbody>
</table>
</div>
Is the issue that I have a nested click event inside of a click event? If so how could I handle this better? I am looking to understand what I am doing wrong in addition to a better code solution. Thank you in advance.
The #tblDetail tbody tr click handler should be defined outside of your ListDetails click handler. That is likely causing the click-twice issues.
I don't see what the ListDetails handler is supposed to be doing, maybe we can just omit that and have the end of your code snippet look something like this:
function getKeyValue(key){
var keyValue = key
alert('key Value: '+keyValue)
}
$('#ListDetails').on("click", "#tblDetail tbody tr", function(event) {
var k2 = $(this).find('td').first().text();
event.stopPropagation();
getKeyValue(k2);
return false;
});
</script>
It seems you were on the right track, the nesting of click handlers caused the inner handler to be defined only after the outer click handler had fired. After the first click, the inner handler starts working.

Fade out Columns in HTML-Table with jQuery: Why is .fadeTo() so slow?

I want to fade out all cells in a column of my HTML-table when I click on a button in the Header of this col. For that I run the following JavaScript:
...
myDOMElement.find(".headerIcon").bind("click", function(event){
var colo = $(event.target).parent().attr("id"); // colNo is stored as Icons id
myDOMElement.find(".myTable").find("tr").find("#"+colo) // each tr has an id according to its colNumber
.each(function(index) {
$(this).fadeTo(0,0.2);
}
});
});
This works as desired but is relative slow even on tables with only 200 rows.
Is there a better (faster) way to do this?
"#"+colo is (must be!) a unique id. No reason for the cascaded finds - and if not, you are facing other problems:
...
myDOMElement.find(".headerIcon").bind("click", function(event){
var colo = $(event.target).parent().attr("id"); // colNo is stored as Icons id
$("#"+colo).fadeTo(0,0.2);
});
});
[edit]
As per the comments, in order to fade out Columns, the id must better hold information about row and column and will thus be unique per cell:
<tr>
<td id="1.1">scheme is <col>.<row></td>
<td id="2.1">
...
<tr>
<td id="1.2">
<td id="2.2">
...
...
myDOMElement.find(".headerIcon").bind("click", function(event){
var roco= $(event.target).parent().attr("id");
var col = roco.split('.')[0];
var row = roco.split('.')[1];
// now search all TD#s which have the clicked col (1.~) as a beginning of their ID
myDOMElement.find("td[id^='" + col + ".']").each(function(index) {
this.fadeTo(0,0.2);
});
});
see also jQuery Attribute selector
Since I dont need the animation provided by .fadeOut() I fond a faster way to do this:
myDOMElement.find(".myTable").find("tr").find("#"+colo).css({opacity:0.2});

Trying to remove a child html element with javascript

I have 3 tables in my boostrap tab. Each tab as a table. The rows of this table is dynamically generated with csharp asp.net code. Right I Want a scenario were if a user click on the row of the first table, the clicked role of the first table get remove from the first table and is added to the rows of the second table.
My challenge as been getting to remove the row after the onClick process.
<tbody>
<tr id="kayode#yahoo.com">
<td> kayode <a class="chat" connectionid="135976e6-799b-4cda-a764-a00f7110d515"
data-parentid="kayode#yahoo.com"
href="/Visitor/StartChat?threadid=3&email=kayode%40yahoo.com"
operatorid="1" target="_blank" threadid="3">chat</a></td>
<td>271.0.0.1</td>
<td>Active</td>
<td></td>
<td>9/13/2014</td>
<td>04:15:18</td>
<td>02:52:55</td>
<td>271.0.0.1</td>
</tr>
</tbody>
My javascript code which I am trying to use to remove the row after the Click event.
function updateWaitingState(sender) {
var parentid = $(sender).attr("data-parentid");
//alert(parentid);
//we are going to remove the role from this field
var element = document.getElementById(parentid);
element.parentNode.removeChild(element); //This line is a problem says
//document.querySelector("tablebody4 first").appendChild(element);
console.log(element);
}
This is untested, but I imagine jQuery will greatly reduce your headache here:
function updateWaitingState(sender) {
var parentId = $(sender).attr("data-parentid");
$('#' + parentId).appendTo('.tablebody4:first');
}
You may need to adjust the selector in the appendTo function, as it was a guess on my part.
function updateWaitingState(sender) {
var parentid = $(sender).attr("data-parentid");
var element = document.getElementById(parentid);
$(element).appendTo('.tablebody2:first');
}

Categories