Toggle an inactive element's text with jQuery - css

So I am attempting to create a menu element that shows and hides specific divs on a page, while also changing the text of the menu. After a little searching I have it worked out for the most part (although I know the code is a bit kludgey):
$(document).ready(function(){
$('.section[id="option1"]').click(function(){
$(this).text($(this).text() == 'OPTION1' ? 'OPTION1 >>' : 'OPTION1');
$('.blurb').not('.blurb[id="option1"]').hide();
$('.blurb[id="option1"]').slideToggle();
});
$('.section[id="option2"]').click(function(){
$(this).text($(this).text() == 'OPTION2' ? 'OPTION2 >>' : 'OPTION2');
$('.blurb').not('.blurb[id="option2"]').hide();
$('.blurb[id="option2"]').slideToggle();
});
$('.section[id="option3"]').click(function(){
$(this).text($(this).text() == 'OPTION3' ? 'OPTION3 >>' : 'OPTION3');
$('.blurb').not('.blurb[id="option3"]').hide();
$('.blurb[id="option3"]').slideToggle();
});
$('.section[id="option4"]').click(function(){
$(this).text($(this).text() == 'OPTION4' ? 'OPTION4 >>' : 'OPTION4');
$('.blurb').not('.blurb[id="option4"]').hide();
$('.blurb[id="option4"]').slideToggle();
});
$('.section[id="option5"]').click(function(){
$(this).text($(this).text() == 'OPTION5' ? 'OPTION5 >>' : 'OPTION5');
$('.blurb').not('.blurb[id="option5"]').hide();
$('.blurb[id="option5"]').slideToggle();
});
$('.section[id="option6"]').click(function(){
$(this).text($(this).text() == 'OPTION6' ? 'OPTION6 >>' : 'OPTION6');
$('.blurb').not('.blurb[id="option6"]').hide();
$('.blurb[id="option6"]').slideToggle();
});
});
(full code in action can be viewed here)
This code works for the most part, except that if you already have a certain element (class="blurb") shown, when you click on the menu item (class="section") for another element, the menu indicates that the other element is still open. It seems like there must be a simple way to append or remove the desired text on click, but I can't seem to find a good way of doing it. Would it be worth rewriting the code using something like expander.js?
Here is the effected html
<div class="nav">
<div class="section" id="option1">option1</div>
<div class="section" id="option2">option2</div>
<div class="section" id="option3">option3</div>
<div class="section" id="option4">option4</div>
<div class="section" id="option5">option5</div>
<div class="section" id="option6">option6</div>
</div>
<div class="blurb hidden" id="option1">
<h1>content for option1</h1>
</div>
<div class="blurb hidden" id="option2">
<h1>content for option2</h1>
</div>
<div class="blurb hidden" id="option3">
<h1>content for option3</h1>
</div>
<div class="blurb hidden" id="option4">
<h1>content for option4</h1>
</div>
<div class="blurb hidden" id="option5">
<h1>content for option5</h1>
</div>
<div class="blurb hidden" id="option6">
<h1>content for option6</h1>
</div>
I'm still fairly new to jQuery, so any advice/pointers is greatly appreciated.

I solved your problem using a custom class and :after CSS styles: http://jsfiddle.net/mblase75/sDrZ2/3/
First, some CSS to append the arrows and convert to uppercase without modifying the text directly:
.uppercase {
text-transform: uppercase;
}
.uppercase.arrowed:after {
content: " >>";
}
Add in some changes to your HTML to utilize data- attributes, remove duplicate IDs and add an arrowed class which the JS toggles:
<div class="nav">
<div class="section arrowed" data-blurb="option1">option1</div>
<div class="section arrowed" data-blurb="option2">option2</div>
<div class="section arrowed" data-blurb="option3">option3</div>
<div class="section arrowed" data-blurb="option4">option4</div>
<div class="section arrowed" data-blurb="option5">option5</div>
<div class="section arrowed" data-blurb="option6">option6</div>
</div>
And finally, a rewrite to optimize your JavaScript a lot:
$('.section').click(function () {
$(this).addClass('uppercase').toggleClass('arrowed')
.siblings('.section').removeClass('arrowed');
$('#'+$(this).data('blurb')).slideToggle()
.siblings('.blurb').hide();
});
Note that the arrowed class is toggled, so it needs to be added initially so that it's toggled off on the first click.

Related

How to Query Select all children of a class, but no grandsons of that class

I have the css class 'control', and I want to get all the 'control' children elements from my container, but I dont want to get grandsons 'control'.
<div id='mydiv'>
<div id='div1' class='control'>
<div id='div2' class='control'></div>
<div id='div3' class='control'></div>
</div>
<div class='other'>
<div id='div4' class='control'></div>
<div id='div5' class='control'>
<div id='div6' class='control'></div>
<div id='div7' class='control'></div>
</div>
</div>
</div>
The call below will get me all the controls inside 'mydiv'.
document.querySelectorAll('#mydiv .control');
I want a query that brings me only #div1, #div4 and #div5;
Is that possible?
With only querySelector* it will not work at the moment.
In the future, browsers will support the :has() pseudo-selector.
Then you can select only elements which has or not has elements inside them like this:
#mydiv .control:not(:has(.control))
See the current browser support for this: https://caniuse.com/css-has
For now you need following sulution:
const elements = [...document.querySelectorAll('#mydiv .control')].filter(element => {
return element.parentNode.closest('.control') == null
});
console.log(elements);
<div id='mydiv'>
<div id='div1' class='control'>
<div id='div2' class='control'></div>
<div id='div3' class='control'></div>
</div>
<div class='other'>
<div id='div4' class='control'></div>
<div id='div5' class='control'>
<div id='div6' class='control'></div>
<div id='div7' class='control'></div>
</div>
</div>
</div>
Explanation:
Get at first all .control elements into an array (querySelectorAll returns a NodeList and NodeList does'nt have methods like filter. So we extract it with the spread syntax [...variable]
Then filter all elements which has no parent elements named .control.
.closest() can return itself, so we need to make sure we call parentNode at first.
UPDATE End September 2022
Browser are starting to implement :has()

apply CSS class in Ionic on selected div in ng-repeat

<ion-slide ng-repeat="category in uniqueCategories" ng-if="$index % 4 === 0">
<div class="row" id="rowInSlider">
<div class="col col-25" ng-if="$index < uniqueCategories.length" ng-click="CategorySelected(uniqueCategories[$index], $index)">
<span class="img-centered img-padding imageDiv button button-icon">
<img class="smaller" src="img/south-indian-category-thumb.png">
</span>
<p class="smaller">{{uniqueCategories[$index]}}</p>
</div>
<div class="col col-25" ng-if="$index+1 < uniqueCategories.length" ng-click="CategorySelected(uniqueCategories[$index+1])">
<div class="img-centered img-padding imageDiv button button-icon">
<img class="smaller" src="img/south-indian-category-thumb.png">
</div>
<p class="smaller">{{uniqueCategories[$index+1]}}</p>
</div>
</ion-slide>
How can I set the background color for selected div?
This is what I tried:
<div class="col col-25" ng-if="$index < uniqueCategories.length" ng-click="CategorySelected(uniqueCategories[$index], $index)" ng-class="{selectedCategory: selectedCategory[$index]" >
controller:
$scope.CategorySelected=function(categoryName, indexNumber){
console.log(indexNumber)
$rootScope.readyToRender=false;
var selectedCategory={}
selectedCategory[indexNumber]=true;
}
But it does not work and I get no background color.
You wrote:
ng-class="{selectedCategory: selectedCategory[$index]"
First, there is a missing curly bracket, but there is also another problem: you have to expose selectedCategory on the $scope:
$scope.CategorySelected = function (indexNumber){
$scope.selectedCategory = {};
$scope.selectedCategory[indexNumber] = true;
}
Then:
ng-class="{selectedCategory: selectedCategory[$index]}"
That said, what you want to achieve here is probably better done by adding a flag isSelected to the category object.

Select an element of his parent that is not immediately after his parent

I have this html code:
<div class="form-group well">
<p>...</p>
<hr>
<div class="select-skill">
...
</div>
<div class="select-skill">
...
</div>
<div class="select-skill">
...
</div>
<div class="select-skill">
...
</div>
</div>
And i want to set a style using css3 to second child that has select-skill class, but i cant use .select-skill:nth-child(2), It doesn't work.
I know the solution is to remove <p>...</p><h1> or move select-skill to a new parent.
Is there any solution to select this element without adding any code of html?
JSFiddle
You can use this:
.select-skill:nth-of-type(2){
background:red;
}
Or if there are more in different div's, you can do:
.form-group .select-skill:nth-of-type(2){
/*styles*/
}
instead.

Bootstrap Alert Size Change

Is there a way I could edit how far an alert could stretch across the page, so it doesn't go all the way across?
Here's an example of my alerts:
<div class="alert alert-success">Your first number was correct.</div>
Using some CSS
.alert {
width:40%;
}
Example
http://www.bootply.com/96921
The example above makes the alert width 40% of the container, or in this case the screen.
You can also set a fixed width.
.alert {
width:300px;
}
if you want that the alert is juste the size of the inner text :
.alert {
display:inline-block;
}
Placing it in a row and offsetting its col did it for me.
<div class="row">
<div class="alert alert-danger col-md-4 col-md-offset-4" align="center">
</div>
</div>
I think it would work to just take the code from the question
<div class="alert alert-success">
and add one of the column classes like this
<div class="alert alert-success col-md-3">
Something like that worked for me anyhow, my exact code was
<div class="alert alert-info alert-dismissible col-md-3" role="alert">
Made a nice small alert out of it just a bit bigger than a button.
In newer versions of Bootstrap (v4 and v5), you can use this simple width modifier (w-25, w-50, w-75):
<div class="alert alert-danger w-50" role="alert">
You have been altered, dangerously!
</div>
https://getbootstrap.com/docs/4.5/utilities/sizing/#relative-to-the-parent
https://getbootstrap.com/docs/5.0/utilities/sizing/
If your alert is part of a .row then setting its class to include .col-lg-12 will force it to span across its container.
If you are using Bootstrap 4.0 or above your can make use of d-inline-block.
Here is an example how to use it:
<div class="alert alert-success d-inline-block" role="alert">
This is a success alert—check it out!
</div>
In bootstrap's documentation you can read more about the display property.
Simply use a span instead of a div. It is again the same "inline vs block elements" dilemma.
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<div class="alert alert-info">div alert</div>
<span class="alert alert-info">span alert</span>
Available since, at least, bootstrap v3.

Page css doesnt refresh within javascript function

my first question here so be gentle :).
I have this issue with changing css of elements and their refresh. I am createing a webforms application with ajax requests. My problem is that when somone chooses a report from a tree view it should display a gif with loading sign and after data is recieved it should display it. Its working fine on firefox and opera but not on ie, chore or safari. Here is the code:
This the method that is launched when someone clicks a tree node
this.hideElements();
var id = node.getId().substr(2);
var client = new CAjaxClient();
var data;
client.addParameter(new CKeyValuePair('ReportID', id));
client.postCallBack('/ajaxpages/Reports.aspx', 'GetReportFilters', this.dataRecieved);
filterGenerator.setReportID(id);
This the method hideElements()
$('#FiltersContainer').css('visibility', 'hidden');
$('#ActionsContainer').css('visibility', 'hidden');
$('#loadingDiv').css('visibility', 'visible');
$("input[id$='Date']").parent().css('visibility', 'hidden');
This the ajax postBack method
if (this.readyState == 4 && this.status == 200) {
$('#FiltersContainer').css('visibility', 'visible');
$('#ActionsContainer').css('visibility', 'visible');
$('#loadingDiv').css('visibility', 'hidden');
var data = eval(this.responseText);
filterGenerator.processFiltersData(data);
Data and everything is returned in order its just that in the request time the browser is like frozen and when the data returns css state is of that at the end of the whole process. Loading div is never shown. I tried also forcing redraw with domelement.style changing but no effect. When I execute the code in chrome debugger line by line everything goes perfectly. Please help if you can.
Html code(vio:TreeView is our own ASP control):
<div id="pageHeader" style="display:inline-block">
<div id="headerImageDiv" style="float:left; margin-left:15px; margin-top:5px;">
<img src="style/default/printerLarge.png" alt="" />
</div>
<div id="pageTitleDiv" style="float:left">
<span style="display:block; margin-top:20px;margin-left:10px;color:#78b4bb; font-size:20px;">Reports And Analyses</span>
<span style="display:block; margin-top:20px;margin-left:10px;font-size:18px;">Select a report</span>
</div>
</div>
<br />
<div id="mainPane" style="display:inline-block;width:100%;">
<div id="readerTreeContainer" style="float:left;border-top-style:solid;border-left-style:solid;border-bottom-style:solid;border-right:none; border-width:1px; overflow : auto;width:300px;height:auto; background-color:white;">
<vio:TreeView ID="TreeView" runat="server"
Width="298" Height="500"
ActionListener="ReportsGeneralListener"
ActionListenerScript="ReportsGeneralTree.js"
GlobalTreeviewName="reportsTreeview">
</vio:TreeView>
</div>
<div id="FiltersContainer" style="position:relative;visibility:hidden;float:left;border-top-style:solid;border-right-style:solid;border-bottom-style:solid;border-left:solid 1px; border-width:2px; overflow : auto;width:30%;height:500px; background-color:#dbdae4;">
<div id="filterColumnOne" style="float:left;width:50%;height:100%;border-right:solid 1px;border-left:none;">
</div>
<div id="filterColumnTwo" style="float:left;width:49%;height:100%;">
</div>
<div id="loadingDiv" style="z-index:10;position:absolute;top:50%;left:50%;margin: -35% 0 0 -35%;z-index:100001;height:316px;width:396px;">
<div style="position:relative;display:block">
<img src="style/default/loading.gif" alt="" style="position:absolute;left:0px;top:0px;z-index:-1;"/>
<span style="display:block;text-align:center;padding-top:80px;font-size:25px;font-weight:bold;">Loading Report</span>
</div>
</div>
</div>
<div id="ActionsContainer" style="visibility:hidden;float:left;border-left-style:none;border-top-style:solid;border-right-style:solid;border-bottom-style:solid;border-width:2px; overflow : auto;width:200px;height:200px; background-color:#abe9e7;">
<div style="display:block;border-bottom:solid 1px;height:50%">
<div style="position:relative; height:100%;">
<div style="position:absolute;top:50%;left:50%; height:72px;margin: -35px 0 0 -35%;">
<img src="style/default/document.png" alt="" style="float:left;margin-right:10px;"/>
<button type="button" style="margin-top:18%;height:30px;" onclick="print();">Print</button>
</div>
</div>
</div>
<div style="display:block;border:none;height:49%;">
<div style="position:relative; height:100%;">
<div style="position:absolute;top:50%;left:50%; height:72px;margin: -35px 0 0 -35%;">
<img src="style/default/application_pdf.png" alt="" style="float:left;margin-right:10px;height:72px;"/>
<button type="button" style="margin-top:18%;height:30px;">PDF</button>
</div>
</div>
</div>
</div>
</div>
Try .hide and .show instead. They work cross-browser.
See the jQuery API
I think your problem was:
<div stuff I'm hiding>
<div loading screen>
See here for a working demo of what you provided. I removed the inline visibility:hidden from the styles (I'd suggest you split into a CSS file, it's making it unreadable) and took the loading div from inside the div you were hiding.

Resources