How to create this custom control with AngularJS directive?

21,365

Solution 1

If you want to make your directives reusable not just on the same page, but across multiple AngularJS apps, then it's pretty handy to set them up in their own module and import that module as a dependency in your app.

I took Cuong Vo's plnkr above (so initial credit goes to him) and separated it out with this approach. Now this means that if you want to create a new directive, simply add it to reusableDirectives.js and all apps that already have ['reusableDirectives'] as a dependency, will be able to use that new directive without needing to add any extra js to that particular app.

I also moved the markup for the directive into it's own html template, as it's much easy to read, edit and maintain than having it directly inside the directive as a string.

Plnkr Demo

html

<zurb-select data-label="{{'Select an option'}}" data-options="names" 
  data-change-callback="callback(value)"></zurb-select>

app.js

// Add reusableDirectives as a dependency in your app
angular.module('angularjs-starter', ['reusableDirectives'])
.controller('MainCtrl', ['$scope', function($scope) {
  $scope.names = [{name: 'Gavin'}, {name: 'Joseph'}, {name: 'Ken'}];
  $scope.callback = function(name) {
    alert(name);
  };
}]);

reusableDirectives.js

angular.module('reusableDirectives', [])
.directive('zurbSelect', [function(){
  return {
    scope: {
      label: '@', // optional
      changeCallback: '&',
      options: '='
    },
    restrict: 'E',
    replace: true, // optional 
    templateUrl: 'zurb-select.html',
    link: function(scope, element, attr) { }
  };
}]);

zurb-select.html

<div class="row">
  <div class="large-12 columns">
    <label>{{label || 'Please select'}}</label>
    <select data-ng-model="zurbOptions.name" data-ng-change="changeCallback({value: zurbOptions.name})" 
       data-ng-options="o.name as o.name for o in options">
    </select>
  </div>
</div>

Solution 2

Is something like this what you're looking for?

http://plnkr.co/edit/wUHmLP

In the above example you can pass in two attribute parameters to your custom zurbSelect directive. Options is a list of select option objects with a name attribute and clickCallback is the function available on the controller's scope that you want the directive to invoke when a user clicks on a section.

Notice there's no code in the link function (this is where the logic for your directive would generally go). All we're doing is wrapping a template so that it's reusable and accepts some parameters.

We created an isolated scope so the directive doesn't need to depend on parent scopes. We binded the isolated scope to the attribute parameters passed in. The '&' means bind to the expression on the parent scope calling this (in our case the callback function available in our controller) and the '=' means create a two way binding between the options attribute so when it changes in the outter scope, the change is reflected here and vice versa.

We're also restricting the usage of this directive to only elements (). You can set this to class, attributes, etc..

For more details the AngularJs directives guide is really good:

http://docs.angularjs.org/guide/directive

Hope this helps.

Share:
21,365
cpeele00
Author by

cpeele00

Updated on July 09, 2022

Comments

  • cpeele00
    cpeele00 almost 2 years

    I'm a bit new to AngularJS and am trying to write a custom select control based on Zurb Foundation's custom select(see here: http://foundation.zurb.com/docs/components/custom-forms.html)

    I know I need to use a directive for this but am not sure how to accomplish this.

    It's going to have to be reusable and allow for the iterating of whatever array is passed in to it. A callback when the user selects the item from the dropdown list is probably needed.

    Here is the markup for the custom Foundation dropdown list:

        <select name="selectedUIC" style="display:none;"></select>
        <div class="custom dropdown medium" style="background-color:red;">
            <a href="#" class="current custom-select">Please select item</a>
            <a href="#" class="selector custom-select"></a>
            <ul ng-repeat="uic in uics">
                <li class="custom-select" ng-click="selectUIC(uic.Name)">{{uic.Name}}</li>
            </ul>
        </div>
    

    This works for now. I am able to populate the control from this page's Ctrl. However, as you can see, I'd have to do this every time I wanted to use a custom dropdown control.

    Any ideas as to how I can turn this baby into a reusable directive?

    Thanks for any help!

    Chris

  • cpeele00
    cpeele00 about 11 years
    This looks great! Thanks Cuong!
  • cpeele00
    cpeele00 about 11 years
    Thanks for the great explanation! This really helped!
  • kij
    kij about 11 years
    Clear & usefull, +1 for sure! Thanks for all details
  • Jure Triglav
    Jure Triglav about 11 years
    I added the foundation styles to this plnkr, so it is exactly what the questions is about, but it doesn't work. Any ideas why? plnkr.co/edit/xEyEOZ Update: I added ng-init="menuOpen=false" ng-class="{open: menuOpen}" ng-click="menuOpen = !menuOpen" to the custom dropdown div, and it works now. Update 2: It doesn't, actually, the ng-repeat should be on the li element, not on the ul. I fixed that in my plnkr.