JQuery disable table row toggle when one row already toggled - javascript

I have a table or articles and a toggle on each row that displays the child row content. In the child row I also display Disqus comments. This all works fine but I do not want multiple rows opened up all at once and multiple Disqus comments loading, slowing down my page.
I want to disable all toggle buttons when one toggle is activated. Each toggle link (class option_toggle) and the row it's on has a unique ID. See below. How can I accomplish this via JQuery?
//Hide main article table's options row
$(document).ready(function() {
$(".option_toggle").click(function(e) {
e.preventDefault();
aid = $(this).attr('id');
//Determine if we are showing the comments or hiding the comments
is_hidden = $(this).parent().parent().next(".options_row").is( ":hidden" );
if(is_hidden)
{
disqus_container = '#disqus_container_' + aid;
jQuery('<div id="disqus_thread"></div>').insertBefore(disqus_container);
$.ajax({
type: 'POST',
url: 'http://www.example.com/disqus',
data: {'msmm_tn' : '12d406df3c8b2e178893e2c146d318e5', 'aid' : aid},
dataType: 'json',
success : function(data) {
if (data)
{
$('#disqus_container_' + aid).html(data.script);
DISQUS.reset({
reload: true,
config: function () {
this.page.url = 'http://www.example.com/#!'+ aid;
this.page.remote_auth_s3 = data.payload;
this.page.identifier = aid;
this.page.api_key = "cULB96iURBu1pZOtLOOSVlVgBj10SY9ctXWiv0eiQdzhdxqBq9UgmVr5SeSiaFiP";
}
});
}
}
});
}
else
{
//Remove the comments
$('#disqus_container_' + aid).prev('#disqus_thread').remove();
$('#disqus_container_' + aid).html('');
}
$(this).parent().parent().next(".options_row").toggle("fast");
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<tbody>
<tr class="main_row" data-id="ROWID428272">
<td class="bkgcol-sunflower wht-border">
<td>
<a id="428272" class="option_toggle" href="#" title="Ratings/Comments">
</td>
<td class="key-title dark unpadded">
<td class="artcl_info text-center">Scitech</td>
<td class="text-center" style="width:10px">
<td class="text-center">
</tr>
<tr class="options_row" style="display: table-row;">
<td colspan="6">
<div class="row article_options">
<div class="row comments_row">
<div id="comments" class="col-md-12">
<div class="text-center article_title top_pad" style="width: 100%;">Comment on This Article</div>
<div id="disqus_thread">
<div id="disqus_container_428272">
</div>
</div>
</td>
</tr>
<tr class="main_row" data-id="ROWID427694">

I want to disable all toggle buttons when one toggle is activated.
$(".option_toggle").click(function(e) {
e.preventDefault();
// Remove click event handler defined above, and add a new one which prevents
// the click from doing anything
$(".option_toggle").off('click').on('click', function(e) {
e.preventDefault();
});
aid = $(this).attr('id');
// Continue with rest of your code ...
});
But is this really what you want? It means once you click a toggle, you cannot click any others. It also means all other toggles still look like links, maybe you should update styling to indicate they are disabled or something like that, eg add a disabled class and style that:
Javascript:
$(".option_toggle").addClass('disabled-link');
CSS:
a.disabled-link {
cursor: default;
color: #666;
text-decoration: none;
}

Related

Dynamically change jquery contextmenu

I'm using this jquery plugin. The instantiation of the menu looks like this:
$.contextMenu({
selector:'.disposition-menu',
zIndex: 120,
callback: function(key, options) {
var stepID = $(this).closest('.card').attr("id").substring(5);
handle_disposition(key,stepID);
},
items: {
"pin": {name: "Pin to top"},
"unpin": {name:"Unpin"},
"complete": {name: "Mark step completed"},
"remove": {name: "Remove step from Map"},
},
events: {
show: function(){}, //this is where I'm lost
hide: function(){} //this is where I'm lost
},
trigger: 'hover'
});
The 'handle disposition' function interacts with php and the database to record the '.card' as pinned or unpinned in the database so that it appears properly when the page is reloaded. The HTML is a bootstrap 4 card like this:
<div class="card" >
<div class="card-header ">
<table class="title-table">
<tr>
<td>...</td>
<td>...</td>
<td>...</td>
<td class="disposition-menu">&vellip;</td>
</tr>
</table>
</div>
<div class="card-body">
...{body content}
</div>
</div>
What I am trying to do is toggle between the pin and unpin menu items. Only one of these should appear on the menu at a time. If the item is already "pinned" (i.e. flagged in database, and represented by a data attribute in the '.card' html) then "Unpin" should appear...and vice versa. Similarly as soon as the "Pin..." is clicked on the menu, the menu should immediately be changed to hide the "Pin" item and expose the "Unpin" item and vice versa
I've looked at the documentation for the plugin, but I'm a bit of a newbie when it comes to using functions after the keys with colons (eg selector: ) and callbacks. The plugin apparently has a "visible:" key, and also "show:" and "hide:" keys (used as per this issue, but I'm at a loss as to how to string these elements together to accomplish my objective.
Use build:
https://swisnl.github.io/jQuery-contextMenu/docs.html#build
If the build callback is found at registration, the menu is not built
right away. The menu creation is delayed to the point where the menu
is actually called to show.
$.contextMenu({
selector: ".menu",
build: function($trigger) {
var options = {
callback: function(key, options) {
var m = "clicked: " + key;
alert(m);
},
items: {}
};
if ($trigger.hasClass('pin')) {
options.items.unpin = {name: "unpin"};
} else {
options.items.pin = {name: "pin"};
}
return options;
}
});
.menu{
width: 100px;
padding: 10px;
background: red;
margin: 10px;
color: #FFF;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/jquery-contextmenu/2.9.0/jquery.contextMenu.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-contextmenu/2.9.0/jquery.contextMenu.min.js"></script>
<div class="menu pin">Pin</div>
<div class="menu">Unpin</div>
Example on demand:
https://swisnl.github.io/jQuery-contextMenu/demo/dynamic-create.html
Edit:
$.contextMenu({
selector: ".disposition-menu",
build: function($trigger) {
var options = {
callback: function(key, options) {
if(key == "pin")
$trigger.removeClass("unpin").addClass("pin");
else if(key == "unpin")
$trigger.removeClass("pin").addClass("unpin");
},
items: {}
};
if ($trigger.hasClass('pin')) {
options.items.unpin = {name: "unpin"};
} else {
options.items.pin = {name: "pin"};
}
return options;
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/jquery-contextmenu/2.9.0/jquery.contextMenu.css" rel="stylesheet"/>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-contextmenu/2.9.0/jquery.contextMenu.min.js"></script>
<div class="card" >
<div class="card-header ">
<table class="title-table">
<tr>
<td>...</td>
<td>...</td>
<td>...</td>
<td class="disposition-menu">&vellip;</td>
</tr>
</table>
</div>
<div class="card-body">
...{body content}
</div>
</div>
Here's how I solved the problem of "menu item swapping". Thanks to #ahed-kabalan for pointing me in the right direction.
The HTML didn't change from my question posted above. Here it is again for convenience:
<div class="card" >
<div class="card-header ">
<table class="title-table">
<tr>
<td>...</td>
<td>...</td>
<td>...</td>
<td class="disposition-menu">&vellip;</td>
</tr>
</table>
</div>
<div class="card-body">
...{body content}
</div>
</div>
The JS was modified to trigger a callback when the specific menu item was clicked and uses the visible key. This solution includes menu items that are modified when clicked and those that aren't affected. The menu appears when on hover, and the callbacks are only triggered on menu item selection. The unpin item is set to visible: false as a default - i.e. only the pin option will appear in the menu initially. Since build is really focused on building an entirely new menu, it wasn't necessary in my case. The JS now looks like this:
$.contextMenu({
selector:'.disposition-menu',
zIndex: 120,
callback: function(key, options) {
var stepID = $(this).closest('.card').attr("id").substring(5);
alert(stepID);
handle_disposition(key,stepID);
},
items: {
"pin": {name: "Pin to top",
callback: function(key, opt) {
opt.items['pin'].visible = false;
opt.items['unpin'].visible = true;
}
},
"unpin": {name:"Unpin",
callback: function(key, opt) {
opt.items['pin'].visible = true;
opt.items['unpin'].visible = false;
}
},
"complete": {name: "Mark step completed"},
"remove": {name: "Remove step from Map"}
},
trigger: 'hover'
});
Hope others will find this useful!

Track all elements on page

I'm attempting to track events for all UI elements on a page. The page contains dynamically generated content and various frameworks / libraries. Initially I tracked elements through creating a css class "track" , then adding style "track" to tracked elements. elements are then tracked using :
$('.track').on('click', function() {
console.log('Div clicked' + this.id);
console.log(window.location.href);
console.log(new Date().getTime());
});
As content can be dynamically generated I wanted a method to track these elements also. So tried this using wildcard jQuery operator.
In this fiddle : https://jsfiddle.net/xx68trhg/37/ I'm attempting to track all elements using the jquery '*' selector.
Using jQuery '*' selector appears to fire the event for all elements of given type.
So for this case if is clicked all the click event is fired for all divs. But id is just available for div being clicked.
For the th element the click event is fired twice , what is reason for this ?
Can the source be modified that event is fired for just currently selected event ?
fiddle src :
$(document).ready(function() {
$('*').each(function(i, ele) {
$(this).addClass("tracked");
});
$('.tracked').on('click', function() {
console.log('Div clicked' + this.id);
console.log(window.location.href);
console.log(new Date().getTime());
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<!-- <div id="1" data-track="thisdiv">
Any clicks in here should be tracked
</div>
-->
<div id="1">
Any clicks in here should be tracked 1
</div>
<div id="2">
Any clicks in here should be tracked 2
</div>
<div id="3">
Any clicks in here should be tracked 3
</div>
<th id="th">tester</th>
You can try with:
$(document).ready(function() {
$("body > *").click(function(event) {
console.log(event.target.id);
});
});
$(document).ready(function() {
$("body > *").click(function(event) {
console.log(event.target.id);
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="1">
Any clicks in here should be tracked 1
</div>
<div id="2">
Any clicks in here should be tracked 2
</div>
<div id="3">
Any clicks in here should be tracked 3
</div>
<table>
<tr>
<td>Cols 1</td>
<td id="td">Cols 2</td>
</tr>
</table>
<p id="th">tester</p>
You may want to use event delegation to target the elements you need. Advantage is that this also works for dynamically generated elements. See code for an example of this.
// method to add/set data-attribute and value
const nClicksInit = (element, n = "0") => element.setAttribute("data-nclicked", n);
// add data-attribute to all current divs (see css for usage)
// btw: we can't use the method directly (forEach(nClicksInit))
// because that would send the forEach iterator as the value of parameter n
document.querySelectorAll("div").forEach(elem => nClicksInit(elem));
// add a click handler to the document body. You only need one handler method
// (clickHandling) to handle all click events
document.querySelector('body').addEventListener('click', clickHandling);
function clickHandling(evt) {
// evt.target is the element the event is generated
// from. Now, let's detect what was clicked. If none of the
// conditions hereafter are met, this method does nothing.
const from = evt.target;
if (/^div$/i.test(from.nodeName)) {
// aha, it's a div, let's increment the number of detected
// clicks in data-attribute
nClicksInit(from, +from.getAttribute("data-nclicked") + 1);
}
if (from.id === "addDiv") {
// allright, it's button#addDiv, so add a div element
let newElement = document.createElement("div");
newElement.innerHTML = "My clicks are also tracked ;)";
const otherDivs = document.querySelectorAll("div");
otherDivs[otherDivs.length-1].after(newElement);
nClicksInit(newElement);
}
}
body {
font: 12px/15px normal verdana, arial;
margin: 2em;
}
div {
cursor:pointer;
}
div:hover {
color: red;
}
div:hover:before {
content: '['attr(data-nclicked)' click(s) detected] ';
color: green;
}
#addDiv:hover:after {
content: " and see what happens";
}
<div id="1">
Click me and see if clicks are tracked
</div>
<div id="2">
Click me and see if clicks are tracked
</div>
<div id="3">
Click me and see if clicks are tracked
</div>
<p>
<button id="addDiv">Add a div</button>
</p>
<h3 id="th">No events are tracked here, so clicking doesn't do anything</h3>
You can invoke the stopPropagation and the condition this === e.currentTarget to ensure invoke the handler function of the event source DOM.
And you must know the <th> tag must wrapped by <table>, otherwise it will not be rendered.
$(document).ready(function() {
$('*').each(function(i, ele) {
$(this).addClass("tracked");
});
$('.tracked').on('click', function(e) {
if (this === e.currentTarget) {
e.stopPropagation();
console.log('Div clicked' + this.id);
console.log(window.location.href);
console.log(new Date().getTime());
}
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<!-- <div id="1" data-track="thisdiv">
Any clicks in here should be tracked
</div>
-->
<div id="1">
Any clicks in here should be tracked 1
</div>
<div id="2">
Any clicks in here should be tracked 2
</div>
<div id="3">
Any clicks in here should be tracked 3
</div>
<table>
<th id="th">tester</th>
</table>

Make link bold if column is visible (not hidden)

I have a filter menu which I put inside a table, and when one of the links are clicked, the according column in another separate table becomes hidden, until the link is click on again.
<!-- Table for filter menu -->
<table>
<tr>
<td>
<a class="toggle-vis" data-column="1">hideColumn1</a> |
<a class="toggle-vis" data-column="2">hideColumn2</a> |
<a class="toggle-vis" data-column="3">hideColumn3</a>
</td>
</tr>
<table>
<script>
$('a.toggle-vis').on( 'click', function (e) {
e.preventDefault();
// Get the column API object
var column = table.column( $(this).attr('data-column') );
column.visible( ! column.visible() );
} );=
</script>
My aim is to have some way of showing which columns are hidden/shown, so onClick, I would like the link text to become bold or change color or whatever.
Do I need to loop through my table? I have no idea - very new to HTML so any help is appreciated and the getElementById doesn't seem to be working for me.
You can use this in order to get the clicked element, and then modify its inline-styling based on that (or use a class).
Inline styling
<!-- Table for filter menu -->
<table>
<tr>
<td>
<a class="toggle-vis" data-column="1">hideColumn1</a> |
<a class="toggle-vis" data-column="2">hideColumn2</a> |
<a class="toggle-vis" data-column="3">hideColumn3</a>
</td>
</tr>
<table>
<script>
$('a.toggle-vis').on( 'click', function (e) {
e.preventDefault();
// ADDED CODE
var element = $(this);
if (element.css('font-weight') === 'bold') {
element.css({
'font-weight': 'normal'
});
} else {
element.css({
'font-weight': 'bold'
});
}
// END OF ADDED CODE
// Get the column API object
var column = table.column( $(this).attr('data-column') );
column.visible( ! column.visible() );
} );=
</script>
Classes
With classes, this is even simpler. Add this to your style:
.bold-link {
font-weight: bold;
}
and then, just use this function:
<script>
$('a.toggle-vis').on( 'click', function (e) {
e.preventDefault();
// ADDED CODE
var element = $(this);
element.toggleClass('bold-link');
// END OF ADDED CODE
// Get the column API object
var column = table.column( $(this).attr('data-column') );
column.visible( ! column.visible() );
} );=
</script>
You can add a class to the last clicked link (and remove previous class).
At the beginning of your file.
<style>
.selected {
font-weight: bold;
}
</style>
In the function
$('a.selected').removeClass('selected');
$(this).addClass('selected');
Also why are you calling e.preventDefault()?
Is it for when you click the link to not do anything?
Another way is to give a href="" attribute to the links and to return false at the end of the onclick function.

<td> focusin event .addclass

i have a data table with a column like this
This is my HTML
<td class="orders-options column-invoice">
<strong>
<a class="row-title" href title="View detail">78060</a>
</strong>
<div class="locked-info"></div>
<div class="row-actions">
<span class="edit">Edit</span>
<span class="view">View</span>
</div>
</td>
I would like to show certain options like, "Edit" or "View" when user mouse over . My plan is to addclass on to so that it's visibility: changes hidden; to visible; according to CSS file.
This is my JS
$("td.orders-options").focusin(function() {
$(this).find(".row-actions").addClass('visible');
});
$("td.orders-options").focusout(function() {
$(this).find(".row-actions").removeClass('visible');
});
However this doesn't seem to have any effect on html.
Also I'm curious if this function will change class only in the that is focused or all on other that are not focused
You can use mouseover and mouseout or simple hover.
$("td.orders-options").mouseenter( function() {
$(this).find(".row-actions").addClass('visible');
}).mouseleave( function() {
$(this).find(".row-actions").removeClass('visible');
});
Also instead of visibility, toggle display property in css. Because visibility:hidden will take space though it's hidden.
In terms of hover, it will be like:
$("td.orders-options").hover( function() {
$(this).find(".row-actions").addClass('visible');
} ,function() {
$(this).find(".row-actions").removeClass('visible');
});
Update: Adding DEMO
$("td.orders-options").hover( function() {
console.log("Rias");
$(this).find(".row-actions").addClass('visible');
} ,function() {
$(this).find(".row-actions").removeClass('visible');
});
.row-actions.visible {
display: block;
}
.row-actions {
display: none;
}
<script src="//code.jquery.com/jquery-1.11.1.min.js"></script>
<table>
<td class="orders-options column-invoice">
<strong>
<a class="row-title" href title="View detail">78060</a>
</strong>
<div class="locked-info"></div>
<div class="row-actions">
<span class="edit">Edit</span>
<span class="view">View</span>
</div>
</td>
</table>
You should rather use .hover()..hover() method specifies two functions to run when the mouse pointer hovers over the selected elements:
$("td.orders-options").hover(function(){
$(this).find(".row-actions").addClass('visible');
},function(){
$(this).find(".row-actions").removeClass('visible');
});
Easily achieve your goal using toggelclass
$("td.orders-options").hover( function() {
$(this).find(".row-actions").toggleClass('visible');
});

Dynamically Added Element Not showing in TD in HTML Table

I have this code :
var closeButton = $("<a class='close'/>")
.button({
icons: {
primary: "ui-icon-close"
},
text: false
})
.removeClass("ui-corner-all")
.addClass("ui-corner-right ui-combobox-toggle")
.click(function () {
if (invisibleElement != null)
jQuery(invisibleElement).val("");
//removing the close button with placaholder value
jQuery(visibleElement).val("Select");
jQuery(visibleElement).focus();
jQuery(visibleElement).blur();
var parentNode = $(this).parent();
parentNode.find(this).remove();
isCloseButton = false;
});
And I am adding this button conditionally by this:
$(visibleElement).parent().find(".showAll").after(closeButton);
This is not added by default. This is added based on some input.
These things are added within a td
<table border="0" width="100%" cellspacing='0' cellpadding='2'>
<tr>
<td style="vertical-align:middle; text-align:left; width: 45%;">
<input type="text" id="theVisibleElement" value=""/>
</td>
</tr>
But After adding the closeButton, I am not able to see the showAll element. Only the inputBox(visibleElement) and the closeButton is visible. Although, in the source code all three are there i.e visibleElement(the input TextBox), showAll element and closeButton. Strangely the td is enough big but still all three are not shown up. What to do? Any suggestion?
This is the jsfiddle: http://jsfiddle.net/8U6xq/1/
Though it's a bit messy.
This is a CSS problem. Your "close" element is right over your showAll element. See the corrected fiddle here :
http://jsfiddle.net/8U6xq/2/
I have just changed this in the css :
.close {
left: 270px;
}

Categories