0

I'm trying to get the materialize library to work together with Angular. To do so I've written an attribute directive that will initialize the dropdown menu on an element.

However, the directive throws an exception (see the dev tools) in the case where the data-activates attribute uses a double-curly-brace expression. Here's a repro (with, for reference, a hard-coded working version as well):

angular.module('foo', [])
  .directive('materialKebab', function() {
    return {
      link: function(scope, element, attrs) {
        $(element).dropdown();
      }
    };
  })
  .controller('bar', function($scope) {
    $scope.id = "abc123";
  });
.dropdown-button { cursor: pointer; background: #ddd; padding: 10px; display: inline-block; font-weight: bold; }
<link href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.7/css/materialize.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.7/js/materialize.js"></script>

<div ng-app="foo" ng-controller="bar">
  Doesn't work:
  <div class="dropdown-button" data-activates="item_{{id}}" material-kebab>⋮</div>
  <ul class="dropdown-content" id="item_{{id}}">
    <li>Action 1</li>
    <li>Action 2</li>
  </ul>
</div>
<hr>
<div>
  Hard coded one works:
  <div class="dropdown-button" data-activates="hardCodedId">⋮</div>
  <ul class="dropdown-content" id="hardCodedId">
    <li>Action 1</li>
    <li>Action 2</li>
  </ul>
</div>

The exception is from jQuery (Sizzle, to be precise):

Error: Syntax error, unrecognized expression: #item_{{id}}

So apparently the dropdown is being activated too early? I've tried setting a priority for my directive to try and make it happen after the other attribute was properly populated, but that didn't seem to work. I've also checked this Github repo with angular-materialize features, but it seems to have no special consideration for this case either.

Is there any good solution to this? Or do I have to resort to watching the $scope.id variable before calling dropdown()?

Community
  • 1
  • 1
Jeroen
  • 60,696
  • 40
  • 206
  • 339

1 Answers1

0

Some more searching, and I found the answer. Posting it as such, should it help any other passer-by, and perhaps someone else can come up with a better answer?

The question is just about a duplicate of a combination of two questions:

So, just use ng-attr- prefix on both data-activates and id and you're good to go:

angular.module('foo', [])
  .directive('materialKebab', function() {
    return {
      link: function(scope, element, attrs) {
        $(element).dropdown();
      }
    };
  })
  .controller('bar', function($scope) {
    $scope.id = "abc123";
  });
.dropdown-button { cursor: pointer; background: #ddd; padding: 10px; display: inline-block; font-weight: bold; }
<link href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.7/css/materialize.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.7/js/materialize.js"></script>

<div ng-app="foo" ng-controller="bar">
  Now does work:
  <div class="dropdown-button" ng-attr-data-activates="item_{{id}}" material-kebab>⋮</div>
  <ul class="dropdown-content" ng-attr-id="item_{{id}}">
    <li>Action 1</li>
    <li>Action 2</li>
  </ul>
</div>
Community
  • 1
  • 1
Jeroen
  • 60,696
  • 40
  • 206
  • 339
  • I have the same exact issue. Using the same exact frameworks (AngularJs+Materialize), I'm trying to do the exact same thing (activate a dropdown with a dynamic "data-activates" value). I've deployed your solution (wich seems brilliant to me) but it doesn't work for me. According to your experience, could it be related to the fact that my directive is inside an ngRepeat directive? Thanks – Simentesempre Oct 19 '17 at 16:45
  • @Simentesempre Thank you for your kind words. Unfortunately I don't have access to the codebase anymore so I cannot check if it was or wasn't inside a repeater. I suggest taking my snippet in this answer and copying it to a new question where it's wrapped in an ngRepeat (or whatever else you need to reproduce your scenario), possibly linking here explaining how your situation/question is different. Good luck! – Jeroen Oct 19 '17 at 21:09
  • thanks for your answer. Well I already created a question before finding this one. Now I've edited it with your new informations. Here's the [link](https://stackoverflow.com/questions/46790943/multiple-dropdown-menus-using-angularjs-materialize-css) – Simentesempre Oct 20 '17 at 07:34