Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I add code into my directive with transclude and pass in a parameter in AngularJS?

Tags:

angularjs

I have code like the following that's used in many places in my application and would like to replace some of this HTML with a directive. I realize there is not so much I can replace as the HTML's are so different:

<div class="select-area">
   <span>Subject</span>
   <select data-ng-disabled="option.subjects.length == 0"
           data-ng-model="option.selectedSubject"
           data-ng-options="item.id as item.name for item in option.subjects">
   </select>
</div>

<div class="select-area" data-ng-hide="utilityService.isNotNumber(option.selectedTopic)">
   <span>Subtopic</span>
   <select data-ng-model="option.selectedSubtopic"
           data-ng-options="item.id as item.name for item in option.subtopicsPlus">
   </select>
</div>

I would like to use a directive but I am not really sure how to start. I want to use transclude to replace the inside so I was thinking that my directive call would look something like this:

<div class="select-area" my-select-area="Subject">
   <select data-ng-disabled="option.subjects.length == 0"
           data-ng-model="option.selectedSubject"
           data-ng-options="item.id as item.name for item in option.subjects">
   </select>
</div>

<div class="select-area" data-ng-hide="utilityService.isNotNumber(option.selectedTopic)" my-select-area="Subtopic">
   <select data-ng-model="option.selectedSubtopic"
           data-ng-options="item.id as item.name for item in option.subtopicsPlus">
   </select>
</div>

Here's what I have so far:

app.directive('mySelect', function () {
    return {
        restrict: "A",
        template: "<div class='select-area'>" +
                  "<span> </span>" +

                  "</div>",
    };
});

Can someone show me how I can pass in the parameter that goes inside the span and also how I can add transclude?

Update: Based on Bastien's answer

There were a couple of small syntax errors but based on Bastien's answer I tried the following:

app.directive('mySelect', function () {
    return {
        restrict: "A",
        transclude: true,
        template: "<div class='select-area'>" +
                    "<span> {{ mySelectArea }} </span>" +
                    "<div ng-transclude></div>" +
                  "</div>",
        link: function (scope, element, attrs) {
            scope.mySelectArea = attrs.mySelectArea;
        }
    }
});

Here's my HTML:

<div data-my-select myselectarea="Page type">
   <select data-ng-model="option.selectedPageType"
           data-ng-options="item.id as item.type for item in option.pageTypes"></select>
</div>

Here's the HTML it created:

<div data-my-select="" myselectarea="Page type">
<div class="select-area">
   <span class="ng-binding">  </span>
   <div ng-transclude="">
   <select data-ng-model="option.selectedPageType" 
           data-ng-options="item.id as item.type for item in option.pageTypes" 
           class="ng-scope ng-pristine ng-valid">
      <option value="0">Edit Basic</option>
      <option value="1" selected="selected">Edit Standard</option>
      <option value="2">Report</option>
   </select>
   </div>
</div>
</div>

What I really need is for it to create this:

<div class="select-area">
   <span>Page Type</span>
   <select data-ng-model="option.selectedPageType" 
           data-ng-options="item.id as item.type for item in option.pageTypes" 
           class="ng-pristine ng-valid">
      <option value="0">Edit Basic</option>
      <option value="1" selected="selected">Edit Standard</option>
      <option value="2">Report</option>
   </select>
</div>
like image 249
Alan2 Avatar asked Nov 29 '13 04:11

Alan2


People also ask

What does ng-transclude do in AngularJS?

That’s exactly angularJS does. It provides ng-transclude directive that can be used as a placeholder somewhere in directive’s own content, that then be replaced by element’s content stored in previous step. List of Sale Items.

How to create a custom directive in angular?

Create a custom directive using the @Directive decorator. We will create both custom attribute directive & custom Structural directive. Pass value to it using the @input. Manipulate the DOM element (Change the Appearance) etc. Applies to: Angular 2 to the latest edition of i.e. Angular 8. Angular 9, Angular 10, Angular 11, Angular 12

How to add class to an element in angular?

The Attribute directives can change the appearance or behavior of an element. The Angular has several built-in attribute directives. Let us create a ttClass directive, which allows us to add class to an element. Similar to the Angular ngClass directive.

How do I inject code into an angular component?

One can also create a custom directive which can be used to inject code in the main angular application. Custom directives can be made to call members defined in the scope object in a certain controller by using the ‘Controller’, ‘controllerAs’ and ‘template’ keywords.


2 Answers

About transclusion, I advise you to take a look to this section of the doc. In your case, you have to:

  1. ask for transclusion in the directive definition object
  2. indicate in the template which element will receive the transcluded elements with the ng-transclude directive

That give us this directive:

app.directive('mySelect', function () {
    return {
        restrict: "A",
        transclude: true,
        template: "<div class='select-area'>" +
                    "<span> </span>" +
                    "<div ng-transclude></div>" +
                  "</div>"
    };
});  

About passing a parameter, you have access to the attributes of the directive on the third parameter of the link function:

app.directive('mySelect', function () {
    return {
        restrict: "A",
        transclude: true,
        template: "<div class='select-area'>" +
                    "<span> </span>" +
                    "<div ng-transclude></div>" +
                  "</div>",
        link: function (scope, element, attrs) {

        }
    };
});  

Then, if your parameter is always plain text you can access the value directly:

attrs.mySelectArea      

Otherwise, if your parameter can be in the scope you can use the $parse service to get its value:

$parse(attrs.mySelectArea)(scope)

To display the value in the template, you have to provide it in the scope:

app.directive('mySelect', function () {
    return {
        restrict: "A",
        transclude: true,
        template: "<div class='select-area'>" +
                    "<span> {{ mySelectArea }} </span>" +
                    "<div ng-transclude></div>" +
                  "</div>",
        link: function (scope, element, attrs) {
            scope.mySelectArea = attrs.mySelectArea;
        }
    };

Finally, if you want that your directive template replace the element you can use the replace option (more infos):

app.directive('mySelect', function () {
    return {
        restrict: "A",
        transclude: true,
        replace: true,
        template: "<div class='select-area'>" +
                    "<span> {{ mySelectArea }} </span>" +
                    "<div ng-transclude></div>" +
                  "</div>",
        link: function (scope, element, attrs) {
            scope.mySelectArea = attrs.mySelectArea;
        }
    };

I made a plunker of it.

I strongly advise you to to deep dive into the directive guide and the directive API to have a good sight of what can be done with directives.

like image 189
Bastien Caudan Avatar answered Oct 28 '22 23:10

Bastien Caudan


Using the <div ng-transclude> directive will always result in a wrapping <div> in your rendered html. There are other ways to include the transcluded content programatically. For example, your link function gets passed a transclude function as the last argument. That function takes a callback that lets you attach the transcluded content wherever you like:

    link: function (scope, element, attrs, ctrl, transclude) {
        scope.mySelectArea = attrs.mySelectArea;
        transclude(function(dom){
          element.append(dom);
        });
    }

I've updated the plunkr from the other option using this technique:

http://plnkr.co/edit/sFL9uVt4mx60NtZq41yE?p=preview

like image 3
Daniel Tabuenca Avatar answered Oct 28 '22 21:10

Daniel Tabuenca