Expanding and collapsing multiple neighboring divs within the same parent element - html

I'm struggling with this bit of code, and I'm not sure if it's even possible. I have a list of divs within a single parent element, and I need to collapse and expand certain sets. Here's an example:
<div id="parent">
<div class="alway_show">ALWAYS SHOW ME</div>
<div class="collapse_me">COLLAPSIBLE</div>
<div class="collapse_me">COLLAPSIBLE</div>
<div class="collapse_me">COLLAPSIBLE</div>
<div class="alway_show">ALWAYS SHOW ME</div>
<div class="collapse_me">COLLAPSIBLE</div>
<div class="collapse_me">COLLAPSIBLE</div>
<div class="collapse_me">COLLAPSIBLE</div>
</div>
So, in the initial state, .collapse_me will be display:none. There will be a link in always show to expand ONLY the collapsed divs below that particular .always_show div. I know this would be ten million times easier if the collapsible divs were in their own div, but I don't have control over the code. I have to make it work as is using jquery. Possible?

$('div.always_show').nextAll().each(function() {
if($(this).is('.collapse_me')) {
$(this).toggle();
}
else {
//this will halt the each "loop", stopping before the next .always_show
return false;
}
});
Of course you should not use my initial selector 'div.always_show', but rather supply it the actual element, which will be the parent of the clicked link. For example:
$('#expand_anchor').parent().parent().nextAll()...

var fncdiv = function(){
var el = this;
do{
el = $(el).next();
if ($(el).hasClass("collapse_me") )
$(el).toggle();
else
break;
}while (true)
};
$('#parent div.alway_show').bind("click", fncdiv);

You shouldn't need to use jQuery. It only requires some clever CSS:
#parent
{
/* normal parent css here */
}
#parent div
{
display: block;
}
#parent.collapsed
{
display: block;
}
#parent.collapsed div
{
display: none;
}
Selectors are applied in order of specificity. Since '#parent.collapsed div' is more specific than '#parent div', it should override. Now, all you need to do, is set the parent div's class, and you're done. You can use javascript to add/remove the 'collapsed' class to the DIV at runtime to toggle expansion without any additional effort:
// Mootools:
$('parent').addEvent('click', function()
{
$('parent').toggleClass('collapsed')
});

Related

Select an element in DOM which is not a sibling, but goes after

Let us suppose I have the following DOM
<div class="parent">
<div class="childNotSibling">
</div>
</div>
<div class="elementToSelect">
</div>
Now I would like to select the div with elementToSelect class but only if div with parent class has inside it an element with childNotSibling class. Is it possible to acomplish this using css?
This JSFiddle should do the trick: https://jsfiddle.net/tremor/f4cghd5x/
Using JQuery here is the Javascript portion of the code.
// find all the occurrences of .childNotSibling
$("body").find(".childNotSibling").each(function(index, element) {
// if .childNotSibling's parent has class "parent"
if ($(this).parent().hasClass("parent")) {
// and if the parent's next sibling has "elementToSelect"
if ($(this).parent().next().hasClass("elementToSelect")) {
// do something with that element
$(this).parent().next().css("background-color", "red");
}
}
});

Can i use attributes of element to create style rules?

I'm noot good in english, so the title may seem a bit odd.
I want to use css function attr() like this:
I mean i have a container <div> and an inner <div> that i want to have width depending on data-width attribute. For example this would be great, but this doesnt work:
<div class="container">
<div data-width="70%">
</div
</div>
.container {
width: 600px;
height: 200px;
}
.container div {
width: attr(data-width);
height: 100%;
}
Is there any noJS way to use attributes like that?
UPDATE: Guys convinced me that the JS is the only way to do this :)
That's not a big problem (but that's bad. CSS, why youre so illogical? Is the difference between content:attr(data-width) and width: attr(data-width) so big ?).
One of the guys had an idea to go through the all elements with jQuery.
That's ok, but it is very... local? Don't know how to say it in english.
Anyway, i remaked his code a little bit and here it is:
allowed = ['width','color','float'];
$(document).ready(function () {
$('div').each(function (i, el) {
var data = $(el).data(),style = '';
if (!$.isEmptyObject(data)) {
$.each(data, function (attr, value) {
if (allowed.indexOf(attr) != - 1) {
style += attr + ': ' + value + '; ';
}
})
if (style.length != 0) {
$(el).attr('style', style);
}
}
})
})
Idea is simple:
1. We suppose that style we want to add to an element is the only one. I mean there are no scripts that will try to add some other styles,
2. We create an array of allowed attribute names, we need to avoid using wrong names at the style attribute, for example style="answerid: 30671428;",
3. We go through each element, save its data attributes in an object, check if object is empty, and if not - check every attribute if it is allowed, create a string that contains all styles that we need, and - finally - add our style string to the element as the content of style attribute.
That's all, thanks everybody
I would not advise to use CSS alone since it will not allow you to do what you're looking for... instead use a scripting language (in my case jQuery) to accomplish this functionality for you like so: jsFiddle
jQuery
jQuery(document).ready(function(){
var dataElem; // to store each data attribute we come accross
jQuery('div').each(function(){ //loop through each div (can be changed to a class preferably)
dataElem = jQuery(this); //get the current div
if(dataElem.data('width')){ //make sure it exists before anything further
dataElem.width(dataElem.data('width')); //set the element's width to the data attribute's value
dataElem.css("background-color", "yellow");
}
});
});
HTML
<p>The links with a data-width attribute gets a yellow background:</p>
<div>
w3schools.com
</div>
<div class="me" data-width="50"> <!-- change value to see the difference -->
disney.com
</div>
<div>
wikipedia.org
</div>
Notes on the above:
each, data, width.
Instead of doing data-width, use a class attribute. An html tag can have mutliple classes separated by spaces, so if you wanted to be very precise, you could set up as many classes as you need. For instance:
<div class="w70 h100">
</div>
Then in your css:
.w70{
width: 70%;
}
.h100{
height: 100%;
}
And so on.
Is there any noJS way to use attributes like that?
No, you cannot use CSS to set the width of the element to it's data-width attribute. CSS does not allow for this as attr() is only currently available for the CSS content property which is only available on css pseudo elements (::before and ::after).
How can you achieve this with as little javascript as possible?
This is extremely easy to do using the native host provided DOM API.
Select the elements using Document.querySelectorAll().
Iterate the elements and apply the styles using Element.style which can be retrieved from the data-width attribute using Element.dataset
(Demo)
var items = document.querySelectorAll('#container div'), item, i;
for(i = 0; (item = items[i]); i++) item.style.width = item.dataset.width;

Adding divs inside a hidden section

I have 8 hidden sections with display:none; on my site that are triggered with jQuery to show when a select id is selected. When i try to start building the structure inside the hidden element #Restaurant (like this)
<div id="common">
<div id="Restaurant" class="common_reveal">
<div class="common_title">test</div>
</div>
</div>
It doesn't work. However, if i just insert plain text or <span>, it does...
Is there a reason for why it wont display additional <div>'s within the hidden element?
JS
$('#business_type').change(function(){
$("#common div").each(function() {
$(this).attr("style", "display: none;");
})
$("#" + $(this).val()).attr("style", "display: block;");
})
CSS
#common {
}
.common_reveal {display: none;}
You are picking all divs inside your #common element, try this:
$("#common >div").each(...)

How to correctly override .ng-hide class in order to change hiding/showing nature?

When using ng-hide or ng-show directives a .ng-class is added or removed so DOM elements are visible or not.
However they kinda get positional "removed" as for example, hiding or showing two continous div elements one on top of the other.
<div ng-show="condition1">First div</div>
<div ng-show="condition2">Second div</div>
So, if condition1 evaluates to false first div will be hidden BUT second div will take the position which the just hidden div took.
How can I avoid that? I only want DOM elements to be invisible but not to get somehow removed.
First workaround.
I tried to overried .ng-hide class and getting a secondary class, only-hide, for elements on which I wanted this effect:
.ng-hide.only-hide {
visibility: hidden !important;
}
But didn't get results so far.
I achieved it with this second class approach by setting:
.ng-hide.only-hide {
visibility: hidden !important;
display: block !important;
}
As Angular sets .ng-hide with display:none, I make it invisible but present setting display:block.
To preserve and maintain the space occuped by the div you can't use directly ng-hide or ng-show.
You can use the ng-style directive as following:
<div ng-style="conditionHide1">First div</div>
<div ng-style="conditionHide2">Second div</div>
then your conditionHide1 and conditionHide2 should be like
if (condition1)
$scope.conditionHide1= {'visibility': 'hidden'}; // then div1 will hidden.
else
$scope.conditionHide1= {'visibility': 'visible'}; // then div1 will visible.
if (condition2)
$scope.conditionHide2= {'visibility': 'hidden'}; // then div2 will hidden.
else
$scope.conditionHide2= {'visibility': 'visible'}; // then div2 will visible.
You can change the visibility of the button by changing the $scope.conditionHide1 and $scope.conditionHide2 according to your conditions.
Solution2 by using a custom directive:
Create a new directive named condition and relative to an Attribute. Set-up a watch to watch the value of the attribute and, based on the value, set to the element (in this case the div) an appropriate css style. The value is mapped to the variable showDiv which change his value by clicking on the button. Clicking on the button, the value showDiv became the opposite !showDiv and the watch change the visibility from visible to hidden and vice-versa.
angular.module('MyModule', [])
.directive('condition', function() {
return {
restrict: 'A',
link: function(scope, element, attributes) {
scope.$watch(attributes.condition, function(value){
element.css('visibility', value ? 'visible' : 'hidden');
});
}
};
})
.controller('MyController', function($scope) {
$scope.showDiv = true;
});
<script src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.7.0/underscore-min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app='MyModule' ng-controller='MyController'>
<div condition='showDiv'>Div visible/invisible</div>
<button ng-click='showDiv = !showDiv'>Hide div or show it</button>
</div>

how to change properties of a parent div on hover of child div

how to change properties of a parent div on hover of child div.
can it be done with pure css ?
html:
<div class="parent">
<div class="child">
</div>
</div>
css:
.parent{width:200px;height:100px;background:#cccccc;}
.child{width:200px;height:100px;background:transparent;}
Not with plain CSS you need some form of script to notify the parent that the child is being hovered(eg.):
<div id="parentId" class="parent">
<div id="childId" onmouseover="doOnMouseOver()" onmouseout="doOnMouseOut()" class="child">
</div>
</div>
<script type="text/javascript">
function doOnMouseOver() {
var parentNode = this.parentNode;
var newParentClass = parentNode.getAttribute('class') + 'child-beeing-hovered';
parentNode.setAttribute('class', parentClass);
}
function doOnMouseOut() {
var parentNode = this.parentNode;
var newParentClass = parentNode.getAttribute('class').replace('child-beeing-hovered', '');
parentNode.setAttribute('class', parentClass);
}
</script>
Note that I've added ids to your html elements so that I can get a hold of them with javascript without making the code unnecessary complex nor using a third party library like jQuery.
Note that you need also to bind onmouseout or otherwise the parent element will keep the new class child-beeing-hovered.
jQuery actually makes your job easier but you should try doing this with javascript at least once.
I hope it helps.
Is there a reason you do not want to use JavaScript or JQuery?
You could simply:
$("#child_id").hover(function (){
$(this).parent("div").addClass("some-class")
});
There is no parent selector in CSS.
You can find quite good explanation why it's not supported here: http://snook.ca/archives/html_and_css/css-parent-selectors