2

I'm working on a project where I use both angularJS and foundation, so I'm making use of the Angular Foundation project to get all the javascript parts of foundation working. I just upgraded from 0.2.2 to 0.3.1, causing a problem in the top bar directive.

Before, I could use a class has-dropdown to indicate a "top-bar" menu item that has a dropdown in it. Since the menu items are taken from a list and only some have an actual dropdown, I would use the following code:

<li ng-repeat="item in ctrl.items" class="{{item.subItems.length > 0 ? 'has-dropdown' : ''}}">

However, the latest version requires an attribute of has-dropdown instead of the class. I tried several solutions to include this attribute conditionally, but none seem to work:

<li ng-repeat="item in ctrl.items" has-dropdown="{{item.subItems.length > 0}}">

This gives me a true or false value, but in both cases the directive is actually active. Same goes for using ng-attr-has-dropdown.

this answer uses a method of conditionally applying one or the other element, one with and one without the directive attribute. That doesn't work if the same element is the one holding the ng-repeat so i can't think of any way to make that work for my code example.

this answer I do not understand. Is this applicable to me? If so, roughly how would this work? Due to the setup of the project I've written a couple of controllers and services so far but I have hardly any experience with custom directives so far.

So in short, is this possible, and how?

3
  • 1
    I think you'll have to use a directive that returns the <li> with has-dropdown based off whatever your condition is. I'm searching for an answer. I haven't had to do this yet, but it sounds like something I could eventually run into Commented Sep 8, 2014 at 19:36
  • I found this answer, and now I think why it doesnt works for you ? jsfiddle.net/gleezer/sCC72/2 it should work Commented Sep 8, 2014 at 19:50
  • Thanks Narek, but you didn't really read my question. My problem is a bit more complicated than that. Commented Sep 8, 2014 at 19:56

2 Answers 2

1

As per this answer, from Angular>=1.3 you can use ngAttr to achieve this (docs):

If any expression in the interpolated string results in undefined, the attribute is removed and not added to the element.

So, for example:

<li ng-repeat="item in ctrl.items" ng-attr-has-dropdown="{{ item.subItems.length > 0 ? true : undefined }}">

angular.module('app', []).controller('testCtrl', ['$scope',
  function ($scope) {
    $scope.ctrl = {
      items: [{
        subItems: [1,2,3,4], name: 'Item 1'
      },{
        subItems: [], name: 'Item 2'
      },{
        subItems: [1,2,3,4], name: 'Item 3'
      }]
    };
  }
]);
<div ng-app="app">
  <ul ng-controller="testCtrl">
    <li ng-repeat="item in ctrl.items" ng-attr-has-dropdown="{{ item.subItems.length > 0 ? true : undefined }}">
      {{item.name}}
    </li>
  </ul>
</div>

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks, this is actually a better (more canonical) answer now that it's fixed in Angular itself.
1

Ok, I made a directive. All <li> will need an initial attr of:

is-drop-down="{{item.subItems.length > 0}}"

Then the directive checks that value and for somereason its returning true as a string. Perhaps some onc can shed some light on that

app.directive('isDropDown', function () {
    return {
        link: function (scope, el, attrs) {
           if (attrs.isDropDown == 'true')
           {
               return el.attr('has-dropdown', true); //true or whatever this value needs to be
           }
       }
    };
});

http://jsfiddle.net/1qyxrcd3/

If you inspect test2 you will see it has a has-dropdown attribute. There is probably a cleaner solution, but this is all I know. I'm still new to angular.

edit I noticed a couple extra commas in my example json data..take note, still works, but they shouldn't be there.

9 Comments

This is great, thanks! I'm still trying to work it into my application but it does seem a huge step in the right direction. I'm currently getting the following error (in browser console): "Error: [$compile:ctreq] Controller 'hasDropdown', required by directive 'topBarDropdown', can't be found!". I have the feeling this means that the hasDropdown is already required at a stage during interpreting the page before your directive has kicked in. Is that possible? And is it possible to change the timing so that it's there in time? (the attribute is visible in the DOM so that's something)
Where did you place the directive above? If you just copy/pasted, you have to be sure your app variable is indeed named app. app.directive won't work unless you have specified var app = angular.module('YourApp',[]); If its something like var myAwesomeApp = angular.module(...) then the directive would be myAwesomeApp.directive(...)
Hey, I'm pretty sure I placed it correctly, my app is a lot bigger/more complicated than a basic 1 js file setup, but since the attributes do appear and console logs also show at the right times I'm fairly certain it works on a basic level. I'll try to move around the include for the directive, but I think it has to do with the Angular-Foundation "topBarDropDown" directive which requires the 'hasDropdown' directive to be present.. which it is but chronologically not in the right order.
I just realised I'm asking the wrong question probably. I'm not conditionally applying an attribute, I'm trying to conditionally apply a directive. Your answer is the right one for the question in the title.
ok so the attribute has-dropdown will always be there? Can you give me an example of one computed condition versus the other? Not sure what you mean by conditionally apply a directive.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.