How to replace directive controller function in AngularJS

Here is the issue that needs to be addressed. I am working with a third party directive named main-directive.

app.directive('mainDirective', function() {
  return {
    scope: {
      foo: '&'
      // attrs
    },
    controller: function($scope) {

      $scope.click = function() {
        window.alert($scope.foo());
      }

    },
    template: '<button ng-click="click()">Click me</button>'
  }
});

My goal is to create a custom directive called parent-directive which will set default values for the attributes of the third party directive.

app.directive('parentDirective', function() {
  return {
    scope: {
      foo: '&?',
      attr2: '='
        // lots of attrs
    },
    controller: function($scope) {


      $scope.attr1 = "some default value"

      $scope.foo = function() {
        return "not overrided"
      }

      if (this.foo) {
        $scope.foo = this.foo
      }

    },
    template: '<div class="some-styling"><main-directive foo="foo()" attr1="attr1" attr2="attr2"></main-directive></div>'
  }
});

If I need to create another directive, let's say child-directive, which should inherit the logic from parent-directive. Overloading attributes can be easily achieved using the "compile" function. But how can functions be overridden?

app.directive('childDirective', function() {

  return {
    scope: false,
    require: 'parentDirective',
    link: function(scope, element, attr, controller) {

      controller.foo = function() {
        return "overrided";
      }

    },
    compile: function(element, attr) {
      attr.attr2 = "attr2";
    }
  }
});

The entire process could be simplified by utilizing a child scope instead of an isolated one. Alternatively, extending through a template could also work. However, copying the parent's "scope" and "template" definition to the child-directive and forwarding all non-default attributes might not be the most elegant solution.

Hence, the crucial question remains, is there a way to override a function from the parent-directive using an isolated scope without having to forward attributes.

Take a look at the DEMO for reference.

Answer №1

After conducting thorough research, I discovered that there are multiple approaches available.

Scope inheritance

In the case of the child-directive not creating its own scope but instead generating new methods within the parent-directive's parent scope, we have the ability to modify attributes during compilation and specify an overridden foo method.

app.directive('parentDirective', function() {
  return {
    scope: {
      fooImpl: '&?',
      // numerous attributes
    },
    controller: function($scope) {

      $scope.foo = function() {
        if ($scope.fooImpl) {
          return $scope.fooImpl();
        }
        return "not overrided";
      }

    },
    template: '<div class="some-styling"><main-directive foo="foo()"></main-directive></div>'
  }
});

app.directive('childDirective', function() {

  return {
    scope: false,
    require: 'parentDirective',
    controller: function($scope) {

      $scope.foo = function() {
        return "overrided";
      }

    },
    compile: function(element, attr) {
      attr.fooImpl = "foo()";
    }
  }
});

Check out the DEMO1

Add to isolated scope

Angular offers a special function that can access the isolated scope from an element. This allows us to override our method during the linking phase.

app.directive('parentDirective', function() {
  return {
    scope: {
      fooImpl: '&?',
      // numerous attributes
    },
    controller: function($scope) {

      $scope.foo = function() {
        if ($scope.fooImpl) {
          return $scope.fooImpl();
        }
        return "not overrided";
      }

    },
    template: '<div class="some-styling"><main-directive foo="foo()"></main-directive></div>'
  }
});

app.directive('childDirective', function() {

  return {
    scope: false,
    require: 'parentDirective',
    link: function(scope, element, attr) {
      var innerScope = angular.element(element[0]).isolateScope();
      innerScope.foo = function() {
        return "overrided";
      }
    }
  }
});

Check out the DEMO2

Controller method

If we utilize the controllerAs syntax, which exposes controller object variables as a scope, we can override a function in the child directive during the linking phase.

app.directive('parentDirective', function() {
  return {
    scope: {
      fooImpl: '&?',
      // numerous attributes
    },
    controller: function($scope) {

      var vm = this;

      vm.foo = function() {
        return "not overrided";
      }

    },
    controllerAs : 'vm',
    template: '<div class="some-styling"><main-directive foo="vm.foo()"></main-directive></div>'
  }
});

app.directive('childDirective', function() {

  return {
    scope: false,
    require: 'parentDirective',
    link: function (scope, element, attr, controller) {

       controller.foo = function() {
        return "overrided";
      }


    }
  }
});

Check out the DEMO3

Transclusion

In practice, achieving the same outcome with separate parent and child directives using transclusion could be considered. Nonetheless, this would essentially be a combination of the aforementioned approaches. Special thanks to "Extending an existing directive in AngularJS"

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

Watching for when the state changes in the AngularJS framework using the `$scope.$on('$stateChangeStart')` and

My AngularJs application has the functionality to detect a change in state (using ui.router) and prompt the user to save any unsaved changes. Currently, I am utilizing a confirm dialog for this task: $scope.$on('$stateChangeStart', () => { ...

Transform angularjs directive into angular 10

After stumbling upon this intriguing code snippet, I decided to integrate it into my angular project: 'use strict'; /** * A mesmerizing floating text animation */ angular.module('g1b.text-animation', []). directive('textAnimatio ...

ApEditingError: The method editAp is not defined in _this.props

I am facing an issue while trying to invoke the function editAp located in the func.js file from Edit1.js. I have provided the code snippets below for better understanding: import firebase from "firebase"; if (!firebase.apps.length) { firebase.initializ ...

Adding JSON content to a form for editing functionality within an Angular 8 CRUD application

I am currently working on building a Single Page Application using Angular 8 for the frontend and Laravel for the backend. I have been able to successfully pass data to the backend via JWT, and everything is functioning as expected. The application follows ...

JavaScript code to enforce a 100% page zoom setting

After developing a small game in Canvas, I encountered an issue. Some users with their default zoom level set to something other than 100% are unable to view the entire game page. I attempted to resolve this by using the following CSS: zoom: 100%; This ...

Explore various THREE.JS 3D models through a clickable link

I am struggling to make each object open a new page using a URL when clicked. No matter what I try, it doesn't seem to work properly. Can someone point out what I might be missing or doing wrong? Here is the click event code for the objects. If needed ...

Can jQuery be utilized to detect momentum scrolling on an iOS device once the touch event has ended?

Looking to implement a toggle menu at the bottom of the page that hides/shows during scrolling. I have already created a fixed menu that appears/disappears based on its position from the top. Currently, the event only triggers with touch input. Is there ...

Differences in characteristics of Javascript and Python

As I tackle an exam question involving the calculation of delta for put and call options using the Black and Scholes formula, I stumbled upon a helpful website . Upon inspecting their code, I discovered this specific function: getDelta: function(spot, str ...

Pause and let the asynchronous function complete without including a callback

Currently, I am in the process of writing tests for my Node.js/Express/Mongoose project utilizing Mocha and Should.js. Specifically, I am focusing on testing the functionality of my functions that interact with MongoDB. To ensure the integrity of these tes ...

What could be causing my Node.js (Express) application to have a response time of 21000 milliseconds for a simple GET request?

Here is the block of code I am working with: // GET - Default (root) app.get('/', (req, res) => { console.log('GET request to "/"..'); res.header('content-type', 'text/html'); return res.end('&ap ...

When hovering over an object in three.js, the cursor should change on mouseover

In my scene, I have added a sphere and plane geometry. Clicking on the plane geometry will open a linked website. Now, when hovering over the plane geometry, I want the mouse cursor to change to a hand pointer icon, and revert back to its original style ...

In Nodejs, the function 'require' fails to load a module when using specific filenames

Hello everyone, I am a long-time user but this is my first time asking a question. So, I have a file named file.js where I am trying to require another file called user.service.js at the beginning of the file: var userService = require('./user.servi ...

What is the best redux middleware for my needs?

As I followed the guide, I discovered a variety of middlewares available for Redux applications. Redux Thunk, Redux Promise, Redux Promise Middleware, Redux Observable, Redux Saga, Redux Pack Selecting a middleware is based on personal preference. Howeve ...

What could be the reason for Object.assign failing to update a key in my new object?

Function handleSave @bind private handleSave() { const { coin, balance } = this.state; console.log('coin', coin); console.log('balance', balance); const updatedCoin = Object.assign({ ...coin, position: balance }, coi ...

Is it possible for me to traverse a CSS stylesheet using code?

Exploring the depths of jQuery, one can effortlessly traverse the DOM. But what if we could also navigate through a stylesheet, accessing and modifying attributes for the specified styles? Sample Stylesheet div { background: #FF0000; display: blo ...

What is the process for changing CORS origins while the NodeJS server is active?

Currently, I am in the process of modifying the CORS origins while the NodeJS server is operational. My main goal is to replace the existing CORS configuration when a specific user action triggers an update. In my attempt to achieve this, I experimented w ...

Setting a checkbox to true within the MUI Data Grid using my input onChange event - how can I achieve this?

I am looking to highlight the selected row in my usage input onChange event. https://i.stack.imgur.com/rp9rW.png Details of Columns: const columns = [ { field: 'part_code', headerName: 'Part Code', width: 200 }, { ...

Using a javascript parameter in a cshtml file to filter data in a datatable

Here is the model code public class viewCase { public List<string> lstCategory { get; set; } public DataTable dtWrkTsk { get; set; } } This is the controller code string query = "SELECT WorkFlowID,Subject,Category FROM CMSTasksWorkFlow" ob ...

Identify all the CHECKBOX elements that are visible and not concealed

On my page, I have various checkboxes - some with hidden=true and others with hidden=false attributes. Despite trying to use a selector or jQuery to locate checkboxes with the hidden property, I am still facing some challenges. My goal is to differentiate ...

Is there a way to include a different component without it automatically displaying within a div element?

Is there a way to make the Torrent component render without directly binding it to a DOM element? I am facing an issue with my Torrent Table Component as I want it to be populated with Torrent Components based on API data, but it's not rendering beca ...