PANDA Stack
PANDA Stack

Reputation: 1363

AngularJS: Accessing an element directive's attributes from within a controller

Problem: The attribute I pass to my directive's controller is not evaluated. For example, I get {{ attribute.value }} instead of 5.

Desired Outcome: My directive's controller has access to a primary key contained in an object from a parent controller. I need it to make API calls like MyResource.save({id: attribute});.

Code Snippets:

Calling directive from HTML

<div ng-controller="BoatDetailController as boatCtrl">
  <div class="row">
    <booking-widget boat-id="{{ boatCtrl.boat.id }}"></booking-widget>
  </div>

Directive

(function () {
    'use strict';

    angular.
        module('trips').
        directive('bookingWidget', bookingWidget);

    bookingWidget.$inject = [];

    function bookingWidget() {
        return {
            restrict: 'E',
            scope: {
                boatId: '@'
            },
            templateUrl: "/static/app/trips/trips.bookingwidget.template.html",
            controller: 'BookingWidgetController as bookingCtrl'
        }
    }
})();

Controller

(function () {
    'use strict';

    angular.
        module('trips').
        controller('BookingWidgetController', BookingWidgetController);

    BookingWidgetController.$inject = ['Trip', 'Booking', 'Messages', '$scope', '$attrs'];

    function BookingWidgetController(Trip, Booking, Messages, $scope, $attrs) {
        var vm = this;

        vm.boatId = $attrs.boatId;
        ...

        activate();

        //////////////////////////////

        function activate() {
            console.log(vm.boatId);
            //
        }

Console Results:

With $scope.boatId: (logs a blank line)

With $attrs.boatId: {{ boatCtrl.boat.id }} (a string)

Recap: The boat-id attribute of my directive is not resolving. Can you help me figure out how to fix it?

Upvotes: 0

Views: 713

Answers (2)

Shivangi
Shivangi

Reputation: 3062

You can actually create a custom directive like this:

function bookingWidget() {
        return {
            restrict: 'E',
            scope: {
                boatId: '@'
            },
            templateUrl: "/static/app/trips/trips.bookingwidget.template.html",
            controller: 'BookingWidgetController as bookingCtrl',
            link : function(scope, element, attrs, controller){
               console.log(attrs.boatId);
               scope.boatId = attrs.boatId;
            }
        }
    }

The link function actually allows you to have an access to the element, the scope of the directive, the attributes associated to the directive and the controller of the directive. The function is called after everything associated to the directive has been performed. In other words, this is the last stage.

The same scope would be shareable between the link function and controller.

Now, to make the API call, you may actually add a function in your controller that accepts the boatID, makes a call to the API and accepts the response onto the controller object. After that, add a watcher within the link function that watches over "vm.boatId", within which you may call that function which makes the API call. So, even if the controller has initialized before the link function, you would still be able to perform what you wish to. So, it would be a "link-based activation".

You may give this solution a try. Hope it helps.

Upvotes: 1

Partha Sarathi Ghosh
Partha Sarathi Ghosh

Reputation: 11576

You can pass a function and call it. Need to use & then.

https://thinkster.io/egghead/isolate-scope-am

Upvotes: 0

Related Questions