Can I use the !important css keyword with Angularjs ng-style directive? - angularjs

I'm having an issue with boostrap3 and it's default background: transparent !important; print setting.
I have the need to show a heatmap in my webapp and have these printable.
I'm using an ng-style directive for that to dynamically calculate the needed background-color.
In short, this is the html part
<div class="heatmap" ng-style="scalecolor(10)">lorem ipsum</div>
and this is the controller part
$scope.scalecolor = function(perc) {
return { backgroundColor: plnkUtils.scaleColorInt('#EE0000', '#88FF00', perc) }
};
However, because bootstrap3 sets all backgrounds to transparent with the !important keyword, I can't print these.
This is the part of bootstrap 3.1.0 css causing the issue with missing background-color:
#media print {
* {
color: #000 !important;
text-shadow: none !important;
background: transparent !important;
box-shadow: none !important;
}
}
Since the inverse of background: transparent !important; is background: color hex code !important;
(see here )
I'm trying to set that using the ng-style, but then the exclamantion mark causes Angularjs to flip when I try this:
$scope.scalecolor = function(perc) {
return { backgroundColor: plnkUtils.scaleColorInt('#EE0000', '#88FF00', perc) !important }
};
or alternatively when I try this in the html template
ng-style="scalecolor(10) !important"
Anyone out there that knows how I can use the !important css keyword with the Angularjs ng-style directive to override the bootstrap3 wildcard?
For those who want to see this with their own eyes, here's a plunker showing the issue

Apparently you can't and it's a known issue but there is some workaround that can be found here:
https://github.com/angular/angular.js/issues/5379
The solution below has been copied from the site just in case the link breaks, or get changed.
You're not able to use the !important directive in the DOM style property in either Chrome nor FF (probably others too). The style attribute gets parsed as CSS, but the HTMLElement.style property doesn't. Unfortunately you're not able to set a property's priority here (in Gecko/Blink/Webkit, at least).
So, there are some workarounds here:
Workaround #1
<ANY data-ng-attr-style="{{ blue && 'background-color: blue!important' || '' }}">
</ANY>
This would be your best way to go in terms of browser-support, because the CSS property priority will get parsed correctly here.
Workaround #2
Alternatively, you can also do the following in javascript:
$scope.$watch(conditionalStyle);
function conditionalStyle() {
if ($scope.blue) {
$element[0].style.setProprety('background-color', 'blue', 'important');
} else {
$element[0].style.backgroundColor = '';
}
}
Where $element is a jQuery/jqLite object referencing an HTMLElement.
Note: caveats are not supported in IE < 9 so workaround #1 is probably your best bet for this behavior where you depend on property priority...

Using the tips for #Wawy I updated my code to get it to work.
For anyone landing on this page, for clarification I made an updated Plunker that can be found here
In short, this is now the html part
<div class="heatmap" ng-attr-style="{{ngAttrScaleColor(10)}}">YES, ng-attr-style works !</div>
and this is the controller part
$scope.ngAttrScaleColor = function(perc) {
return 'background-color: ' + plnkUtils.scaleColorInt('#EE0000', '#88FF00', perc) + '!important';
};

Related

ng-style not refreshing dynamically

I have an md-card with this code:
<md-card ng-style="{ width: pageWidth > 900 ? '40vw' : '80vw' }">...</md-card>
pageWidth is a $scope variable bound to $(window).width(). Here is the code for that:
$scope.pageWidth = $(window).width();
$(window).resize(() => {
$scope.pageWidth = $(window).width();
console.log('page width: ' + $scope.pageWidth);
})
$(document).ready(() => {
$(window).resize(() => {
$scope.pageWidth = $(window).width();
console.log('page width: ' + $scope.pageWidth);
})
})
The style is applied correctly when the page loads, but not when I manually resize the page. As you can see in the second code block, I added a console.log statement to the handlers, so I know that $scope.pageWidth is updating with every pixel of width I change. However, the width of the md-card never changes from one to the other. What's going on here?
And before you mark this as a duplicate, people have asked this before, but not in a way where their answers apply to my situation.
Sorry, I'm not posting an answer for this other then that you have a typo in first line should be:
<md-card ng-style="{ width: pageWidth > 900 ? '40vw' : '80vw' }">...</md-card>
But from what I can see what you are doing can be done much more efficiently using normal CSS - no need to put javascript logic for that. Also I would advise using AngularJS $window (you will need to inject it) instead of global window object and I'm against using Jquery in Angular applications and Jquery DOM manipulations unless it's really really (and I will say again really) necessary.
Check this link about media queries:
https://developer.mozilla.org/en-US/docs/Web/CSS/Media_Queries/Using_media_queries
You will see that you can easily check max-width and max-height, also min-width/height and tons of different things that might solve your problems with pure CSS and no need for Javascript/Jquery mixed with AngularJS.
Your CSS would be something like:
#media screen and (max-width: 900px) {
md-card {
width: 80vw;
}
}
#media screen and (min-width: 901px) {
md-card {
width: 40vw;
}
}
Of course this would be globally on all md-card elements if you need it more specific add classes on each element and change media queries.

Activating Scrolling in React Autosuggest

How to activate scrolling using React Autosuggest (like the fourth example http://react-autosuggest.js.org/) ?
I can't get the option to do that in Documentation.
Actually, it was quite straight-forward :
.react-autosuggest__suggestions-list
{
max-height: 200px;
overflow-y: auto;
}
Defining a static height and adding overflow-y to auto was the solution to my problem.

Unable to see and scroll the html view of ionic modal when keyboard appear

I am using ionic modal in ionic project. the modal is appearing on page clearly, but when I am trying to enter any text into any textbox the keyboard is appearing on page.
Once the keyboard appeared, I am unable to see the html of modal and also unable to scroll modal.
kindly refer the screenshot.
Thank you.
Waited for long time and did't get any answer, So I have written some css to fix this issue, This is working in my project as well as dominik
also tried this. see the comment by him
#media(min-width: 680px){
.modal{ top: 0; height: 70%; }
body.keyboard-open.modal{ height: 90%; }
body.keyboard-open.modal.scroll{ overflow-y: scroll !important; }
}
.overflow-scroll.keyboard-up:not(.keyboard-up-confirm){
overflow-y: scroll;
height: 100% !important;
top: 0;
}
Had to come up with this fix. it worked for me, so give it a try: Put the code in your app.run
NOTE: this issue is normally caused when you set android:windowSoftInputMode="adjustPan" in your AndroidManifest.xml
Make sure jquery is included in your app.
window.addEventListener('native.keyboardshow', keyboardShowHandler);
window.addEventListener('native.keyboardhide', keyboardHideHandler);
function keyboardShowHandler(e){
setTimeout(function() {
var originalHeight = window.innerHeight-30;
var newHeight = originalHeight - e.keyboardHeight;
$('ion-modal-view ion-content').css("height", newHeight);
}, 0);
}
function keyboardHideHandler(e){
setTimeout(function() {
var newHeight = '100%';
$('ion-modal-view ion-content').css("height", newHeight);
}, 0);
}

How to get height of a div in Ionic

I'm working to develop a mobile app using Ionic.
A bit of background first as to what I am trying to achieve.
I've got a challenging bit of design I am coding in. I am placing an image of fixed height, in the bottom right hand corner of a div which has a flexible height. The text within the div then needs to wrap around the image.
Like this:
What the end result should be like
The HTML and CSS side of things
I've got the CSS and HTML sussed (at least I think!). The HTML is:
//this line is in the head
<style ng-bind-html="myStyles"></style>
//the rest is in the body of the HTML
<div class="score_block">
<div class="description">
<div class="image_container">
<img src="img/emotional_man.png">
</div>
<p>{{area.levelling.description}}</p>
<div class="habits_button">
<button ng-click="$state.go('app.planner')" class="button button-stable button-icon button-block">Plan habits</button>
</div>
</div>
</div>
And the CSS (written using SASS) is like this:
.score_block {
text-align: center;
position: relative;
.description {
text-align: left;
margin: 10px 0;
}
.image_container {
clear: both;
float: right;
width: 100px;
height: 100px;
img {
height: 100px;
width: 100px;
}
}
}
.score_block:before {
content: "";
float: right;
height: 200px;
width: 0;
}
If I change the height of the 'score_block:before' class I can reposition the image just I need.
The Javascript so far
So with the Javascript side of things I'm hoping that if I can figure out the height of the .description div, I can subtract the height of the image from it and tell the CSS how to position the image. I need some AngularJS to do this - I think that's what I need as JQuery doesn't work in Ionic as far as I know.
So far I have JS code that does this:
.controller('emotionalCtrl', function ($scope, $state, AreasService, _) {
//these commented out lines are to show things I have tried but don't work
//var blockH = $(".description").height();
//var descriptionHeight = angular.element('description');
//var number = descriptionHeight('offsetHeight');
var number = 0;
$scope.myStyles = "#habit_area_homepage .score_block:before { height:" + number + "px; }";
})
I'm looking to do a calculation on the variable number and pass that back in. I can manually change the value of number of it works fine so I know everything else is good. I've read some stuff about doing directives etc but all the examples I've seen confuse me. Maybe I need to put a directive in here or something to help me get the height of the .description element but I just can't figure out to do this. I've spent nearly two days getting this far!
I'm pretty new to AngularJS and Ionic so any help would be really appreciated. Thanks!
There are multiple ways to accomplish dynamic styles.
According to your provided code. I recommend you add styles to head.
Run below codes in your controller or "run":
angular.module("app",[]).run(function(){
var stylesTpl="<style>#habit_area_homepage .score_block:before { height:" + number + "px; } </style>";
angular.element(document).find("head").append(stylesTpl);
})
Check this post for built-in directives of angular to achieve dynamic styles:
How do I conditionally apply CSS styles in AngularJS?
If you want to get the height of a specific div, you have two ways:
Assign an id to the div, and use
var element = document.getElementById("id");
console.log(element.offsetHeight);
Use querySelectors, this returns the first and only one element:
var element = document.querySelector(".description");
console.log(element.offsetHeight);
Using directive is also a good way, check:
Get HTML Element Height without JQuery in AngularJS

How to properly translate shadow DOM CSS selectors to non-shadow-DOM selectors

I want to test Polymer applications with non-Shadow-DOM capable browsers like Firefox, PhantomJS, and maybe others using WebDriver.
WebDriver commands for Firefox and PhantomJS fail when I use something like
driver.findElement(const By.cssSelector('* /deep/ #some-div'));
Are there some rules how to best translated/approximate these selectors when the polyfills can not be applied:
/deep/
::shadow
:host()
:host-context()
:content
I would like to create a function that translates such selectors automatically to non-shadow-DOM selectors for browsers that don't support them before sending the request and for that I need to know how to translate them.
Question is a bit old, but in case you haven't figured it out yourselves yet.
/deep/ (deprecated): As you said in your answer, just removing it should work in most of the cases.
::shadow (deprecated): Can also just be removed. Replacing it with > might not work if node which you are targeting is not an immediate child of host element's shadow root.
:host() pseudo classes is used to select custom element from inside shadow-dom, in non-supported browsers it will be equal to selecting parent from child element. Since we don't have parent selectors in css and you are writing js for conversion, you can identify tagName of host element and use it instead of :host selector. Something like below:
:host {
opacity: 0.4;
transition: opacity 420ms ease-in-out;
}
:host(:hover) {
opacity: 1;
}
:host(:active) {
position: relative;
top: 3px;
left: 3px;
}
/*Convert it to*/
x-element {
opacity: 0.4;
transition: opacity 420ms ease-in-out;
}
x-element:hover {
opacity: 1;
}
x-element:active {
position: relative;
top: 3px;
left: 3px;
}
:host-context(<selector>) pseudo class matches the host element if it or any of its ancestors matches <selector>. for example:
Below rule will apply on custom element only when it's a descendant of an element with the class .different.
:host-context(.different) {
color: red;
}
<body class="different">
<x-foo></x-foo>
</body>
It won't be very easy to replace this one with anything simple. Even webcomponents polyfill doesn't attempt it. I can't think of any css only way to achieve this.
::content targets distributed child nodes of host element, i.e. all elements which are picked to display using content selectors. Replacing ::content selectors with tagName of host elements should work here. i.e.
::content > h3 {
color: green;
}
/*replace it with*/
x-element h3 {
color: green;
}
Note that I have removed child selector > also from above, because in non-supported browsers after distribution h3 won't be a direct descendant of x-element anymore. Given the way content selector is used, I'd suggest removing child selector also wherever available.
/deep/ can just be removed
::shadow can be replaced by >
don't know about the others yet

Resources