Question

I want to build a simple hello directive that is to be used like so:

<hello foo="bar"></hello>

If the foo attribute equals "bar", I want to replace the element with <div ng-show="true"></div>"; otherwise, replace it with <div ng-show="false"></div>". However, I only one want to replace the hello element, not any of the children nested inside it!

So for example:

<hello foo="bar">
  <h1>Hi everyone!</h1>
</hello>

Would be replaced by this:

<div ng-show="true">
  <h1>Hi everyone!</h1>
</div>

Is this even possible to do?

Was it helpful?

Solution

You can achieve that by using transclusion:

Javascript

app.directive('hello', function() {
  return {
    restrict: 'E',
    transclude: true,
    replace: true,
    scope: { foo: '@' },
    template: '<div ng-show="foo == \'bar\'" ng-transclude></div>',
  };
});

HTML

<hello foo="bar">
  <h1>Hi everyone!</h1>
</hello>

<hello foo="baz">
  <h1>Hi everybody!</h1>
</hello>

Working Plunker here.

OTHER TIPS

Dynamically injecting a directive while compiling/linking another directive is a hairy business. You can't simply set the attribute because it won't be collected by Angular. Manual compilation wouldn't work either because it will cause infinite loop. That being said, if you have already decided that this is what you want :), here you go:

app.directive('hello', function($injector) {
  return {
    transclude: true,
    replace: true,
    restrict: "E",
    template: "<div ng-transclude></div>",
    compile: function(tele, tattrs) {
      var ngShow = $injector.get("ngShowDirective")[0];
      return function(scope, ele, attrs) {
        attrs.$set("ngShow", (attrs.foo === "bar").toString());
        ngShow.link(scope, ele, attrs);
      }
    }
  }
});

The idea is to manually link the the ngShow directive instead of relying on AngularJS to do that. Normally, only AngularJS invokes compile and link; plus, this code relies on the knowledge that ngShow has a link function. In general, it should be considered a hack and used with care.

Demo link

You should just be able to apply the ng-show attribute to the hello element and check a property of the model to see if it should be hidden.

<hello ng-show="foo == 'bar'">
    <h1>Hi everyone!</h1>
</hello>

And on a scope that is accessible by this view you'd have a foo property.

$scope.foo = 'bar';
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top