Dynamic Inline CSS using AngularJS - html

I have an angular app and need to apply some CSS styles on a page, at runtime.
Solution using ng-style is not scalable:
I am aware that for specific (known) items, this can easily be done using the ng-style directive e.g.:
<div id="mydiv" ng-style="{color: bgColor}">ABCD</div>
However, this technique cannot be applied to all the <a> or <p> tags on the page. How does one apply a dynamic style based on an angular scope variable to ALL instances of a tag on the page?
Something like the following would be ideal:
<style>
.in3_counter {color: {{settings.in3Color}};}
.in4_counter {color: {{settings.in4Color}};}
</style>
Update: The value of the css scope variables isn't predetermined, so I we don't know what colors would be applied to the elements as the variables are set at runtime (e.g. with color picker).
Any suggestions?

Check the following example:
var COLOR_CTRL = function($scope, $sce) {
$scope.changeColor = function(color) {
$scope.style = $sce.trustAsHtml('a, p {color: ' + color + '}');
};
$scope.changeColor('#000');
};
var app = angular.module('app', []);
app.controller('ColorCtrl', ['$scope', '$sce', COLOR_CTRL]);
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.7/angular.min.js"></script>
<div ng-controller="ColorCtrl" ng-app="app">
anchor
<p>paragraph</p>
<div>
<button ng-click="changeColor('#f00')">red</button>
<button ng-click="changeColor('#0f0')">green</button>
<button ng-click="changeColor('#00f')">blue</button>
</div>
<style data-ng-bind-html="style"></style>
</div>

Related

jquery change style class attribute value

I have style css cur_font class
I want to change font-family to 'arial' by jquery
and also new font affected on class selectors html,body,h2,h1,div,td
<style>
.cur_font html,body,h2,h1,div,td { font-family:'tahoma'; }
</style>
<script>
$(".change_font").on("click", function (e) {
var font='arial';
$("style.cur_font").css("font-family",font);
});
</script>
trying to change font-family attribute for class cur_font using jquery
The easiest way to do this would be to toggle a class on the body and apply different styles.
Another approach would be to loop over document.styleSheets and then loop over the cssRules and check to see if the selectorText matches. If it does, modify the rule.
Other option is to use a CSS variable and alter the value of the variable.
document.querySelector(".buttons").addEventListener("click", evt => {
const btn = evt.target.closest("button");
if (!btn) return;
const color = btn.dataset.color;
document.documentElement.style.setProperty('--myVariable', color);
});
:root {
--myVariable: red;
}
div {
background-color: var(--myVariable);
}
<div>Hello World</div>
<div class="buttons">
<button data-color="blue">blue</button>
<button data-color="red">red</button>
<button data-color="yellow">yellow</button>
</div>

How to change CSS that Django template uses with a button?

I am trying to implement accessibility option on my page that would change CSS to different file when accessibility button would be clicked.
For now, all my templates extends base_generic.html, where style.css is loaded. When accessibility button would be clicked, I wish for it to change to use style_access.css for that user. How can I accomplish that?
I think a way could be, to refer in the HTML template to both CSS files, and use an onclick function with javascript, and jquery to change the id or class of the specific elements of the template.
So for example,
let's say I wanted onclick to change the CSS of an element, I could make a counter and toggle between two ids that I will have referenced in my CSS file or files.
<body>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js">
</script>
<button>This is a div</button>
<h1 class="potatoe" id="hello">HELLO THIS IS TEXT</h1>
<style>
#hello { color: red; }
#bye { color: blue; }
</style>
<script>
var clickCount = 0;
$("button").on("click", function() {
clickCount++;
$(".potatoe").attr("id", clickCount % 2 === 0 ? "bye" : "hello");
});
</script>
</body>
As you'll see everytime you click the button the CSS of the element will change
This is not exactly changing between CSS files but it ultimately changes the CSS of the elements you want to select.
You can implement by using JavaScript more easily:
const toggleButton = document.getElementById('button');
const workContainer = document.getElementById('work');
toggleButton.addEventListener('click', () => {
document.body.classList.toggle('blue');
toggleButton.classList.toggle('active');
workContainer.classList.toggle('blue');
if(document.body.classList.contains('blue')){
localStorage.setItem('blue', 'enabled');
}else{
localStorage.setItem('blue', 'disabled');
}
});
if(localStorage.getItem('blue') == 'enabled'){
document.body.classList.toggle('blue');
toggleButton.classList.toggle('active');
workContainer.classList.toggle('blue');
}

Angular conditional container element

I have a large chunk of HTML in an ng-repeat that for certain elements has a container element and for others it does not. I'm currently achieving this with two ng-ifs:
<strike ng-if="elem.flag">
… <!-- several lines of directives handling other branching cases -->
</strike>
<div ng-if="!elem.flag">
… <!-- those same several lines copied-and-pasted -->
</div>
While this works, it means I have to remember copy-and-paste any edits, which is not only inelegant but also prone to bugs. Ideally, I could DRY this up with something like the following (inspired by ng-class syntax):
<ng-element="{'strike':flag, 'div':(!flag)}">
… <!-- lots of code just once! -->
</ng-element>
Is there any way to achieve a similarly non-repetitive solution for this case?
You can make such directive yourself.
You can use ng-include to include the same content into both elements.
Assuming the effect you desire is to have the text within your tag be striked through based on the condition of the elem.flag:
You could simply use the ng-class as follows
angular.module('ngClassExample', [])
.controller('elemController', Controller1);
function Controller1() {
vm = this;
vm.flag = true;
vm.clickItem = clickItem
function clickItem() {
// Toggle the flag
vm.flag = !vm.flag;
};
}
.strikethrough{
text-decoration: line-through
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app='ngClassExample' ng-controller="elemController as elem">
<div ng-class="{strikethrough: elem.flag}" ng-click="elem.clickItem()">
element content should be sticked through: {{elem.flag}}
</div>
</div>
You can do it with a directive
module.directive('myFlag', function() {
var tmpl1 = '<strike>...</strike>';
var tmpl2 = '<div>...</div>';
return {
scope: {
myFlag: '='
},
link: function(scope, element) {
element.html(''); // empty element
if (scope.myFlag) {
element.append(tmpl1);
} else {
element.append(tmpl2);
}
}
};
});
And you just use it like:
<div ng-repeat="item in list" my-flag="item.flag"></div>
You could create a directive which will transclude the content based on condition. For tranclusion you could use ng-transclude drirective, in directive template. Also you need to set transclude: true.
HTML
<my-directive ng-attr-element="{{elem.flag ? 'strike': 'div'}}">
<div> Common content</div>
</my-directive>
Directive
app.directive('myDirective', function($parse, $interpolate) {
return {
transclude: true,
replace: false, //will replace the directive element with directive template
template: function(element, attrs) {
//this seems hacky statement
var result = $interpolate(attrs.element)(element.parent().scope);
var html = '<'+ result + ' ng-transclude></'+result+'>';
return html;
}
}
})
Demo Plunkr
You can also use ng-transclude :
Create your directive :
<container-directive strike="flag">
<!-- your html here-->
</container-directive>
Then in your directive do something like :
<strike ng-if="strike">
<ng-transclude></ng-transclude>
</strike>
<div ng-if="!strike">
<ng-transclude></ng-transclude>
</div>

Manipulating inline style with angular does not work in IE

I wanted to set the position of a div based on the return value of a function in an angular controller
The following works fine in FireFox and in chrome but in Internet explorer {{position($index)}}% is interpreted as a literal string value and therefore has no effect
<div ng-repeat="item in items" style="left:{{position($index)}}%"></div>
Here is an example of the issue:
var app = angular.module('app', []);
app.controller('controller', function($scope) {
$scope.items=[1,2,3,4,5,6,7,8,9,10];
$scope.position=function(i){
var percent =[5,10,15,20,25,30,35,40,45,50,55,60,65,70];
return percent[i+1];
}
});
And here is a Fiddle to demonstrate
Does anyone have suggestions on how to rectify?
You must use ng-style instead of style, otherwise some browsers like IE will remove invalid style attribute values (presence of {{}} etc makes it invalid) before even angular has a chance to render it. When you use ng-style angular will calculate the expression and add the inline style attributes to it.
<div ng-repeat="item in items" ng-style="{left: position($index) + '%'}"></div>
Since you are anyways calculating the position you could as well add % from the position and send it. Also remember that calling a function in ng-repeat will invoke the function every digest cycle, so you may want to be careful not to do too much intensive operations inside the method.
<div ng-repeat="item in items" ng-style="{left: position($index)}">{{item}}</div>
and return
return percent[i+1] + "%";
Demo
If you want to use angular binding expression {{}} just like normal style attribute like style="width:{{someScopeVar}}",
use ng-attr-style and it will work perfectly IE (and obviously other smarter ones) :)
check my jsFiddle ... Checked with Angular JS 1.4.8
here I have shown the usage of style, ng-style and ng-attr-style
THE HTML
<div ng-app="app">
<div ng-controller="controller">
<div style="background:{{bgColor}}">
This will NOT get colored in IE
</div>
<div ng-attr-style="background:{{bgColor}}">
But this WILL get colored in IE
</div>
<div ng-style="styleObject">
And so is this... as this uses a json object and gives that to ng-style
</div>
</div>
</div>
THE JS
var app = angular.module('app', []);
app.controller('controller', function($scope) {
$scope.bgColor = "yellow";
$scope.styleObject = {"background": "yellow"};
});
Yes, ng-style will work to resolve this problem. You can use conditionally style using ternary operator.
HTML:
<div ng-style="{'display':showInfo?'block':'none'}">
</div>

DOM manipulation by angularjs direction

I read that Angularjs directives require a different approach than jquery. I am new to angularjs, so it will be great if somebody can explain how to use directives for this simple example. If you click on bottom div, then it moves (re-parent) the top image to the bottom div. I could add this jquery code on ng-click... but is there a better way?
JQUERY INTENT:
$("#bottom").click(function(){
$("#myimage").appendTo("#bottom");
});
ANGULARJS:
<div ng-app="myapp">
<div data-ng-controller="mycontroller">
<div id="top" style="background-color:red;width:200px;height:200px">
<img id="myimage" src="//placehold.it/150x150">
</div>
<div id="bottom" style="background-color:green;width:200px;height:200px">
</div>
</div>
</div>
Instead of listening for a click in jQuery, you can use Angular's ng-click directive to specify a function to call when the element is clicked and you can use the ng-if directive to add/remove the image, for example...
<div ng-click="appendImage()" id="bottom" style="background-color:green;width:200px;height:200px">
<img ng-if="showImage" id="myimage" src="//placehold.it/150x150">
</div>
Then in your controller...
angular.controller('myController', function ($scope) {
$scope.showImage = false;
$scope.appendImage = function (event) {
$scope.showImage = true;
};
});
A key difference between plain jQuery and Angular is that in jQuery you have to write code to manipulate the DOM yourself (like appending the image). If you use directives properly in Angular, you simply make changes to the $scope and directives will update the DOM for you automatically