Callback function located within directive attribute specified in separate attribute

Recently, I created a directive called mySave, and it looks like this:

app.directive('mySave', function($http) {
   return function(scope, element, attrs) {
      element.bind("click", function() {
          $http.post('/save', scope.data).success(returnedData) {
              // callback defined on my utils service here

              // user defined callback here, from my-save-callback perhaps?
          }
      });
   }
});

Here is how the element using this directive looks:

<button my-save my-save-callback="callbackFunctionInController()">save</button>

The current implementation of the callbackFunctionInController in the controller is pretty basic:

$scope.callbackFunctionInController = function() {
    alert("callback");
}

However, when I try to console.log() attrs.mySaveCallback within the my-save directive, it returns a string value of callbackFunctionInController(). After reading some information suggesting that I should use $parse on this, I attempted to do so by calling $parse(attrs.mySaveCallback). This resulted in receiving a different function than expected:

function (a,b){return m(a,b)} 

I'm unsure of what I'm doing wrong in this process. Is this approach possibly flawed from the beginning?

Answer №1

One effective approach is to utilize the isolated scope recommendation by ProLoser

app.directive('mySubmit', function($http) {
   return {
      scope: {
        action: '&mySubmitAction'
      }
      link: function(scope, element, attrs) {
        element.on("click", function() {
            $http.post('/submit', scope.$parent.data).success(returnedData) {
                // calling the callback function from my utility service

                scope.action(); // triggers an alert
            }
        });
      }
   }
});

To send parameters back to the controller, follow these steps

[11:28] <revolunet> you need to pass named variables 
[11:28] <revolunet> for instance, my-var="action(a, b)" 
[11:29] <revolunet> in the directive: scope.action({a:xxx, b:yyy})

Answer №2

There are numerous approaches to tackle the task at hand. The FIRST crucial point to understand is that the $http.post() function will be triggered as soon as the DOM element is rendered by the template engine, and that's it. Placing it within a repeat loop will result in the function being executed for each new item in the repeater, which may not align with your objectives. If it does, then there might be a flaw in the design logic because the presence of DOM elements alone should not drive backend calls.

To address your query directly; after reading through the somewhat inadequate documentation on $parse, you'll discover that it provides an evaluation expression. By invoking this function and passing the scope to evaluate, you will obtain the current state of that expression on the passed scope, effectively executing your function.

var expression = $parse(attrs.mySave);
results = expression($scope); // call when necessary
expression.assign($scope, 'newValue'); // primary use of $parse, assigning values

Admittedly, it may seem perplexing initially, but it's important to grasp that a $scope undergoes constant changes in asynchronous applications, emphasizing the timing of value determination rather than just the method. $parse proves valuable for referencing a model to which you can assign a value, not solely for reading from it.

It would also be beneficial to delve into creating an isolate scope or mastering how to $eval() an expression.

$scope.$eval(attrs.mySave);

Answer №3

Utilize .$eval to run a statement within the specified scope

app.directive('mySave', function($http) {
   return function(scope, element, attrs) {
      $http.post('/save', scope.data).success(returnedData) {
          // callback defined on my utils service here

          // user defined callback here, from my-save-callback perhaps?
          scope.$eval(attrs.mySaveCallback)
      }
   }
});

TD: Demo

If you wish to exchange data between a directive and a controller, you can utilize two-way binding

app.controller('AppController', function ($scope) {
   $scope.callbackFunctionInController = function() {
      console.log('do something')
   };

   $scope.$watch('somedata', function(data) {
      console.log('controller', data);
   }, true);
});

app.directive('mySave', function($http, $parse) {
   return {
     scope: {
       data: '=mySaveData',
       callback: '&mySaveCallback' //the callback
     },
     link: function(scope, element, attrs) {
       $http.get('data.json').success(function(data) {
         console.log('data', data);
         scope.data = data;
         scope.callback(); //calling callback, this may not be required
       });
     }
   };
});

Demo: Fiddle

Answer №4

context: {
    handler: '&mySaveHandler'
}

Explicitly defining the context can be a helpful solution, but it may limit access to other parts of the original context. In my case, I needed to access other parts of the context beyond what was defined. To achieve this, I followed a similar approach to ng-click's implementation.

Here is an example of how I used my directive in HTML:

<div my-custom-directive source="dataSrc" action="performAction(data)">

Within the directive (without explicitly setting the context):

var actionPerformed = $parse(attrs.action);
    context.$apply(function () {
    actionPerformed( {data : conditions}, context, { $event: event });
});

Using this method allows me to call the function in the controller and provide parameters for it.

In the controller:

$scope.performAction= function(data){
    console.log(data);
}

This will correctly display the conditions passed to it.

Answer №5

It was successful for me

Within the view script

<tag mycallbackattrib="scopemethod">

Inside the directive

$scope[attrs.mycallbackattrib](params....);

The function is executed correctly and parameters are passed, although it may not be the most efficient way to work with Angular.

Answer №6

It is recommended to utilize the ng-click attribute rather than developing a custom directive.

Answer №7

app.directive('mySave', function($http, $parse) {
   return {
     scope: {
       data: '=mySaveData',
       callback: '&' //this is the defined callback function
     },
     link: function(scope, element, attrs) {
       $http.get('data.json').success(function(data) {
         console.log('Retrieved data:', data);
         if (scope.callback()) scope.callback().apply(data);
       });
     }
   };
});

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

Disabling $routeprovider while implementing bootstrap

I am encountering an issue with my normal routeprovider code. In a specific section of my HTML, I have some Twitter Bootstrap expand/collapse sections which inadvertently trigger the routeprovider when clicked. Is there a way to prevent this from happening ...

Encountering issues with JSON.Parse in JavaScript leads to errors

I'm encountering issues with JSON parsing in my code and I can't figure out the cause of it. I have a function that calls two ajax functions, one at the start and another in the success function. Everything seems to be working fine until I try to ...

Transitioning from jQuery methodologies to AngularJS techniques

Currently, I am in the process of migrating a Jquery Ajax form to AngularJS and I've encountered a roadblock... The form I am working on contains multiple checkboxes grouped by categories. Some items are listed in more than one category, resulting in ...

Using the updated values from a range slider in JavaScript: A step-by-step guide

In the scenario where a slider has been created and the value is being changed using a mouse, the challenge is how to utilize these values as variables in the global scope. It is important that this variable updates to the new value when the slider is ad ...

Refresh the webpage content by making multiple Ajax requests that rely on the responses from the previous requests

I am facing a challenge where I need to dynamically update the content of a webpage with data fetched from external PHP scripts in a specific sequence. The webpage contains multiple divs where I intend to display data retrieved through a PHP script called ...

Find the total duration of all items within an array by utilizing the Moment.js library

Within an array of objects, each object contains a field named "duration" that represents a string. Here is an example of one such object: { id: 14070 project: {id: 87, name: "Test project for time tracking"} issue: {id: 10940} user: {id ...

Is there a way to create a div that resembles a box similar to the one shown in the

Hello, I am attempting to achieve a specific effect on my webpage. When the page loads, I would like a popup to appear at the center of the screen. To accomplish this, I have created a div element and initially set its display property to 'none'. ...

Leveraging $scope within ui-router resolve

Currently, I am utilizing ui-router resolve to fetch some data from a service. The challenge lies in needing to extract a value from the parent $scope before calling the service, as evidenced below. resolve: { contactService: 'contact ...

When using ng-checked in Angular, the DOM may not display the element.input.checked property even when the

I am having issues with using ng-checked to automatically check a checkbox when a modal loads under certain conditions. Despite the item being checked, the condition if (item.checked) returns false. Below is the directive I am working with. app.directive ...

The client.postMessage() function in a service worker is not being recognized by the onmessage handler within an AngularJS controller

Handling Service Worker Messages: let angularClient; self.addEventListener('message', function(event) { // store the client that sent the message in the angularClient variable angularClient = event.ports[0]; }); Service Worker Notificat ...

JavaScript Regex: Removing all characters that are not numbers

There have been several inquiries about this particular question, such as this one on Stack Overflow. Despite my efforts to replicate the solution and research regex, I can't seem to get it to work: $("#button").click(function () { new_number = $ ...

Place the `service` parameter into the `run` function

What are some examples of when to utilize the angular.run method? I have a service that is resource-intensive and takes a significant amount of time to initialize before it can be used in conjunction with my view. angular.module('myApp').service ...

Manipulating Images with jQuery: Adding and Removing Images Without Affecting Text

Below is the code I'm working with: <input type = checkbox id = "purple" name = "box" > Purple </input> <div id = birdcage></div> This is the JavaScript section: $("#purple").click(function(){ if ($("#purple").is(":chec ...

Chai can't verify the HTML component

During my testing of an Angular project, I initially used Jasmine to check if a specific attribute of an HTML element exists. The following code snippet worked successfully for me: expect(element(by.css("*[id='ref_button']")).getAttribute(&ap ...

What is the best method for displaying a table using a JSON array?

I have a JSON array that I want to display in a table using React boxes: [ { id: 1, color: "red", size: "small" }, { id: 2, color: "blue", size: "medium" }, { id: 3, color: "green", size: "large" }, { id: 4, color: "yellow" ...

Struggling with linking my Angular Controller with my View and experiencing difficulty establishing a connection

I'm encountering an issue while attempting to link a controller to my view. The error I keep receiving is as follows: Error: ng:areq Bad Argument Argument 'TestAppCtrl' isn't a function, received undefined Here's the content ...

Tips for incorporating a Survey Monkey website embed into an Angular application

I have a Survey Monkey account with multiple surveys. I am trying to embed a survey from this website into my Angular website, which already has Bootstrap and jQuery added. I attempted to directly add the script in an HTML component, but it did not work. ...

"Encountering a JavaScript issue while attempting to group items in a Kendo Grid

I'm encountering a problem with my Kendo grid that is populated with AJAX in an ASP.NET MVC view. When I attempt to group by the property FacturasCabecera.NFactura, I get a JavaScript error stating d.ArtFacturasCabecera is undefined, causing the Kendo ...

The curious behavior of JavaScript object fields in Chrome

Attempting to update the targetRow's field with a variable converted from a string to a number is resulting in strange output in Chrome's console: targetRow[fieldName] = Number(value); console.log(targetRow[fieldName]); // = ...

What is the best method for extracting the innerHTML value of html tags using a css selector or xpath?

I am currently struggling with retrieving the HTML inner text value using CSS selector or XPath. While I can achieve this using document.getElementById, I am unable to do so using selectors. I can only print the tag element but not the text from it. For e ...