Reputation: 2127
I'm trying to figure out how to bind AngularJS scope vars into CSS syntax. I think that the problem is in the curly braces. Here is what I'm basically trying to do:
<style>.css_class {background:{{ angular_variable }}; color:#ffffff;}</style>
<style>.css_rule {background:{{ "#000000" }}; color:#ffffff;}</style>
<style>.css_rule {background:{{ var | someFilter }}; color:#ffffff;}</style>
Any ideas on how this could be accomplished? Thank you!
Upvotes: 16
Views: 24061
Reputation: 6759
As explained here angular doesn't run on content inside style tags. There's a workaround plunkr in that post but as a more flexible approach I'd just create a directive that grabs the contents, parses them and replaces:
app.directive('parseStyle', function($interpolate) {
return function(scope, elem) {
var exp = $interpolate(elem.html()),
watchFunc = function () { return exp(scope); };
scope.$watch(watchFunc, function (html) {
elem.html(html);
});
};
});
Usage:
<style parse-style>.css_class {color: {{ angular_variable }};}</style>
app.directive('parseStyle', function()
{
return function(scope, elem)
{
elem.html(scope.$eval('\'' + elem.html() + '\''));
};
});
then:
<style parse-style>.css_class {color: ' + angular_variable + ';}</style>
Not sure about the browser support for this though.
Upvotes: 24
Reputation: 2990
Update
I've put together an Angular "plugin" (module+filters+factory) called ngCss that handles this and much more - check it out!
I also have made a Vanilla Javascript (e.g. no external dependencies) version as well; CjsSS.js (GitHub).
ngCss is a tiny* Angular Module+Factory+Filters that enables binding of strings and objects (including nested objects) within CSS. *Minified+compressed script under 1,700 bytes
Features:
- CSS can be live-bound (changes in
$scope
are$watch
'ed) or updated via the custom$broadcast
event updateCss.- css and cssInline Filters output Javascript/JSON
objects
as CSS to enable mixins, including the ability to nestobjects
.$scope
can be initialized within the CSS itself, allowing for all CSS-related information to be co-located within the *.css or STYLE element.$scope
can be isolated or imported from any Angular$element
(viaangular.element($element).scope()
).
Original
Thanks to @jonnyynnoj's code I've figured out a way to keep the {{angular_variable}}
nomenclature within the style tags as well as live binding any changes. Check out the fork of @jonnyynnoj's code for a simple example or have a look below at what I'm using in my apps:
(function (ngApp) {
'use strict';
//# Live bind a <style cn-styler="{ commented: true, usingSingleQuote: true }" /> tag with {{ngVars}}
ngApp.directive('cnStyler', function () {
return {
//# .restrict the directive to attribute only (e.g.: <style cn-styler>...</style>)
restrict: "A",
link: function ($scope, $element, $attrs, controllers) {
//# .$eval the in-line .options and setup the updateCSS function
//# NOTE: The expected string value of the inline options specifies a JSON/JavaScript object, hence the `|| {}` logic
var css, regEx,
options = $scope.$eval($attrs["cnStyler"]) || {},
updateCSS = function () {
//# .$eval the css, replacing the results back into our $element's .html
$element.html($scope.$eval(css));
}
;
//# Setup the .quote and the inverse in .unquote (which we use to process the css)
//# NOTE: In theory, the .unquote should not be present within the css
options.quote = (options.usingSingleQuote !== false ? "'" : '"');
options.unquote = (options.quote === '"' ? "'" : '"');
regEx = new RegExp(options.unquote, "g");
//# Process the $element's .html into css, .replace'ing any present .unquote's with .quote's (this could cause problems), then the {{Angular}} (or /*{{Angular}}*/) variables with ' + stringified_versions + '
if (options.commented !== false) {
css = options.unquote + ($element.html() + '')
.replace(regEx, options.quote)
.replace(/\/\*{{/g, options.unquote + "+")
.replace(/}}\*\//g, "+" + options.unquote)
+ options.unquote;
} else {
css = options.unquote + ($element.html() + '')
.replace(regEx, options.quote)
.replace(/{{/g, options.unquote + "+")
.replace(/}}/g, "+" + options.unquote)
+ options.unquote;
}
//# .$watch for any changes in the $scope, calling our updateCSS function when they occur
$scope.$watch(updateCSS);
}
};
});
})(YOUR_NG_APP_VAR_HERE);
Then you use this directive like this:
<style cn-styler type="text/css">
.myClass{
color: /*{{themeColor}}*/;
}
</style>
Where you have set $scope.themeColor
somewhere in your controller and you've replaced YOUR_NG_APP_VAR_HERE
with your ngApp
variable.
NOTES:
Make sure that your ng-controller
is defined with scope to the <style>
tag as <style>
tag's should be in the <head>
while ng-controller
is generally defined on the <body>
tag or below. TL;DR: Put your ng-controller
on your <html>
tag like so:
<html ng-app="YOUR_NG_APP_VAR_HERE" ng-controller="MyNgController">
Due to CSS parsing and auto-formatting in tools like Visual Studio I added the feature to have the {{Angular}}
vars within CSS comments (e.g. /*{{Angular}}*/
). This is the default behavior of the directive unless you override it like so:
<style cn-styler="{commented: false}" >...</style>
Due to the nature of this solution (the CSS is .$eval
uated as a string with variables inserted within), the presence of single or double quotes within the CSS also needs to be processed. By default, the directive assumes you are using single quotes (') within your CSS which means in order to avoid any introduced errors you should only use single quotes within your CSS as any double quotes present within the CSS will be replaced with single quotes. You can override this default behavior (meaning you're using double quotes within your CSS) like so:
<style cn-styler="{usingSingleQuote: false}" >...</style>
There are edge cases where the replacing of double quotes with single quotes screws up the CSS (such as in content
), so you will want to ensure that you are only using one style of quotes in your CSS (and signaling the directive accordingly) to avoid any potential issues. Thankfully quotes are rarely used in CSS so this is mostly a non-issue.
Upvotes: 3
Reputation: 69
I can't understand why u want use thid idea! U should use ng-class for that!
For example:
<p ng-class="{strike: strike, bold: bold, red: red}">Map Senter code hereyntax Example</p>
Upvotes: 0
Reputation: 326
You shouldn't need the curly braces as these are being evaluated inside html directive - you only need to use the curly braces if you have an expression that is evaluated outside of them ie;
<p ng-class="some-angular-variable">
{{some-angular-variable}}
</p>
In your situation, removing the double-curly braces and using double-quotes should solve the problem.
As an aside, Chandermani is on the money - what you are trying to is better accomplished with the ng-class directive. Using it will allow to apply a class (or several) to the corresponding tag.
ie;
<p ng-class="mystyle">
some text
</p>
say you have two classes style1 and style2
You can select whichever one to apply with
scope.mystyle = "style1" // or whatever
in your controller.
Upvotes: 0