Using ES6 Classes as Angular 1.x directives

后端 未结 10 813
南旧
南旧 2020-12-04 07:57

I\'m doing a small project to play around the goody bag the ES6 is bringing, I\'m trying to set register a class as an angular directive, but I\'m running into this error \"

相关标签:
10条回答
  • 2020-12-04 08:24

    @Michael is right on the money:

    the module.directive() method expects a factory function

    However I solved it using another technique, a little cleaner I suppose, It works fine for me, it's not perfect though... I defined a static method that returns a the factory expected by module()

    class VineDirective {
        constructor($q) {
            this.restrict = 'AE';
            this.$q = $q;
        }
    
        link(scope, element, attributes) {
            console.log("directive link");
        }
    
        static directiveFactory($q){
            VineDirective.instance = new VineDirective($q);
            return VineDirective.instance;
        }
    }
    
    VineDirective.directiveFactory.$inject = ['$q'];
    
    export { VineDirective }
    

    And in my app I do:

    angular.module('vineyard',[]).directive('vineScroller', VineDirective.directiveFactory)
    

    I believe there's no other way to use classes + directives that going through hacks like this at this point, just pick the easy one ;-)

    0 讨论(0)
  • 2020-12-04 08:24

    My solution:

    class myDirective {
       constructor( $timeout, $http ) {
           this.restrict = 'E';
           this.scope = {};
    
           this.$timeout = $timeout;
           this.$http = $http;
       }
       link() {
           console.log('link myDirective');
       }
       static create() {
           return new myDirective(...arguments);
       }
    }
    
    myDirective.create.$inject = ['$timeout', '$http'];
    
    export { myDirective }
    

    and in the main app file

    app.directive('myDirective', myDirective.create)
    
    0 讨论(0)
  • 2020-12-04 08:24

    I had a similar problem. But in my case it worked and failed when I deployed to production. And it failed because production has the latest version of 6to5. This could be prevented by using npm shrinkwrap. According to the latest ES6 spec you can't use a class like this. https://github.com/babel/babel/issues/700

    0 讨论(0)
  • 2020-12-04 08:26

    As mentioned in a comment, the module.directive() method expects a factory function rather than a constructor.

    The most simple way would be to wrap your class in a function that returns an instance:

    angular.module('app')
        .directive('dateBlock', () => new DateBlock());
    

    However, this will only work in the most limited sense - it does not allow for dependency injection and the compile and link functions of your directive (if defined) will not work as expected.

    In fact, this is a problem I have looked into quite extensively and it turned out to be fairly tricky to solve (for me at least).

    I wrote an extensive article covering my solution, but as far as you are concerned I can point you to the discussion of the two main issues that need to be resolved:

    1. Dynamically converting a class definition into an angular-compatible factory function

    2. Allowing a directive's link and compile functions to be defined as class methods

    The full solution involves too much code to paste here, I think, but I have put together a working demo project which allows you to define a directive as an ES6 class like this:

    class MyDirective {
        /*@ngInject*/
        constructor($interval) {
            this.template = '<div>I\'m a directive!</div>';
            this.restrict = 'E';
            this.scope = {}
            // etc. for the usual config options
    
            // allows us to use the injected dependencies
            // elsewhere in the directive (e.g. compile or link function)
            this.$interval = $interval;
        }
    
        // optional compile function
        compile(tElement) {
            tElement.css('position', 'absolute');
        }
    
        // optional link function
        link(scope, element) {
            this.$interval(() => this.move(element), 1000);
        }
    
        move(element) {
            element.css('left', (Math.random() * 500) + 'px');
            element.css('top', (Math.random() * 500) + 'px');
        }
    }
    
    // `register` is a helper method that hides all the complex magic that is needed to make this work.
    register('app').directive('myDirective', MyDirective);
    

    Check out the demo repo here and here is the code behind register.directive()

    0 讨论(0)
提交回复
热议问题