Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I access the ngStyle key and values in decorator?

I have a list of colour names in my application.

let colours = {
  mango: '#e59c09',
  midnight: '#1476a0'
};

I want to extend the ngStyle directive to be able to understand my custom colour names. I'm doing this by decorating the ngStyle directive. However, I've hit an uphill battle on the decorator's compile function. I can access the elements' ngStyle attribute, but it comes up as a string (understandably). JSON.parse() doesn't work on it as it isn't always a valid JSON string due to bind once etc...

I simply want to step-in, iterate over all style keys, and if it contains color, I want to check for the value - and replace with hex if it is one of the above custom colour.

I can't seem to be able to access any ngStyle internal functions, and the source code is confusing and short; it seems to just set element CSS - where does the $parse do its job? for example, when ng-style="{color: ctrl.textColor}" - there is nothing in ngStyle source code that is pulling the value of ctrl.textColour. Am I looking at the wrong place?

Anyway, how do I access ng-style key values so that I can change custom colours to its hex codes please?

This is what I've got so far in my decorator:

$provide.decorator('ngStyleDirective', function($delegate) {

    let directive = $delegate[0];
    let link = directive.link;

    directive.compile = function(element, attrs) {

        // Expression here is a string property
        let expression = attrs.ngStyle;

        return function(scope, elem, attr) {

          // How do I iterate over and update style values here?

          // Run original function
          link.apply(this, arguments);

        }

      }

      return $delegate;

});

I tried using regex to pull out patterns etc. and inspect elements, but, it seems like the wrong way to approach the problem to me as I then have to manually update string and pass it on to base link function.

Here's a plnkr example.

IF there is a better way to do what I'm trying to do, please let me know.

like image 667
LocustHorde Avatar asked Jun 27 '17 15:06

LocustHorde


People also ask

What is the difference between NgStyle and NgClass?

ng-style is used to interpolate javascript object into style attribute, not css class. And ng-class directive translates your object into class attribute.

Can we use NgClass and NgStyle together?

Combining NgStyle and NgClass Directives with our knowledge of Angular Template Syntax, we can marry conditional styling with Angular's Property & Event Binding.

What is NgStyle directive?

The ng-style directive specifies the style attribute for the HTML element. The value of the ng-style attribute must be an object, or an expression returning an object. The object consists of CSS properties and values, in key value pairs.


1 Answers

Anyway, how do I access ng-style key values so that I can change custom colours to its hex codes please?

The ngStyle property can be re-written within the compile function:

directive.compile = function(element, attrs) {
  let expression = getExpressions(attrs.ngStyle);
  attrs.ngStyle = expression;

  return function(scope, elem, attr) {
    // Run original function
    link.apply(this, arguments);  
  }
}

JSON.parse()

JSON.parse() can be used if the HTML is updated so that the keys are surrounded by double quotes, which means the ng-style attribute needs to be delimited with single-quotes (though if one really wanted, one could try to escape the double quotes...)

<p ng-style='{ "color": "#e59c09" }'>Hello {{name}}!</p>
<p ng-style='{ "padding": "20px 10px", "background-color": "#1476a0", "color": "#ddd" }'>It is dark here</p>

Then parsing that string should yield a valid object, and Object.keys() can be used to iterate over the keys, checking for the word color. If the key contains color, Array.indexOf can be used to check if the value exists in the colors array. If it does exist in the array, then String.replace() can be used to substitute the value for the variable (i.e. the key in colours).

function getExpressions(str) {
    var parsed = JSON.parse(str);
    Object.keys(parsed).forEach(function(key) {
        if (key.indexOf('color') > -1) {
            if (Object.keys(colours).indexOf(parsed[key]) > -1) {
                str = str.replace(parsed[key], colours[parsed[key]])
            }
         }
    });
    return str;
}

See it demonstrated in the example below. By the way, I had to remove the unused variable colours declared within the scope of the function getExpressions(), as it was hiding access to the variable defined above on line 3. Here is an updated plunker.

let app = angular.module('plunker', []);
let colours = {
  mango: '#e59c09',
  midnight: '#1476a0'
};
app.controller('MainCtrl', function($scope) {
  $scope.name = 'World';
});
app.config(function($provide) {
  // Extract colour values from the string
  function getExpressions(str) {
    var parsed = JSON.parse(str);
    Object.keys(parsed).forEach(function(key) {
      if (key.indexOf('color') > -1) {
        if (Object.keys(colours).indexOf(parsed[key]) > -1) {
          str = str.replace(parsed[key], colours[parsed[key]])
        }
      }
    });
    return str;
  }

  $provide.decorator('ngStyleDirective', function($delegate) {
    let directive = $delegate[0];
    let link = directive.link;

    directive.compile = function(element, attrs) {
      let expression = getExpressions(attrs.ngStyle);
      attrs.ngStyle = expression;
      return function(scope, elem, attr) {
        // Run original function
        link.apply(this, arguments);
      }
    }
    return $delegate;
  });
});
div + div {
  margin-top: 60px;
}

.comment { 
  font-family: courier;
  font-size: 12px;
  margin: 15px 0;
}
<script src="https://code.angularjs.org/1.4.12/angular.js"></script>
<div ng-app="plunker" ng-controller="MainCtrl">
  <div>
    <p class="comment">--- with hex --</p>
    <p ng-style='{ "color": "#e59c09" }'>Hello {{name}}!</p>
    <p ng-style='{ "padding": "20px 10px", "background-color": "#1476a0", "color": "#ddd" }'>It is dark here</p>
  </div>

  <div>
    <p class="comment">--- with custom colours --</p>
    <p ng-style='{ "color": "mango" }'>Hello {{name}}!</p>
    <p ng-style='{ "padding": "20px 10px", "background-color": "midnight", "color": "#ddd" }'>It is dark here</p>
  </div>
</div>
like image 185
Sᴀᴍ Onᴇᴌᴀ Avatar answered Oct 21 '22 11:10

Sᴀᴍ Onᴇᴌᴀ