Nilzone-
Nilzone-

Reputation: 2786

Use link function in directives to append different HTML elements

Fiddle

I have two buttons. When pressed it displays a modal, with som text. But I also want to add some html dynamically depending on which button is pressed.

I have tried both $observe and $watch methods, but I'm having problems making it work.

here is my code.

angular.module('TM', [])

.controller('protocolCtrl', function(){
    this.text = 'Now looking at the protocol part';
    this.modalId = 'protocolModal';
})

.controller('categoryCtrl', function(){
    this.text = 'Now looking at the category part';
    this.modalId = "categoryModal";
})

.directive('modalDirective', function(){
    return {
        restrict: 'E',
        scope: {
            ctrl: '=',
            modalId: '@',
        },
        template:  ['<div id="{{modalId}}" class="modal fade" role="dialog">', 
                      '<div class="modal-dialog">',
                        '<div class="modal-content">',
                        '<div class="modal-header">',
                        '<h4 class="modal-title">Modal Header</h4>',
                        '</div>',
                        '<div class="modal-body">',
                        '<p> {{ ctrl.text }} </p>',
                        '</div>',
                        '<div class="modal-footer">',
                        '<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>',
                        '</div>',
                        '</div>', 
                        '</div>',
                        '</div>'].join(''),
        link: function(scope, element, attrs) {
            element.$observe('modalId', function(){
                var modal = element.find('#{{modalId}}');
                if(modal == 'protocolModal'){
                    element.find('#{{modalId}}').append('<div>this is a protocol test...</div>');
                } else {
                    element.find('#{{modalId}}').append('<div>this is a category test...</div>');
                }
            });
        }
    }
});

Upvotes: 0

Views: 540

Answers (3)

Joy
Joy

Reputation: 9560

If your two DOM structure diverses, you can consider using two different templates depending on some parameter value.

templateUrl can be specified as a function, such as:

angular.module('Joy', [])
    .controller('ProfileCtrl', ['$scope', function ($scope) {
    $scope.user = {
        name: 'Elit'
    };
}])
    .directive('profile', [function () {
    return {
        restrict: 'A',
        templateUrl: function (elem, attrs) {
            return 'style-' + attrs.color + '.html';
        }
    };
}]);

And use the directive as:

<div ng-app="Joy" id="play-ground" ng-controller="ProfileCtrl">
    <div profile color="red"></div>
    <div profile color="green"></div>
</div>

In this case, if the color is red, the directive will load template from style-red.html. Otherwise from style-green.html.

In your case, you might maintain a flag in the outside controller. Clicking either button will change this flag value and pass in to the directive. The directive will load different templates accordingly.

Upvotes: 0

Keval Bhatt
Keval Bhatt

Reputation: 6322

See i updated your Fiddle

Use attr in link function. because you already given attribute to your html i.e: modal-id="{{pctrl.modalId}}

 <modal-directive ctrl="pctrl" modal-id="{{pctrl.modalId}}"></modal-directive>


  if(attrs.modalId == 'protocolModal'){
     element.find('#{{modalId}}').append('<div>this is a protocol test...</div>');
  } else {
     element.find('#{{modalId}}').append('<div>this is a category test...</div>');
  }

Edit :

use $timeout

$timeout(function () {

                if (attrs.modalId == 'protocolModal') {
                    element.find('#' + attrs.modalId).append('<div>this is a protocol test...</div>');
                } else {
                    element.find('#' + attrs.modalId).append('<div>this is a category test...</div>');
                }

            }, 1000)

Now why $timeout because you are applying template and and at same time your link function append your div so it will not apply your div .So first apply template and then in template append your div


And if you want to show that div in popup content the use this selector. see this example: https://jsfiddle.net/kevalbhatt18/o76hxj69/6/

element.find('#'+attrs.modalId +' .modal-body').append('<div>this is a protocol test...</div>');

Upvotes: 0

New Dev
New Dev

Reputation: 49590

I don't think there is element.$observe - there is attrs.$observe and scope.$watch. You already have modelId on the scope, so let's use that.

Also, instead of the wonky .find by id, inject an element as a placeholder for the template and replaceWith it accordingly:

template: '<div id="{{modalId}}">\
             ...\
             <div class="modal-body">\
               <template-placeholder></template-placeholder>\
             </div>\
           </div>",
link: function(scope, element){
  // ...

  var unwatch = scope.$watch("modalId", function(val){
    var placeholder = element.find('template-placeholder');
    if(val == 'protocolModal'){
       placeholder.replaceWith('<div>this is a protocol test...</div>');
    } else {
      placeholder.replaceWith('<div>this is a category test...</div>');
    }

    unwatch(); // seems like you don't really need to set it again
  }
}

Upvotes: 1

Related Questions