0

I have a angular service that manages all my UI tabs. It contains an object that has all the information I need about a tab such as icons, labels, URL, etc. I have a use case for one my tabs to have a dynamic counter on it but I can't figure out how to get it working.

Service snippet:

angular.module('app.services').service('tabService', function($rootScope, $route, $location) {

    var tabs = {
        "/front": {
            "search": {
                label: "Search",
                url: "/search",
                classIcon: "fa fa-search",
                urlMatchAddt: ['/searchResults','/productDetails']
            },
            "order": {
                label: "Order",
                url: "/cart",
                classIcon: "fa fa-shopping-bag"
            }  ....

HTML Code: index.html (tabService is injected into a my BaseCtrl controller)

<body ng-app="app" ng-controller="BaseCtrl">
...
<li ng-repeat="t in tabService.getTabs()" ng-class="{active: tabService.isActiveTab(t.url)}" ng-cloak>
                    <a href="#{{t.url}}"><i class="{{t.classIcon}}" aria-hidden="true" ng-bind-html=""></i>&nbsp;<span ng-bind-html="t.label | trustHTML"></span></a>
                </li>
....
</body>

So what I am trying to do for example is in the label field of one of my tabs I want to put something like

label: "Order - {{counter}}"

So every time I update that {{counter}} variable then my label will also refresh. The label can also contain HTML code which is why I am using ng-bind-html directive.

Currently I am doing an ugly $watch on the variable and when it changes then I am manually just completely overwriting the label value with a new string that includes the updated value.

I have tried using $compile but I cannot use it with $rootScope and I cannot pass $scope into my service. I am unsure what the best solution is.

Any ideas?

AngularJS: 1.6

4
  • Is there any problem with doing <span>{{ t.label }} - {{$index}}</span>? Why are these creepy ng-bind-html there? Commented May 5, 2017 at 23:11
  • @estus some of my label attributes have html. Example would be my counter will be wrapped in a span tag to utilize a fontawesome icons Commented May 5, 2017 at 23:18
  • Then please make the question reflect this. Also, there's some template but it's not clear where it is from. Is it a directive? How is it bound with a service? See stackoverflow.com/help/mcve Commented May 5, 2017 at 23:21
  • @estus updated with extra info Commented May 5, 2017 at 23:50

1 Answer 1

2

Basically there's a need for a directive/component instead of <a ...>...</a>.

There's nothing ugly in $watch itself but doing this in one single controller would be certainly ugly.

To calculate strings like Order - {{counter}}, $compile is total overkill but $interpolate service comes to rescue. Its sole purpose is to to what's required, interpolate Angular expressions to strings.

It likely should be something like

app.directive('tab', function () {
  return {
    scope: {
      tabData: '<',
      counter: '<'
    },
    template: '<a ...>...<span ng-bind-html="interpolatedLabel | trustHTML"></span></a>',
    controller: function ($interpolate, $scope) {
      $scope.$watchGroup(['tabData.label', 'counter'], function () {
        $scope.interpolatedLabel = $interpolate($scope.tabData.label)({
          counter: $scope.counter
        });
      }
    }
  }
});

and

<li ng-repeat="t in tabService.getTabs()"...>
  <tab tab-data="t" counter="$index"></tab>
</li>
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks this seems to work. Its wrecking havoc with my Boostrap CSS but that's another issue entirely I suppose.
Glad it worked for you. Fixed </tab> closing tag in code. You can make it attribute directive like<span tab ...> to fit the layout better, but the proper idiomatic way is to make it element directive (basically a component) and provide styling for it, display: inline or display: inline-block.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.