Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multiple custom directives scope in Angular

I have a custom directive that I'd like to have on multiple elements on the page. I'm having difficulty isolating the scope and showing elements based on the child scope. Here's an example of what I'm trying to do:

app.js:

var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
  $scope.name = 'World';
})
.directive('comShowLabelOnFocus', function() {
  return {
    restrict: 'A',
    scope: {
      showlabel: '='
    },
    link: function(scope) {
      scope.inputClicked = function() {
        event.currentTarget.placeholder = '';
        scope.showlabel = true;
      };
    }
  }
});

index.html:

<body ng-controller="MainCtrl">
    <p>Hello {{name}}!</p>


    <div class="form-group medium-6 columns" com-show-label-on-focus>
      <input  
        type="email"
        name="email"
        ng-model="model.email"
        placeholder="Your Email Address"
        ng-click="inputClicked()"/>
      <label ng-show="showlabel">Email Address (Required)</label>
      showlabel is: {{showlabel}}
    </div>

    <div class="form-group medium-6 columns" com-show-label-on-focus>
      <input  
        type="text"
        name="name"
        ng-model="model.name"
        placeholder="Your Name"
        ng-click="inputClicked()"/>
      <label ng-show="showlabel">Name (Required)</label>
      showlabel is: {{showlabel}}
    </div>
  </body>

In action: Plunker

Basically, the field label should appear when the field takes focus. If I comment out that scope declaration in the directive, the showlabel scope variable is the root scope and BOTH labels appear. Thanks.

like image 526
panzhuli Avatar asked Feb 02 '26 19:02

panzhuli


1 Answers

First off, you are expecting the markup inside your div with the attribute directive on it to function like the directive's template. This won't work like you want it to.

Let us define the markup for your directive in the template or templateUrl of your directive object:

return {
    //other properties
    template: '<input type="text" name="name" ng-model="model.name" placeholder="{{myPlaceholder}}" ng-click="inputClicked()"/> <label ng-show="showlabel">{{myLabel}}</label>showlabel is: {{showlabel}}',
}

Next, set up the scope to use the template correctly, and don't bind to showlabel. The directive can manage it on its isolated scope:

scope: {
  myPlaceholder: '@',
  myLabel: '@'
}

Finally, lets see what the Angular docs have to say about the restrict property for directives that have control over their templates:

When should I use an attribute versus an element? Use an element when you are creating a component that is in control of the template. The common case for this is when you are creating a Domain-Specific Language for parts of your template. Use an attribute when you are decorating an existing element with new functionality.

So, since your directive does control its template, you should restrict it to an element.

In the end your directive javascript could look something like this:

.directive('comShowLabelOnFocus', function() {
  return {
    restrict: 'E',
    scope: {
      myPlaceholder: '@',
      myLabel: '@'
    },
    template: '<input type="text" name="name" ng-model="model.name" placeholder="{{myPlaceholder}}" ng-click="inputClicked()"/> <label ng-show="showlabel">{{myLabel}}</label>showlabel is: {{showlabel}}',
    link: function(scope) {
      scope.showlabel = false;
      scope.inputClicked = function() {
        event.currentTarget.placeholder = '';
        scope.showlabel = true;
      };
    }
  }
});

And the markup like this:

<com-show-label-on-focus data-my-placeholder="Your Name" data-my-label="Name (Required)"></com-show-label-on-focus>

And here is your plunker modified and demonstrating this implementation

I apologize for all the edits, I misread your question at first.

like image 147
Nick Avatar answered Feb 05 '26 13:02

Nick



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!