Misha Moroshko
Misha Moroshko

Reputation: 171321

AngularJS: How to implement a directive that outputs its markup?

DEMO

Imagine I have some markup, e.g.:

<my-input model="data.firstName"></my-input>

Now, I would like to create a my-markup directive that will add a button to show/hide its markup.

So, this:

<div my-markup>
  <my-input model="data.firstName"></my-input>
</div>

should result in this:

enter image description here

and when the button is clicked, the markup should appear:

enter image description here

The my-markup directive should not break any data bindings of its children.

Here is my attempt to implement this.

The markup appears, but the button doesn't work. Any ideas how to fix this?

PLAYGROUND HERE

Upvotes: 1

Views: 674

Answers (2)

sylwester
sylwester

Reputation: 16498

Please see below

function escapeHtml(html) {
  return html.replace(/&/g, '&amp;')
    .replace(/</g, '&lt;')
    .replace(/>/g, '&gt;')
    .replace(/"/g, '&quot;');
}

angular.module('App', []).controller('AppCtrl', function($scope) {
  $scope.data = {
    firstName: 'David'
  };
}).directive('myInput', function() {
  return {
    restrict: 'E',
    scope: {
      model: '='
    },
    template: '<input class="my-input" type="text" ng-model="model">'
  };
}).directive('myMarkup', function() {
  return {
    restrict: 'A',
    scope: {},
    link: function(scope, elem, attr) {

    },
    compile: function(element) {
      var showButton = '<button ng-if="data.showMarkup" ng-click="data.showMarkup=!data.showMarkup">Hide Markup</button>';
      var hideButton = '<button ng-if="!data.showMarkup" ng-click="data.showMarkup=!data.showMarkup">Show Markup</button>';
      var markup = '<pre ng-if="data.showMarkup">' + escapeHtml(element.html()) + '</pre>';

      element.append(showButton);
      element.append(hideButton);
      element.append(markup);

      return function(scope, element) {
        scope.data = {
          showMarkup: true
        };
      };
    }
  };
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>

<body ng-app="App" ng-controller="AppCtrl">
  <pre>data = {{ data | json }}</pre>
  <div my-markup>
    <my-input model="data.firstName"></my-input>
  </div>
</body>

Upvotes: 1

PSL
PSL

Reputation: 123739

Here is my approach. Couple of things:-

1) Instead of isolated scope on myMarkup, create a child scope, ultimately the actual directive myInput will be isolated. This would be required if you do need to support multiple myMarkup directive under the same scope.

2) You need a click event on the button, i wouldn't do logic on the markup instead abstract out to a method on the scope.

3) You would just need one button, do not need 2 buttons. Just change the text of the button.

.directive('myMarkup', function($compile) {


  return {
    restrict: 'A',
    scope: true, //Create a child scope
    compile: function(element) {
      //Just need one button
      var showButton = '<button  ng-click="toggleMarkup()">{{model.showMarkup ? "Hide": "Show"}} Markup</button>';
      var markup = '<pre ng-show="model.showMarkup">' + escapeHtml(element.html()) + '</pre>';

      //append the markups
      element.append(showButton).append(markup);

      return linker;
     }
   };

    function linker(scope, element) {
        scope.model = {
          showMarkup: false
        };
        //Click event handler on the button to toggle markup
        scope.toggleMarkup = function(){
          scope.model.showMarkup = !scope.model.showMarkup;
        }
    };
});

Demo

Upvotes: 2

Related Questions