Leveraging ng-transclude and the require attribute for effective communication between directives

I'm working with two directives, let's call them:

angular.module('app').directive('directiveX', directiveX);

    function directiveX(){
        return {
            restrict: 'E',
            transclude: true,
            scope: {},
            templateUrl: 'directiveX.html',
            controller: function($scope){
                $scope.data="some data";
            }
        };
    }

And the second one:

angular.module('app').directive('directiveY', directiveY);

function directiveY(){
    return {
        restrict: 'E',
        require: '^directiveX',
        transclude: true,
        scope: {},
        templateUrl: 'directiveY.html',
        link: function(scope, elem, attrs, directiveXController) {
            console.log("directiveY linked");
        }
    };
}

HTML structure for directiveX:

<div>
<!-- content here -->
    <div ng-transclude></div>
</div>

HTML structure for directiveY:

<div>{{data}}</div>

Now, I want to use them in this manner:

<directive-x>
     <directive-y></directive-y>
</directive-x>

How can I establish communication between them using require and ng-transclude and ensure that both templates are rendered? For instance, I wish to display the data variable from directiveX in the directiveY template. As a newcomer to directives and transclusion, any guidance would be appreciated.

Answer №1

There are various ways to establish communication:

  1. Utilize $broadcast or $emit depending on your scope. Refer to this Stack Overflow question. Broadcasting to $rootScope is recommended as it allows all child components to listen to events.
  2. Implement a callback function (specifically for the child directive).
  3. Implement the Observer pattern.

Check out my demonstration code below or on this jsfiddle.

angular.module('demoApp', [])
.controller('mainController', function($scope) {

})
.service('interDirCom', function() {
    // Observer pattern
    var self = this;
    
    angular.extend(this, {
        subscribers: [],
        subscriberCount: 0,
        newSubscriber: function(callback) {
            return {
                id: self.subscriberCount++,
                notify: callback
            };
        },
        subscribe: function(callback) {
            // Add listener
            var subscriber = self.newSubscriber(callback);
            self.subscribers.push(subscriber);
        },
        notify: function(message){
            console.log('notify', this, self, self.subscribers);
            angular.forEach(self.subscribers, function(subscriber) {
                console.log(subscriber, message);
                subscriber.notify(message);
            });
        }
    });
})
.directive('directiveA', directiveA)
.directive('directiveB', directiveB);

function directiveA() {
    return {
        restrict: 'E',
        transclude: true,
        scope: {},
        templateUrl: 'directiveA.html',
        controller: function ($scope, $rootScope, interDirCom) {
            
            interDirCom.subscribe(function(message) {
                //console.log('callback of subscriber called');
                $scope.test2 = message;
            });
            
            $scope.test = "test data";
            this.test = 'hello from controller A in dir. B';
            
            $rootScope.$on('dirB:test', function(evt, data) {
                console.log('received event', data);
                $scope.test = data.message;
            });
            
            this.callback = function(message) {
                $scope.test2 = message;
            };
        }
    };
}

function directiveB(interDirCom) {
    return {
        restrict: 'E',
        require: '^directiveA',
        transclude: true,
        scope: {},
        templateUrl: 'directiveB.html',
        link: function (scope, elem, attrs, directiveACtrl) {
            console.log("directiveB linked");
            //scope.test = "hello from B";
            scope.test = directiveACtrl.test;
            
            scope.$emit('dirB:test', {message: 'Hello from directive B in dir. A with a $emit to $rootScope'});
            directiveACtrl.callback('I am added with a callback function from dir. B. to dir. A');
            interDirCom.notify('Message from dir. B with observer pattern');
            console.log(interDirCom);
        }
    };
}
directive-b div{
    background-color: green !important;
}

directive-a>div{
    background-color: lightgray;
    border: 2px solid red;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="demoApp" ng-controller="mainController">
    <script type="text/ng-template" id="directiveA.html">
        <div>
            <h1>Directive A</h1>
            {{test}}<br/>
            {{test2}}
            <!-- something here -->
            <div ng-transclude></div>
        </div>
    </script>
    <script type="text/ng-template" id="directiveB.html">
        <div>
        <h1>Directive B</h1>
        <div>{{test}}</div>
            <div>{{test2}}</div>
        </div>
    </script>
    <directive-a>
        <directive-b></directive-b>
    </directive-a>
</div>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Error in Angular Google Maps Component: Unable to access the 'nativeElement' property as it is undefined

I am currently working on creating an autofill input for AGM. Everything seems to be going smoothly, but I encountered an error when trying to integrate the component (app-agm-input) into my app.component.html: https://i.stack.imgur.com/mDtSA.png Here is ...

The Angularfire library encountered an issue when trying to access the 'push' property of a null object

I am currently in the process of creating a new object in the database for an assessment. Right now, I have hardcoded it to test its functionality, but ultimately, it will be dynamic based on user input from the view. However, I am encountering an error th ...

Map checkboxes aren't updating after an array update following a refactor to react hooks

I recently transformed a class component into a function component using hooks. However, I am facing an issue where the checkboxes within a specific mapping are not updating with the checked value. The onChange handler is firing and updating the array corr ...

A guide on adding specific rows together in a list

I'm working with a grid that contains various items and I want to calculate the total of the val_itemservico column only for the selected rows, not all of them. How can I achieve this functionality? When the user clicks on the "Calculate" button, I n ...

How to retrieve a value from PHP using Ajax?

I am struggling to implement ajax for adding a div to display an error message. Despite my efforts, I keep receiving null as the error message instead of the expected value. The occurrence of null is traced back to <?php echo json_encode($_SESSION[&ap ...

Issues with jQuery function arising post-update to newer jQuery version

Recently, I encountered an issue with a function that used to work perfectly fine with jQuery 1.8.3. However, when I upgraded to jQuery 1.10.x or above, the function stopped working. <script type="text/javascript"> $.ajaxSetup({cache: false}); ...

Retrieving HTML elements from the website address

Imagine having a URL like www.example.com. On this webpage, there is a DOM element <a>. To programmatically click on this element, you would typically use document.getElementById('#link')[0].click(). The challenge arises when dealing with ...

Cypress: harnessing the power of regular expressions within jQuery selectors for the ":contains()" method

Trying to use Cypress along with a regular expression to target an element that includes specific text. The following get() function successfully works: cy.get('[data-cy=tile]').contains(new RegExp(myVar)) However, the following command does no ...

Safari re-downloads background image when revisiting with jQuery CSS

Using jQuery to set a background-image on my website: $('.header-image').css('background-image', 'url(/img/image.jpg)'); However, upon returning to the page from Safari, the image is downloaded again, unlike Chrome and F ...

The user could not be deserialized from the session

I am having an issue with deleting users from my database. When a user is logged in and I try to refresh the page after deleting the user, I encounter the following error message: Error: Failed to deserialize user out of session Below is the code snippet ...

AngularJS refrains from computing expressions

As a newcomer to AngularJS, I decided to experiment with some basic code. However, the results were not as expected. Here is the HTML code that I used: <!DOCTYPE html> <html ng-app> <head> <script src="js/angular.min.js"></sc ...

"Encountering a problem with posting API requests using Express

I've encountered a problem where I keep receiving a 404 error when trying to post to a specific route. Here's the code snippet: app.js (code snippet for app.js) .... module.exports = app; api.js (code snippet for api.js) .... module.export ...

Managing errors within AngularJS in your controller.js file

In my NodeJS + AngularJS single page application, there are fields for inputting text. I need to create a function in controller.js to check if any of the fields are empty so that an error alert can be displayed in the browser. This is my controller.js fi ...

Problem with $http.post() in Angular where Codeigniter is not able to receive data

I'm facing a peculiar issue with Codeigniter and Angular. My approach was to configure the controller in the following way: index is a simple Angular page with just one app and one controller get retrieves data from the database set saves data sent u ...

Exploring data visualization within a JSX Component

I am attempting to dynamically render a Card component that is mapped from an array of objects. However, I am encountering an "unexpected token error" and the URL is not rendering as expected. The goal is to display five cards based on the data within the ...

What is the best way to give a fixed height to Card content in Material UI? Is CSS the way to go?

I've been struggling with a design issue involving Material-UI cards used to display News. The problem arises when the paragraph section of the card occupies multiple lines of text. When it spans two lines, there is a 10px spacing between the paragrap ...

What is the reason for not using ng-attr-width to set the width of this SVG?

I am facing a challenge in understanding ng binding on a simple web page I created to experiment with: <html ng-app="AngularSVGTestApp"> <head> <title>Angular SVG Test</title> <style> svg { backgro ...

Achieving optimal performance with scoped CSS in Vue.js

As I work on creating a new app using VueJs, I have noticed the implementation of "css scoped" as shown below: <style scoped> .example { color: red; } </style> <template> <div class="example">hi</div> </template> ...

Adding JSON data to a MySQL column in JSON format with the help of NodeJS

I currently have a MySQL table set up with the following specifications: CREATE TABLE `WorkOrders` ( `workorder_id` int(11) NOT NULL AUTO_INCREMENT, `intertype_id` int(11) NOT NULL, `equipment_id` int(11) NOT NULL, `reason_id` int(11) NOT NULL ...

When the initial image URL returns a 404 error, the ng-src path does not automatically switch to the alternative

I'm currently working on a webpage where I want to show an image only if the URL of that image is valid, using AngularJS. The challenge I'm facing is that ngIf only checks whether a value is null or not. So, even if the URL returns a 404 error, ...