I want to add an overlay that slides into view on my page. To do it, I am setting the style.width of the div during overlay open and close. The problem is the div is controlled by a *ngIf, and is undefined when my .ts code sets the *ngIf true and tries to set the div's width.
How can I get this working?
Component HTML:
<div *ngIf="showOverlay === true">
<div id="myOverlay" class="overlay" style="margin-top: 25px;">
×
<div class="overlay-content">
Overlay is working!
</div>
</div>
</div>
<div *ngIf="showOverlay === false" id="content" style="padding: 30px;">
...
</div>
Component TS:
public showOverlayFcn() {
this.showOverlay = true;
this.openOverlay();
}
public openOverlay() {
document.getElementById("myOverlay").style.width = "100%";
}
public closeOverlay() {
document.getElementById("myOverlay").style.width = "0%";
}
Thanks! Bob
You could try using a conditional ngStyle attribute on the div with ID of myOverlay:
[ngStyle]="{'width': showOverlay ? '100%' : '0%'}"
Looks like you're not following the angular way. To get any element angular recommends to use #ViewChild. SO the proper way would be something like below:
<div *ngIf="showOverlay === true">
<div #myOverlay class="overlay" style="margin-top: 25px;">
×
<div class="overlay-content">
Overlay is working!
</div>
</div>
</div>
<div *ngIf="showOverlay === false" id="content" style="padding: 30px;">
...
</div>
And on your class file access it like this:
#ViewChild('myOverlay', { static: false }) myOverlay: ElementRef;
Even after this if you're not able to get the element then trigger a change detection like: this.changeDetectorRef.detectChanges();. Please remember to inject the ChangeDetectorRef in your constructor.
Try to use setTimeout function as there maybe delay to enable element by ngIf.
public openOverlay() {
setTimeout(function() {
document.getElementById("myOverlay").style.width = "100%";
}, 100);
}
Related
I am trying to change the css of a html given a span class.
I have an html as follows:
<form id=thing>
<div id=a>
<span class=x>
</span>
</div>
<div id=b>
<span class=x>
</span>
</div>
</form>
When I inspect the webpage I see the following style being applied:
#thing .x {
display: none !important;
}
Now my goal is to get rid of this display css property completely.
I tried $("#thing .x").css("display", ""); but i keep getting "$(...).css is not a function - unable to remove css "
Any tips on how to solve this?
Using inline style with setAttribute()
I assume you are trying to remove the styling for display from none. '' => nothing would not be a valid style to use, use a valid property value recognized by the display property, like inline or block for example.
You can override the !important rule set in CSS with the same CSS hack used in inline style as inline style takes presidence over styles set in CSS sheet. The only way I was able to do it was by setting the style attribute using el.setAttribute('style', 'display: inline !important;'). See snippit and a few examples of failure and finally success below...
let dontUseImportant = document.querySelectorAll('#thing .x')
dontUseImportant.forEach(el => {
// style display inline !important is ignored
// this is likely a rule in JS that will disallow
// spaces in values passed into properties for style
// more research on this may be fruitful
// however note the outcome in console.log
el.style.display = "inline !important";
el.textContent = 'this will not parse to DOM'
console.log(el)
})
dontUseImportant.forEach(el => {
// style display is added but is over written by !important used in CSS
el.style.display = "inline";
el.textContent = 'this will not parse to DOM'
console.log(el)
})
// this also will not work
dontUseImportant.forEach(el => {
el.setAttribute('style', 'display: null !important;');
el.textContent = 'this will not parse to DOM'
console.log(el)
})
// by adding !important using setAttribute behind our
// property, this affects the elements style
// however, we are putting a bandaid on a bandaid
dontUseImportant.forEach(el => {
el.setAttribute('style', 'display: inline !important;');
el.textContent = 'content x is finally shown!'
console.log(el)
})
#thing .x {
display: none !important;
}
.y {
display: inline;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form id="thing">
<div id="a">content a
<span class="x">content x
</span>
</div>
<div id="b">content b
<span class="x">content x
</span>
</div>
</form>
Swapping classes on element
Because the CSS file is using !important this unfortunately will override any styles you place on the element using el.style.property = '' regardless of using JS or a JS library like JQuery.
You could add a new class using JS that has a defining display: inline and then remove the old class. Keep in mind that you must add a valid property value when using styles. display = '' is not valid.
Your particular issue is a great example as to why !important is a BAD IDEA for styling as a crutch!
let $dontUseImportant = $('#thing .x')
// iterate over elements and swap out the classes
// make sure to add the new class 'y' first
// then remove initial class 'x'
$.each($dontUseImportant, function(i){
$(this).addClass('y')
$(this).removeClass('x')
console.log($dontUseImportant[i])
})
#thing .x {
display: none !important;
}
.y {
display: inline;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form id="thing">
<div id="a">content a
<span class="x" >content x
</span>
</div>
<div id="b">content b
<span class="x">content x
</span>
</div>
</form>
Why not using the hidden attribute? It is supported in all modern browsers. So in your case, you don't even need CSS.
jQuery:
$('button').on('click', function() {
$('.x').each(function() {
$(this).show();
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form id="thing">
<div id="a">
<span class="x" hidden>
1
</span>
</div>
<div id="b">
<span class="x" hidden>
2
</span>
</div>
</form>
<button>Show</button>
Vanilla JS
const x = document.querySelectorAll('.x');
document.querySelector('button').addEventListener('click', (e) => {
for (let item of x) {
item.removeAttribute('hidden');
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form id="thing">
<div id="a">
<span class="x" hidden>
1
</span>
</div>
<div id="b">
<span class="x" hidden>
2
</span>
</div>
</form>
<button>Show</button>
The structure is similar to this:
<div>
<div id="selected">
<div id="inBetweenDiv">
<input id="action"></input>
</div>
</div>
<div id="changeThis"></div>
</div>
I want to change background of #changeThis on the focus of the input element.
In pure CSS you could use the :focus-within pseudoclass
#selected:focus-within ~ #changeThis {
background: yellowgreen
}
<div>
<div id="selected">
<div id="inBetweenDiv">
<input id="action" />
</div>
</div>
<div id="changeThis">Change this</div>
</div>
Otherwise you could do the same via JS, if you need to support older browsers e.g.
var input = document.getElementById('action');
var ct = document.getElementById('changeThis');
input.addEventListener('focus', () => { ct.classList.add('focus'); });
input.addEventListener('blur', () => { ct.classList.remove('focus'); });
and in CSS – assuming that #changeThis has a default background already applied – you need to use a more specific selector like
#changeThis.focus {
background: yellowgreen;
}
I have added the library for Bootstrap and data-spy attribute where I want to make the div fix when I scroll the page down. But it doesn't work, I have almost tried everything, but not able to figure out the problem.
Is is something like the data-spy attribute doesn't work on class = "row" ?
Here's my code for HTML.
<div class="row">
<h4> HEADING </h4>
<h5>
<div class="row" data-spy="affix" data-offset-top="10">
dsds
Date : <input type="date" name="graph_date" id="graph_date">
</div>
<div class="row">
<div class="graph-hourly">
<div class="loader" id="chart_loader">
<p>Loading...</p>
</div>
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart_hourly"></div>
</div>
</div>
</div>
and some css :
.affix {
top : 0;
width: 80%;
}
after searching for some solutions, I've added this also,
.affix-top {
width: 100%;
}
.affix-bottom {
position: absolute;
width: 100%;
}
but this solution also dosen't worked for me.
Not sure what the problem is in your case. I copied and pasted your code into a jsfiddle with the bootstrap library and the affix class did work. Though, it worked badly because it affixed the row right when you started scrolling.
Looks like Bootstrap doesn't have a way to set the offset to the current position of the element so I added the following javascript to make it work.
$('#affix-this').affix({
offset: {
top: $('#affix-this').offset().top
}
})
(#affix-this should be changed to the id of the row you want to affix.)
Note the $('#affix-this').offset().top. This makes sure the element gets affixed right when you reach the element's current position.
Second, I removed the html attributes that you had for the affixing.
<div class="row">
<h4> HEADING </h4>
<div class="row" id="affix-this">
dsds Date :
<input type="date" name="graph_date" id="graph_date">
</div>
<div class="row">
<div class="graph-hourly">
<div class="loader" id="chart_loader">
<p>Loading...</p>
</div>
<div id="chart_hourly"></div>
</div>
</div>
Notice the affix-this id was added to the row that you want to affix.
Here is a working JSFiddle with these changes so you can see it in action: https://jsfiddle.net/heraldo/6s4u26m3/4/
First of all delete top:0; from affix class because it will make a issue for you.
now you have two methods pick a one :
1
adding data-spy="affix" which is works fine for me
2
same result ass data-spy but you will need some styling after you complete your page
by adding a position Property for input tag
as ex. :
CSS:
sticky{
position:fixed;
}
and HTML :
<input type="date" name="graph_date" class="sticky" id="graph_date">
Update 1
this Jquery code can detect a scroll event so when user scroll down it will make the div tag sticky or "affix"
$(function() {
$(window).scroll(function() {
var aTop = "100";
if ($(this).scrollTop() >= aTop) {
$('#affix-this').css( "position", "fixed" );
$('#affix-this').css( "top", "0" );
$('#affix-this').css( "width", "100%" );
}
});
});
change the aTop variable with the height you want (in pixel) so when the user scroll down 100px the div become sticky
a JSfiddle example
Update 1.1
a bit smarter Jquery code do the same but get the height automatically from a another element this can be good if you format your page to something similar to this
$(function() {
$(window).scroll(function() {
var aTop = $('id').height();
if ($(this).scrollTop() >= aTop) {
$('#affix-this').css( "position", "fixed" );
$('#affix-this').css( "top", "0" );
$('#affix-this').css( "width", "100%" );
}
});
});
Make sure the element to which you're adding data-spy="affix has been created in the DOM before your Bootstrap scripts load. I ran into an issue where I was adding data-spy="affix" in my HTML, but it was wrapped up in a section that wasn't rendering, thanks to data-ng-if. My HTML was created after my Bootstrap had loaded, so the <div> I wanted to stick to the top of the screen never stayed in a fixed position. If you can, use data-ng-show, or something that merely hides HTML, rather than prevents it from being created on page load.
I'm trying to develop a collapsible list based on Google Inbox in Polymer.
I've created a list of polymer-elements, where each element is a paper-material with an iron-collapse inside.
The iron-collapse contains data and a couple of paper-buttons.
I need to show/hide the <iron-collapse> element, when clicking the parent paper-material.
This works really well, but unfortunately that event also fires after clicking a paper-button e.g. Send-Button inside the iron-collapse.
I tried adding event.stopPropagation() to the child's button handler, but the iron-collapse still collapses, when clicking the button.
Any ideas?
Code for parent container:
<paper-material id="papercontainer" elevation="1" class="container padded" animated style="border-radius:4px;">
<div class="container">
<div class="container flex-start-justified">
<div class="flexchild">
<h4 class="smaller-margin">Bill Gates</h4>
<p class="smaller-margin">bill#gates.com</p>
<p class="paper-font-caption smaller-margin">Date received: 01/01/2015</p>
</div>
<p>
<paper-button raised on-click="send">Send</paper-button>
</p>
</div>
<!--Code for iron-collapse (child): -->
<div class="container flex-horizontal">
<iron-collapse id="collapse" class="flexchild">
<div class="flexchild collapse-content" style="margin-top:10px;">
<paper-button>Edit Mail</paper-button>
</div>
</iron-collapse>
</div>
</div>
</paper-material>
Javascript:
Polymer({
is: 'zapytania-result-element2',
toggle: function() {
this.$.collapse.toggle();
},
listeners: {
'tap': 'regularTap'
},
regularTap: function(e) {
console.log('toggle iron-collapse');
if(this.$.collapse.opened) {
this.$.collapse.hide();
this.$.papercontainer.elevation = 1;
} else {
this.$.collapse.show();
this.$.papercontainer.elevation = 5;
}
},
send: function() {
sendMail();
}
}
I have followed the Events Tutorial from
https://www.polymer-project.org/1.0/docs/devguide/events.html
Per my understanding 'tap' makes the whole element listen for the tap event.
After removing that handler and assigning my own on-click event handler to the parent paper-material container and calling e.stopPropagation() at the end of my child's button event it works.
I have 5 div's all with the same class name like this:
CSS:
.test:hover{
color:red;
}
HTML:
<div class="test"></div>
<div class="test"></div>
<div class="test"></div>
<div class="test"></div>
<div class="test"></div>
Imagine for a moment these Div's are in different parent div's on the page...
I'm trying to find a way so they all change to color:red if i hover my mouse over any of the 5 rather than just the one in question changing...
I can't wrap them in a parent and give that parent a hover how ever... they are not sharing the same parents in the first place.
Does CSS provide a way to do this or am I going to have to rest to JavaScript?
One (plain/vanilla) JavaScript approach that works (in compliant browsers, which support [].forEach(), and document.querySelectorAll()), given that CSS cannot (yet) perform this task, is:
function classToggle (evt, find, toggle) {
[].forEach.call(document.querySelectorAll('.' + find), function(a){
a.classList[evt.type === 'mouseover' ? 'add' : 'remove'](toggle);
});
}
var els = document.querySelectorAll('.test');
for (var i = 0, len = els.length; i<len; i++){
els[i].addEventListener('mouseover', function(e){
classToggle(e, 'test', 'highlight');
});
els[i].addEventListener('mouseout', function(e){
classToggle(e, 'test', 'highlight');
});
}
JS Fiddle demo.
References:
Array.prototype.forEach().
document.querySelectorAll().
Element.classList.
Function.prototype.call().
You could use JQuery to pretty easily achieve what you want... copy this to an .html file to test it...
<html>
<head>
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script>
$(document).ready(function() {
$(".test").hover(
function() {
$(".test").css("background-color", "red");
}, function() {
$(".test").css("background-color", "");
}
);
});
</script>
</head>
<body>
<div class="test">My Div</div><br />
<div class="test">My Div</div><br />
<div class="test">My Div</div><br />
<div class="test">My Div</div><br />
<div class="test">My Div</div>
</body>
</html>
It's impossible to select element's parent via CSS nowadays. So also it's impossible to select element by one element and general parent. It's like a tiny proof.
Here is the code:
css:
.sample{
background: none repeat scroll 0 0 #FFFFFF;
height: 105px;
opacity: 0.1;
position: absolute;
top: 0;
width: 5%;
}
.sample:hover ~ div{
color:red;
cursor:pointer;
}
html:
<div class="sample"></div>
<div class="container">
<div class="test">1111</div>
</div>
<div class="container">
<div class="test">2222</div>
</div>
<div class="container">
<div class="test">3333</div>
</div>
<div class="container">
<div class="test">4444</div>
</div>
<div class="container">
<div class="test">5555</div>
</div>
Check the demo here: http://jsfiddle.net/eN49z/
Quick answer: it is not possible via CSS-only to achieve the effect that you are looking for, as CSS is unable to travel up the parent, but only down the DOM tree to affect elements.
You can, however, rely on JavaScript to achieve the effect. In my example I have chosen to rely on jQuery. You can use various methods to get all other <div>s with the class test, but it depends on how they are nested - are they nested under parents that are siblings, and the level of nesting and etc.
Here is an example markup of the scenario you have described:
<div>
Parent 1
<div class="test"></div>
</div>
<div>
Parent 2
<div class="test"></div>
</div>
<div>
Parent 3
<div class="test"></div>
</div>
The CSS would be simple. The .hover class (not the :hover state) is added dynamically by jQuery (see below):
.test:hover, .test.hover {
background-color: red;
}
The JS would be something like:
$(function() {
$(".test").hover(function() {
// Find '.test' in all siblings of a specific '.test' parent
$(this).parent().siblings().find(".test").addClass("hover");
}, function() {
// You can refine the criteria of which '.test' should be selected.
$(document).find(".test").removeClass("hover");
});
});
http://jsfiddle.net/teddyrised/fHwFf/