Toggling the class of an object with jquery - javascript

I have elements that are added by the user (when they click a button), it adds a p and a pre element. The pre element is invisible and has no class while the p element has a class of "query-p".
What I'm trying to do is to make it so whenever the user clicks on a p element with "data-id='p1'", it add the class "show" to the pre element with "data-id='pre1'" or for example when you click on a p element with "data-id='p2'", it add the class "show" to the pre element with "data-id='pre2'" and so on.
This is my jquery code :
$(function () {
$("p[data-id]").on("click", function() {
var idFound = $(this).data("id");
if ($("p[data-id]").attr("class") == "query-p" && $("pre[data-id]").attr("class") != "show") {
$("pre[data-id]").attr("class", "show");
}
else if ($("pre[data-id]").attr("class") == "show") {
$("pre[data-id]").removeAttr("class");
}
});
});
This is my HTML (the elements that I'm working with are not in this code, I put it here because it might help): https://pastebin.com/eKVbUZHQ
This is my other javascript file (it mostly contains the code that adds the elements that I'm working with) : https://pastebin.com/yEZuuhA8
The problem that I'm having is that my code shows all pre elements instead of only the one it's supposed to.
EXAMPLE :
I added new elements with :
p element 1 : id="display-pre1" class="query-p" data-id="p1"
pre element 1 : id="display-pre-a1" data-id="pre1"
p element 2 : id="display-pre2" class="query-p" data-id="p2"
pre element 2 : id="display-pre-a2" data-id="pre2"
The pre elements are hidden with "display: 'none'".
All elements with class "show" have "display: 'block'".
The pre elements have no class.
Now, whenever I click on the first p element, it adds the class "show" to both the pre element 1 and the pre element 2, so they both get "display: 'block'", when I click it again it hides both of the pre elements again.
Hope this helps a bit.

Some of the issues within the click handler:
With $("p[data-id]") you select all p elements with a data-id attribute, while you need to only select the clicked one.
With $("pre[data-id]") you select all pre elements with a data-id attribute, while you need to only select one with a particular value for that attribute.
You compare the class attribute with "query-p", but then why not put this condition in a way that the click handler is only defined for those? Then you don't have to check this anymore once the user has clicked.
The code with attr("class") and removeAttr("class") assumes that an element will have at the most one CSS class. This is restricting the possibilities. Elements should be allowed to have multiple CSS classes defined for it.
Here is a small snippet to demo how it could work:
$(function () {
$("p.query-p[data-id]").on("click", function() {
var data = $(this).data("id").replace(/^p/, "pre"),
$pre = $("pre[data-id=" + data + "]");
$pre.toggleClass("show");
});
});
pre { display: none }
pre.show { display: block }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p class="query-p" data-id="p1">para 1</p>
<p class="query-p" data-id="p2">para 2</p>
<pre data-id="pre1">pre 1</pre>
<pre data-id="pre2">pre 2</pre>

Related

Refactoring : Would like a single function/event handler to do the same thing

I am new to programming and JS as can be seen in my code. The background colour and text on the page changes according to which target <li> tag is clicked, possibly i.e. function, objects, arrays or if statements using eventListeners and events handlers.
I am looking for inspiration here so that I can finally understand how programming really works.
See my code below.
let navLink1 = document.querySelector('color1');
let navLink2 = document.querySelector('color2');
let navLink3 = document.querySelector('color3');
let navLink4 = document.querySelector('color4');
let p1 = document.querySelector('para');
navLink1.addEventListener('click', function (e) {
document.body.style.background = "color1";
document.innerHTML(p1) = "New text!";
});
navLink2.addEventListener('click', function (e) {
document.body.style.background = "color2";
document.innerHTML(p1) = "New text!";
});
navLink3.addEventListener('click', function (e) {
document.body.style.background = "color3";
document.innerHTML(p1) = "New text!";
});
navLink4.addEventListener('click', function (e) {
document.body.style.background = "color4";
document.innerHTML(p1) = "New text!";
});
<ul class ='nav'>
<li class ='color1'><a href=''>color1</a></li>
<li class ='color2'><a href=''>color2</a></li>
<li class ='color3'><a href=''>color3</a></li>
<li class ='color4'><a href=''>color4</a></li>
</ul>
<h2>The text in the <p> tag below changes according to clicked link in the menu</h2>
<p class ='para'>This is (color)</p>
<!-- if color1 is clicked in the menu then the <body> background will be changed to color1 and the innerHTML will also be changed to color1. The background color and targeted text changes according to the menu item clicked ->
There are a few issues with that code, but basically: Yes, you can use a single event handler to handle all four links. The process is called "event delegation" — delegating the handling of the event to some ancestor element. In this case, the ul makes a good place to put a click handler. click events "bubble" from the target element (the li) to its parent, then its parent, etc., so we can handle a click on any li in the ul by handling it on the ul.
See comments:
// Handle click on the `ul.nav`:
document.querySelector(".nav").addEventListener("click", function(event) {
// `event.target` is the element the event was targeted at (the `li`
// element). We can use the `closest` method to find the first element
// starting with that one and then working through its parent, parent's
// parent, etc., until we find one that matches the selector. The
// selector looks for an element that has a `data-color` attribute.
const li = event.target.closest("[data-color]");
// If we found one and it's within the element we hooked `click` on
// (the `ul`), we handle the click
if (li && this.contains(li)) {
// Get the color from the attribute
const color = li.getAttribute("data-color");
// Assign it to the body
document.body.style.backgroundColor = color;
// Show the color name in the `span`
document.querySelector(".color").textContent = color;
}
});
li[data-color] {
cursor: pointer;
}
<ul class="nav">
<!-- I've removed the classes and set a data-* attribute with the color to set -->
<!-- I've also removed the `a` elements. Because they're links, clicking follows them -->
<li data-color="#E0E0E0">color1</li>
<li data-color="#D0D0D0">color2</li>
<li data-color="#C0C0C0">color3</li>
<li data-color="#B0B0B0">color4</li>
</ul>
<!-- Note that I've changed the opening angle bracket in the `p` tag below to its
character reference form (<) so it's not handled as a paragraph -->
<h2>The text in the <p> tag below changes according to clicked link in the menu</h2>
<!-- I've added a span with a class so we can set the color name -->
<p class="para">This is <span class="color">(no color yet)</span></p>
More
Introduction to events
data-* attributes
CSS selectors
closest
contains
If you wanted to do it with the a elements (so we get default tabbing and "activation" on various user gestures, like pressing Enter), we can do much the same thing just with a event.preventDefault() call to tell the browser not to follow the href of the a. When doing that, it's usually best to have the href indicate to the user what it's going to do, so we can use that rather than a data-* attribute:
// The prefix used on `a` element `href`s:
const prefix = "#set-color-";
// Handle click on the `ul.nav`:
document.querySelector(".nav").addEventListener("click", function(event) {
// `event.target` is the element the event was targeted at (the `li`
// element). We can use the `closest` method to find the first element
// starting with that one and then working through its parent, parent's
// parent, etc., until we find one that matches the selector. The
// selector looks for an `a` element whose `href` *starts with* the
// text `set-color-`
const anchor = event.target.closest(`a[href^="${prefix}"]`);
// If we found one and it's within the element we hooked `click` on
// (the `ul`), we handle the click
if (anchor && this.contains(anchor)) {
// Get the color from the `href` by grabbing the part after the
// prefix
const color = anchor.getAttribute("href").substring(prefix.length);
// Assign it to the body
document.body.style.backgroundColor = color;
// Show the color name in the `span`
document.querySelector(".color").textContent = color;
// Prevent the default of following the anchor
event.preventDefault();
}
});
li[data-color] {
cursor: pointer;
}
<ul class="nav">
<!-- I've removed the classes and set a data-* attribute with the color to set -->
<!-- I've also removed the `a` elements. Because they're links, clicking follows them -->
<li>color1</li>
<li>color2</li>
<li>color3</li>
<li>color4</li>
</ul>
<!-- Note that I've changed the opening angle bracket in the `p` tag below to its
character reference form (<) so it's not handled as a paragraph -->
<h2>The text in the <p> tag below changes according to clicked link in the menu</h2>
<!-- I've added a span with a class so we can set the color name -->
<p class="para">This is <span class="color">(no color yet)</span></p>

How to remove style attribute added with jquery

I am using a devExpress table with some custom requirements.
(UPDATE)
Took a break from this for a day and went back and did it properly using React Styling! Thanks for suggestions
In the screenshot I have certain cells disabled. However the user wants all cells to look disabled other that the row selected.
Using this
window
.$("td")
.not(document.getElementById(this.state.selection[0]))
.not(document.getElementsByClassName(this.state.selection[0]))
.not("td:first-child")
.not(window.$("td:contains('iPlay')"))
.not(window.$("td:contains('iLOE')"))
.not(window.$("td:contains('iInvest')"))
.not(window.$("td:contains('SPACER')"))
.not(window.$("td:contains('$MM')"))
.not(window.$("td:contains('$/BOE')"))
.attr("style", "color:#868a8f");
window
.$("td > div > div > div > input")
.not(document.getElementsByClassName(this.state.selection[0]))
.attr("style", "color:#868a8f");
I managed to achieve my desired result on page load
My problem is when I select a new row I cannot remove that color I applied before when it was not selected. I am trying to use "has" to find the selected row and change the color back to inherit or completely remove the style attribute.
window
.$("td")
.has(document.getElementById(this.state.selection[0]))
.has(document.getElementsByClassName(this.state.selection[0]))
.not("td:first-child")
.not(window.$("td:contains('iPlay')"))
.not(window.$("td:contains('iLOE')"))
.not(window.$("td:contains('iInvest')"))
.not(window.$("td:contains('SPACER')"))
.not(window.$("td:contains('$MM')"))
.not(window.$("td:contains('$/BOE')"))
.attr("style", "color:inherit");
window
.$("td > div > div > div > input")
.has(document.getElementsByClassName(this.state.selection[0]))
.attr("style", "color:inherit");
If it helps I do have the ids of the rows that are NOT selected.
I tried to do something with that but did not have any luck
const otherRows = ExpensesUtils.ROW_PROPS.filter(x => x !== this.state.selection[0]);
for (let i = 0; i < otherRows.length; i += 1) {
window
.$("td")
.has(document.getElementById(otherRows[i]))
.has(document.getElementsByClassName(otherRows[i]))
.attr("style", "color:inherit");
window
.$("td > div > div > div > input")
.has(document.getElementById(otherRows[i]))
.has(document.getElementsByClassName(otherRows[i]))
.attr("style", "color:inherit");
}
link to HTML
Table HTML
this.state.selection[0] is the selected rowId from the list below
I have applied the the rowIds to classes in the nested components. I could not figure out another way to access them.
const ROW_PROPS = [
"leaseAndWellExpense",
"leaseAndWellExpenseBoe",
"iloeLeaseAndWellExpense",
"iloeLeaseAndWellExpenseBoe",
"gnaLeaseAndWell",
"gnaLeaseAndWellBoe",
"transportation",
"transportationBoe",
"divisionGnA",
"divisionGnABoe",
"gatheringProcessing",
"gatheringProcessingBoe",
"hqGnA",
"hqGnABoe",
"interestExpense",
"interestExpenseBoe",
"netProdBoe",
"leaseImpairments",
"leaseImpairmentsBoe",
"ddaProducing",
"ddaProducingBoe",
"iInvestDdaProducing",
"iInvestDdaProducingBoe",
"ddaGatheringProcessing",
"ddaGatheringProcessingBoe",
"iInvestDdaGatheringProcessing",
"iInvestDdaGatheringProcessingBoe",
"marketingCosts",
"otherIncomeExpense",
"otherIncomeExpenseBoe",
"otherRevenue",
"incomeTaxProvision",
"incomeTaxProvisionBoe",
"severanceTaxes",
"severanceTaxesPercent",
"currentTaxes",
"currentTaxesRate",
"netWellHeadRevenue",
];
The easiest way of doing this is by creating a CSS rule's stylesheet.
In that stylesheet, you should define 2 classes.
Let's suppose 1 for your desired CSS rules and the other for the default/none rules.
I am just showing you the simplest version of doing this thing but with another aspect.
$('#b1').on('click', function() {
$('.c1').removeClass('c1');
$(this).addClass('c2');
});
.c1 {
color: red;
}
.c2 {
color: green;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button id="b1">Change</button>
<p class="c1">This is a Test Line.</p>
The easiest way is
$('#idName').on('click', function()
{
$('.className').removeClass('removeClassName');
$(this).addClass('addClassName');
});
The code above means that when a button with the id of IdName is clicked, the element with className will be removing the class of removeClassName, and adding the class of addClassName.
For further clarification you can have a look at Removing CSS Using JQuery Documentation
There is another way by which you can achieve it.
Instead of playing with style attribute, since it takes the highest specificity so somewhere it might create an issue.
Instead of that you can use toggleClass. First add your default styling to table, whenever you click any row you can make use of toggle class
Toggle Class Example
Example.
$("td > div > div > div").click(function(){
$("input").toggleClass("main");
})

How can I remove elements with a class when its header matches the page title?

$(document).ready(function () {
var pageTitle = $('h3.title-hidden');
if (title === pageTitle) {
$('.content-hidden').remove();
}
});
Where is my mistake?
pageTitle is the jQuery object that wraps the h3 element. It doesn't contain the text of that element. If you want the text, use .text():
var pageTitle = $('h3.title-hidden').text();
That assumes, based on your code, that there's just one h3.title-hidden on the page, and that you want to remove all .content-hidden elements if that one element's text matches the document title.

How to get cursor placed element from onclick button using javascript

I have contenteditable div in HTML5. I have a ul li inside the DOM. When I click on that button I want that cursor placed inside the li using javascript. How can I do that?
<span class="mT2 mL10 bullotIcon fR vam" onclick="iconClick(this)">clickButton</span>
<div id="editableEvent" class="w100p ht70 f13 textField w250 boxSizeBB whiteBg selev grayBdr oA" contenteditable="true" style="height: 100px;">
<ul>
<li>dafdsasdsdfasdfd</li>
<li>dfsfsdfdsfsdfdfdsfsdfsdfdsf</li>
<li>sdfsdfsdfsdfsdfdfsdffdf</li>
</ul>
</div>
function iconClick(obj){
if ($('#editableEvent').getSelection) {
console.log($('#editableEvent').getSelection().anchorNode.parentNode);
}
}
Normally my cursor was inside the content editable div. on click button i want the cursor placed element like 'li' Thanks in advance
Add code below after you click button.
document.getElementById("editableEvent ul li").style.cursor = "default";
To remove an LI that was clicked on, you can use an event's target property to work out what you clicked on then remove it.
Plain JS:
document.getElementById('editableEvent').onclick = function(e){
if(e.target instanceof HTMLLIElement){
e.target.remove();
}
}
jQuery:
$('#editableEvent').click(function(e){
$target = $(e.target);
if($target.is('li')){
$target.remove();
}
});
I am just providing links that may help you
https://stackoverflow.com/a/3976125/3979414 - to find the current position in contentEditable text.
https://stackoverflow.com/a/1211981/3979414 - to find the cursor mentioned tag
https://stackoverflow.com/a/4232971/3979414 - to remove the corresponding tag
you can also try:
$('li').on('click',function(){
$(this).remove();
});
On click li, I was add one class on it after button clicked i remove that class element
"Li clicked":
callLiFunction: function (obj){
$('#editableEvent').find('.liCreated').removeClass('liCreated');
$(obj).addClass('liCreated');
}
"button clicked":
funcCallDel : function() {
$('#editableEvent').find('.liCreated').remove();
}
Thanks for get some idea from you people.

How to check if an element with id exists or not in jQuery?

I'm generating a div dynamically and I've to check whether a dynamically generated div exists or not ? How can I do that?
Currently I'm using the following which does not detects the div generated dynamically. It only detects if there is already an element with the id contained in the HTML template.
$(function() {
var $mydiv = $("#liveGraph_id");
if ($mydiv.length){
alert("HHH");
}
});
How can I detect the dynamically generated div?
If mutation observes aren't an option due to their browser compatibility, you'll have to involve the code that's actually inserting the <div> into the document.
One options is to use a custom event as a pub/sub.
$(document).on('document_change', function () {
if (document.getElementById('liveGraph_id')) {
// do what you need here
}
});
// without a snippet to go on, assuming `.load()` for an example
$('#container').load('/path/to/content', function () {
$(this).trigger('document_change');
});
If it is added dinamically, you have to test again. Let's say, a click event
$("#element").click(function()
{
if($("#liveGraph_id").length)
alert("HHH");
});
How you inserting your dynamic generated div?
It works if you do it in following way:
var div = document.createElement('div');
div.id = 'liveGraph_id';
div.innerHTML = "i'm dynamic";
document.getElementsByTagName('body')[0].appendChild(div);
if ($(div).length > 0) {
alert('exists'); //will give alert
}
if ($('#liveGraph_id').length > 0) {
alert('exists'); //will give alert
}
if ($('#liveGraph_id_extra').length > 0) {
alert('exists'); //wont give alert because it doesn't exist.
}
jsfiddle.
Just for interest, you can also use a live collection for this (they are provided as part of the DOM). You can setup a collection of all divs in the page (this can be done in the head even before the body is loaded):
var allDivs = document.getElementsByTagName('div');
Any div with an id is available as a named property of the collection, so you can do:
if (allDivs.someId) {
// div with someId exists
}
If the ID isn't a valid identifier, or it's held in a variable, use square bracket notation. Some play code:
<button onclick="
alert(!!allDivs.newDiv);
">Check for div</button>
<button onclick="
var div = document.createElement('div');
div.id = 'newDiv';
document.body.appendChild(div);
">Add div</button>
Click the Check for div button and you'll get false. Add the div by clicking the Add div button and check again—you'll get true.
is very simple as that
if(document.getElementById("idname")){
//div exists
}
or
if(!document.getElementById("idname")){
// don't exists
}

Categories