简体   繁体   中英

Dynamically add a directive in AngularJS

I'm having some problems with a directive that I want to be dynamically added as the user clicks a button. What would be the best approach to achieve this?

In my research I've found element.bind (from jqLite), but I haven't found lots of examples on the internet.

Here's my code:


HTML CODE

 <div class="form-group"> <button class="btn btn-info" ng-click="addAttr()">Add Atributtes</button> </div> <addattributes options="attributes" attr="obj"></addattributes> 


ANGULARJS DIRECTIVE

 .directive('addattributes', function () { return { restrict: 'E', scope: { attributes: '=options', attr: '=' }, template: '<div ng-class="classInput">' + ' <div class="col-md-8" style="padding-left: 0;">' + ' <label>Nome do Atributo</label>' + ' <input type="text" class="form-control" placeholder="Attrs name" ng-model="attrname" ng-change="validation()">' + ' </div>' + ' <div class="col-md-4" style="padding-right: 0;"> ' + ' <label>Tipo do Atributo</label> ' + ' <select class="form-control" ng-options="attribute.name for attribute in attributes" ng-model="attrtype"></select>' + ' </div> '+ ' <div class="clearfix"> '+ ' <div> '+ ' <button type="button" class="btn btn-default btn-xs pull-right" ng-click="changeButton()" style="margin-top: 1em;" ng-show="showBtn == true"> Adicionar </button> ' + ' </div> {{attr}}'+ '</div>', link: function(scope,element,attrs){ scope.showBtn = true; scope.classInput = 'form-group'; scope.attrtype= scope.attributes[2]; scope.changeButton = function(){ scope.showBtn = false; scope.attr = { name: scope.attrname, type: scope.attrtype }; } scope.validation = function(){ if(scope.attrname.length < 6) { scope.classInput = 'form-group has-error'; } else { scope.classInput = 'form-group has-success'; } } } };}) 

Thanks in advance, have a great day!

You don't "add a directive" in the controller. This means that you are manipulating DOM, which you should not do.

Instead, think in terms of ViewModel. What ViewModel property does this directive display/alter? Say it is an "attribute", so add an attribute to $scope.myAttributes (to avoid name collision with some attributes property that you have) array.

$scope.myAttributes = [];
$scope.addAttr = function(){
   $scope.myAttributes.push({}); // empty object to hold some property of an "attribute"
}

Then, in the View, ng-repeat over attributes :

<div class="form-group">
    <button class="btn btn-info" ng-click="addAttr()">Add Atributtes</button>
</div>
<addattributes ng-repeat="attribute in myAttributes" attr="attribute"></addattributes>

(I'm not fully understanding what your addattributes directive does, so I'm assuming that it sets an attribute object via attr )

Without giving some details of your use-case, it's hard to tell whether what you're trying to achieve could be more simply (and importantly more intuitively) done with ng-show , ng-switch or some other ng- directive, but we'll assume that your approach is well thought through.

As @New Dev has already pointed out in another answer, you should try to keep DOM manipulation inside a directive, and NOT in a controller - this will help with testability, separation of concerns, and many, many other things.

The below code demonstrates how to do what you're trying to do, but in an abstract way, because your example looks too complex for a simple answer.


If your directive is an element called newDirective adding it is a three step process:

  1. Create the element and append it to the DOM
  2. Compile the element
  3. Link it to a scope

You should do this in the link function of a directive where you have access to the element:

link: function (scope, element, attributes) {    
  scope.addDirective = function () {
  // create the new directive element
    $newDirective = angular.element('<new-directive>');
    // Append it to the DOM
    element.append($newDirective);
    // compile it and link it to the scope
    $compile($newDirective)(scope);
  }
}

Note that a directive's compile function returns its link function, so the compile & link is actually two steps in one line.

See the runnable code snippet below. myDirective adds newDirective s. The newDirective 's template contains a button that removes it. Clicking the remove button works, proving the link function has been run and the directive is functioning properly.

 angular.module('app', []) .directive('myDirective', function ( $compile ){ return { restrict: 'E', template: '<button ng-click="addDirective()">Click me!</button>', link: function (scope, element, attributes) { scope.addDirective = function () { // create the new directive element $newDirective = angular.element('<new-directive>'); // Append it to the DOM element.append($newDirective); // compile it and link it to the scope $compile( $newDirective )(scope); } } } }) .directive('newDirective', function ( $compile ){ return { restrict: 'E', template: '<li>{{someText}}' + '<button ng-click="remove()">Remove</button>' + '</li>', link: function (scope, element, attributes) { scope.someText = "If the scope is linked this will show"; scope.remove = function () { element.remove() } } } }); 
 <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"> </script> <div ng-app="app"> <my-directive></my-directive> </div> 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM