15

Can't access controller scope from angular component output binding function

I'm trying to access my home controller scope from dashboard component but it's undefined.

I also tried a second approach but then my function variable is undefined.

I'm using Angular 1.5 with Typescript

FIRST APPROACH:

Home controller HTML:

<div class="home-container">
    <dashboard-component on-tile-type-changed="HomeCtrl.onTileTypeChanged">
    </dashboard-component>
</div>

Home controller js:

namespace app.dashboard {
    'use strict';

    class HomeController {
        static $inject:Array<string> = ['$window'];

        constructor(private $window:ng.IWindowService) {

        }

        private onTileTypeChanged(tile:ITile) {
            console.log(tile); // DEFINED AND WORKING
            console.log(this); // NOT DEFINED
        }
    }

    angular
        .module('app.dashboard')
        .controller('HomeController', HomeController);
}

Dashboard controller js:

angular.module('app.dashboard')
    .component('dashboardComponent', {
        templateUrl: 'app/dashboard/directives/dashboard-container.html',
        controller: DashboardComponent,
        controllerAs: 'DashboardCtrl',
        bindings: {
            onTileTypeChanged: "&"
        }
    });

this.onTileTypeChanged()(tile);

SECOND APPROACH:

Home controller HTML:

<div class="home-container">
    <dashboard-component on-tile-type-changed="HomeCtrl.onTileTypeChanged()">
    </dashboard-component>
</div>

Dashboard controller js:

this.onTileTypeChanged(tile);

And here I'm getting the opposite:

private onTileTypeChanged(tile:ITile) {
    console.log(tile); // NOT DEFINED
    console.log(this); // DEFINED AND WORKING
}
5
  • What are the bindings for the dashboard-component? Commented Feb 21, 2016 at 15:26
  • Tried using controllerAs syntax? Commented Feb 21, 2016 at 15:29
  • @georgeawg added, The function in the controller is fired but I can't make both the controller scope and the input variable to be accessible. Commented Feb 21, 2016 at 15:31
  • I meant for homecontroller, how do you bind homecontroller to the view? Are u using router? Commented Feb 21, 2016 at 15:36
  • @Yerken Yes I'm using router with controllerAs syntax Commented Feb 21, 2016 at 15:40

1 Answer 1

15

tl;dr; see Demo below

You are using expression binding.

angular.module('app.dashboard')
    .component('dashboardComponent', {
        templateUrl: 'app/dashboard/directives/dashboard-container.html',
        controller: DashboardComponent,
        controllerAs: 'DashboardCtrl',
        bindings: {
            onTileChange: "&"
        }
    })t

To communicate event data from a component to a parent controller:

Instantiate the dashboard-component with:

<dashboard-component on-tile-change="HomeCtrl.onTileChange($tile)">
</dashboard-component>

In the component controller invoke the function with locals:

this.onTileChange({$tile: tile});

The convention for injected locals is to name them with a $ prefix to differentiate them from variables on parent scope.

From the Docs:

  • & or &attr - provides a way to execute an expression in the context of the parent scope. If no attr name is specified then the attribute name is assumed to be the same as the local name. Given <my-component my-attr="count = count + value"> and the isolate scope definition scope: { localFn:'&myAttr' }, the isolate scope property localFn will point to a function wrapper for the count = count + value expression. Often it's desirable to pass data from the isolated scope via an expression to the parent scope. This can be done by passing a map of local variable names and values into the expression wrapper fn. For example, if the expression is increment($amount) then we can specify the amount value by calling the localFn as localFn({$amount: 22}).

-- AngularJS Comprehensive Directive API Reference


DEMO of using expression ("&") binding to pass data

angular.module("app",[])
.directive("customDirective",function() {
    return {
        scope: {
            onSave: '&',
        },
        template: `
            <fieldset>
                <input ng-model="message"><br>
                <button ng-click="onSave({$event: message})">Save</button>
            </fieldset>
        `,
    };
})
<script src="//unpkg.com/angular/angular.js"></script>
<body ng-app="app">
    <custom-directive on-save="message=$event">
    </custom-directive>
    <br>
    message={{message}}
</body>

Sign up to request clarification or add additional context in comments.

2 Comments

is this only available for angular 1.5.9?
Expression binding is part of AngularJS 1.2. In directives it is done with the scope property of the Directive Definition Object.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.