dcohenb
dcohenb

Reputation: 2127

Bind AngularJS variables into CSS syntax

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

Answers (4)

noj
noj

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:

Updated answer

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>

http://jsfiddle.net/VUeGG/31/


Original answer

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.

http://jsfiddle.net/VUeGG/4/

Upvotes: 24

Campbeln
Campbeln

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 nest objects.
  • $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 (via angular.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 .$evaluated 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

Denis
Denis

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

Matthew Tyler
Matthew Tyler

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

Related Questions