1

I am working on seeing if I can take a directive in 1.4 and trying to resemble a 1.5 component. I am using bindToController and controllerAs to use the controller in my directive instead of a separate controller. I have done this successfully with exporting as a function, but wanted to see if I could export as a class, and see if there is a good reason to do so. I am running into a bindToController error right now with the following code:

export default class recordingMenuComponent {
    constructor(RecordingCtrl) {
        'ngInject';
        this.restrict = 'E',
        this.scope = {},
        this.templateUrl = '/partials/media/recording/recording-menu.html',
        this.controller = RecordingCtrl,
        this.controllerAs = 'record',
        this.bindToController = {
            video: '='
      }
    }

    RecordingCtrl($log, $scope, $state, $timeout, RecordingService) {
      'ngInject';
      const record = this;
      Object.assign(record, {
        recentCalls: record.recentCalls,
        startRecording() {
            let video = {
                accountId: $scope.accountId,
                title: record.sipUrl
            };

            RecordingService
                .recordVideoConference(video, record.sipUrl, record.sipPin, 0)
                .then(result => {
                    video.id = result.id;
                    $timeout(() => $state.go('portal.video', {videoId: video.id}), 500);
                }, error => $log.error('Error starting the recording conference: ', error));
        },
        getRecentCalls() {
            RecordingService
                .recentVideoConferenceCalls()
                .then(result => {
                    record.recentCalls = result;
                }, error => $log.error('There was an error in retrieving recent calls: ', error));
        }
    });
}

  static recordingFactory() {
    recordingMenuComponent.instance = new recordingMenuComponent();
    return recordingMenuComponent.instance;
  }
}

and then importing:

import angular from 'angular'
import recordingMenuComponent from './recordingMenuComponent'

angular.module('recordingModule', [])
    .directive(recordingMenuComponent.name, recordingMenuComponent.recordingFactory);

There is some of the module that I have left out for brevity that did not have to do with trying to turn this directive into a component. Note that I am trying to not use the .controller() before the .directive().

When I try to use this, I get this error:

angular.js:9490 Error: [$compile:noctrl] Cannot bind to controller without directive 'recordingMenuComponent's controller

I am not sure I am going on the right track or this is not the right road to be going on.

Thank you for any help.

miquelarranz
  • 876
  • 11
  • 26
pertrai1
  • 4,146
  • 11
  • 46
  • 71

2 Answers2

1

You should implement RecordingCtrl as a class

const app = require('../app');

class RecordingCtrl {

    static $inject = ['$log', 'RecordingService'];
    constructor($log, recordingService) {
        this.$log = $log;
        this.recordingService = recordingService;
    }


    startRecording() {
        // . . .
    }

    recentCalls() {
        // . . . 
    }
}

// for ng15 component
const recordingMenu = {
     restrict: 'E',
     scope = {},
     templateUrl = '/partials/media/recording/recording-menu.html',
     controller = RecordingCtrl,
     controllerAs = 'record',
     bindToController = {
         video: '='
     }
}

app.component('recordingMenu', recordingMenu);

// or ng1.4 directive
function recordingMenu() {
    return {
        restrict: 'E',
        scope = {},
        templateUrl = '/partials/media/recording/recording-menu.html',
        controller = RecordingCtrl,
        controllerAs = 'record',
        bindToController = {
           video: '='
        }
     }
}

app.directive('recordingMenu', recordingMenu);

It does't make sense to implement a controller as a class method.

This means you will have two classes... unless you just want to make the Directive Definition Object factory a plain-old-function or a static method of your controller.

Martin
  • 15,820
  • 4
  • 47
  • 56
  • I want to make sure I understand that you recommend another class in the code but then you say it does not make sense. What do you think is the best approach? I tried to add the second class, but did not know how to implement into the `recordingMenuComponent this.controller`? – pertrai1 Jun 20 '16 at 16:40
  • Just do this.controller = RecordingCtrl – Martin Jun 20 '16 at 21:47
  • Just to clarify, it makes sense to use a class for the controller, as you can have multiple instances of the controller. For the DDO, it doesn't make as much sense to use a class. The DDO is an object by definition. There are not multiple instances. – Martin Jun 20 '16 at 22:59
  • I have updated my example with code for the angular 1.5 component. – Martin Jun 21 '16 at 09:09
  • 1
    Forgive me if I have this wrong, but the `static $inject` property declaration isn't valid ES6 (though it would be **really** nice if it was). The `$inject` property should be set as `RecordingCtrl.$inject = [...]` and placed after the class. Or am I missing something here? – Zac Seth Oct 10 '16 at 12:36
  • Zac -- you can add a static member the way you describe. You are correct, static methods are in the ES6 spec but static properties did not make it into the spec. This is supported by TypeScript and there is a plugin to add this support to Babel https://babeljs.io/docs/plugins/transform-class-properties/ – Martin Oct 10 '16 at 12:55
0

I was able to get this working even if it is not the best approach. It is for experimentation and the way that I was able to get it working:

.directive(recordingMenuComponent.name, () => new recordingMenuComponent())
pertrai1
  • 4,146
  • 11
  • 46
  • 71