Use jQuery ID Selector with CSS - javascript

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

Related

Conditionally displaying React components with hover and timeouts

I ran into a tricky React layout problem. It's a simple enough problem, just hard to explain so I tried to be as explicit as possible. I have some data which maps individual components like this:
map => <TableRow name={props.name} actionOne={props.someAction} />
Name
Type
Show/Hide Controls
Buttons (hidden by default)
John Deere
Tractor
show/hide
<div style="hidden"><button id="actionOneButton"></div>
John Smith
Person
show/hide
<div style="hidden"><button id="actionOneButton"></div>
The control buttons are hidden by default. The idea here is to show the button tools only when the user dwells on a certain row OR if the user decides to have some of the control buttons permanently visible on certain rows
We need two things to happen:
When entering a table and hovering over a row, there is a 500msec delay, after which the action buttons only for that row appear. If at this point after that we move the cursor up or down to different rows within the, there is no delay, and the newly hovered rows reveal their corresponding button immediately and the previously shown button in the previous row is hidden immediately
When a user moves the cursor outside the table, there is a countdown of 500msec. During this time, a button that's last been displayed on a row, stays displayed. Once the timer is up, the row which last had a revealed button, now hides it. Think of it as "show on hover," but with a 500msec delay upon entering and exiting the table.
Almost done!
One caveat: clicking on show link will display the button in that row permanently, while the hide link returns the button to the original condition by hiding it. (We're back to #1)
Manually shown buttons stick around permanently until closed, at which point they behave the same as at the start.
Important note:
If the cursor exits the table and then hovers back inside the table before the "exit timer" ticks down:
Previously highlighted row displaying buttons remains visible while the cursor is outside the table; it is then hidden when the exit timeout of 500ms is reached.
Meanwhile, as the above is timing out and is about to disappear, the cursor which has now entered the table again initiates a 500ms count to show the hidden button of the row it happens to have re-entered at. At this point #1 times out and hides and if hovered over from inside the table, would appear instantly as per the first set of criteria in the beginning: any hidden button in a row instantly shows up if the "entry" 500ms gate is passed.
Questions
I have some loose ideas but what comes to mind in designing something like this so that all of the state and timeouts (is that even the way to go) are encapsulated in a maximum of two components - something like a table and rows?
How do I design this component functionality? Am I barking up the wrong tree here and can the show/hide be done by clever CSS?
I believe this could be a possible approach to a working solution. With some more tweaking, I think it can achieve the required behavior you outlined.
This captures the last element the cursor left the table on, from the list of rows, by using the mouse coordinate at the point of leaving the table. In the example the exited element will remain visible, but you can decide how to handle it.
[...table.children[0].children].forEach(tr => {
tr.classList.remove('exited');
if(evt.offsetY >= tr.offsetTop
&& evt.offsetY <= tr.offsetTop + tr.clientHeight
){
tr.classList.add('exited'); // in react you could instead set this element to state.
}
});
Hope it won't be an issue translating to JSX. You can keep a reference to the table's DOM element with refObject.
const table = document.getElementById("table");
let hoverTimer = 0;
table.addEventListener("mouseenter", () => {
clearTimeout(hoverTimer);
hoverTimer = setTimeout(() =>
table.classList.add('active'),
500
);
});
table.addEventListener("mouseleave", (evt) => {
[...table.children[0].children].forEach(tr => {
tr.classList.remove('exited');
if(evt.offsetY >= tr.offsetTop
&& evt.offsetY <= tr.offsetTop + tr.clientHeight
){
tr.classList.add('exited');
}
});
clearTimeout(hoverTimer);
hoverTimer = setTimeout(() =>
table.classList.remove('active'),
500
);
});
tr.table-row button.action-btn {
pointer-events: none;
}
table.active tr.table-row:hover button.action-btn {
pointer-events: auto;
}
tr.table-row {
opacity: 0;
transition: opacity 0.5s;
}
table.active tr.table-row:hover {
opacity: 1;
}
tr.exited {
opacity: 1;
}
<table id="table">
<tr class="table-row"><td><button class="action-btn">click me!</button></td></tr>
<tr class="table-row"><td><button class="action-btn">click me!</button></td></tr>
<tr class="table-row"><td><button class="action-btn">click me!</button></td></tr>
<tr class="table-row"><td><button class="action-btn">click me!</button></td></tr>
<tr class="table-row"><td><button class="action-btn">click me!</button></td></tr>
<tr class="table-row"><td><button class="action-btn">click me!</button></td></tr>
<tr class="table-row"><td><button class="action-btn">click me!</button></td></tr>
<tr class="table-row"><td><button class="action-btn">click me!</button></td></tr>
<tr class="table-row"><td><button class="action-btn">click me!</button></td></tr>
<tr class="table-row"><td><button class="action-btn">click me!</button></td></tr>
</table>
I would go about this the following way
Table States:
lastHovered - the id of the last hovered row (or null)
hoverTimerId - the timer id of the current timer
hoverRowId - the row id of the current timer
Row Props:
isLastHovered - boolean, true when this is the last shown prop
Row State:
alwaysShow - boolean, true when the always show controls button is selected
Hover Event for rows / outside the table
//can be called with null for outside hover or rowId for row hover
onRowHover = (rowId) => {
if(rowId === hoverRowId)
return
if(hoverTimerId !== null)
clearTimeout(hoverTimerId)
const timerId = setTimeout(() => {
setLastHovered(rowId)
}, 500)
setHoverTimerId(timerId)
setHoverRowId(rowId)
}
Finally, make sure the controlls are shown if the isLastHovered prop is true, or the always show state is true.
(The isLastHovered state is controlled by the show/hide button| in the row)

jQuery append and remove not working with dynamically columns

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');
}
});

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');
}

target the parent row of a particular cell

I have a table with a list of records. each row has class "list_request" and has a cell of class "record_approval":
<table>
<tr>
<th>name</th><th>date</th><th>id</th><th>group</th><th>approval</th>
<tr class="list_request">
<td>Frank</td><td>2012-2-15</td><td>01</td><td>Account</td><td class="record_approval">Dave Ellis</td>
</tr>
<tr class="list_request">
<td>Ellen</td><td>2012-2-19</td><td>04</td><td>Admin</td><td class="record_approval">Susan Peters</td>
</tr>
<tr class="list_request">
<td>Michael</td><td>2012-2-26</td><td>06</td><td>Admin</td><td class="record_approval"></td>
</tr>
I'd like to construct a javascript function that checks whether or not "record_approval" has a value (which value is unimportant), and if so, change the css color value for that row. Essentially, the approved records should have a different color than the unapproved ones.
something like...
function check_approval(){
var checkrow = document.querySelectorAll( "tr.request_list" )
var checkcell = document.querySelectorAll( "td.record_approval" )
for (i=0;i<checkcell.length;i++){
if (!checkcell.value){
this.parentNode.style.color = "ff9900";
}
else{
}
}
is this essentially the wrong approach?
Mistakes I found:
Unclosed for loop (missing closing })
You're looking for class request_list, but on your html it's list_request
You should be using checkcell[i] instead of checkcell inside your loop
Your color hex value should begin with a #.
There's no need to get all rows and cells from an event listener
It's unclear when you want that function to run. Should it respond to an event?
Also, I'd set a new css class on the row, instead of setting the color directly.
Apparently, you're looking for this:
var checkcell = document.querySelectorAll( "td.record_approval" );
for (i=0;i<checkcell.length;i++){
if (checkcell[i].innerHTML){
checkcell[i].parentNode.style.color = "#ff9900";
}
}
http://jsbin.com/anadij/1/edit
checkcell is an array of elements. you'll want to loop through them, accessing 'checkcell[i]' instead of checkcell.value.
your hex color should be defined with a "#" preceding ff9900
your for loop isn't closed properly
basically update it s.t.
if (!checkcell[i].value){
checkcell[i].parentNode.style.color = "#ff9900";
} else{
}

Categories