0

I'm writing an application in Angular 1.5 in TypeScript. I have a component that is supposed to change the template of the view when I resize the window. ( Because I have a mobile template and a desktop template )

This used to work fine when it was written in pure Javascript. Now that it is in Typescript I'm having problems defining functions since I'm new to TypeScript I don't see where the issue is coming from.

In Javascript the component was a directive and looked like this :

angular.module('app.directives').directive('adaptScreen', adaptScreen);

adaptScreen.$inject = ['$window', '$state'];

function adaptScreen($window, $state) {
    return {
        restrict: 'E',
        template: '<div ng-include="templateUrl"></div>',
        link: function (scope) {
            var rootUrl = 'public/app/views/';

            $window.onresize = function () {
                changeTemplate();
                scope.$apply();
            };
            changeTemplate();

            function changeTemplate() {
                var screenWidth = $window.innerWidth;
                if (screenWidth < 1050) {
                    scope.templateUrl = rootUrl + $state.current.name + '-mobile.html';
                } else if (screenWidth >= 1050) {
                    scope.templateUrl = rootUrl + $state.current.name+'-desktop.html';
                }
            }
        }
    }
};

And in my home.html view i had :

<adapt-screen></adapt-screen> 

and it used to work perfectly fine.

Now, in TypeScript the component looks like this :

const rootUrl = 'public/app/views/';
let templateUrl = '';

class AdaptViewComponentController implements IAdaptViewComponentController {

    static $inject = ['$window', '$state','$scope'];    


    constructor($window: Window, $state: ng.ui.IStateService, $scope: ng.IScope) {

        $window.onresize = function () {
            this.changeTemplate($window,$state,$scope);
            $scope.$apply;
        }    

        //console.log('in');
    };


    private changeTemplate($window: Window, $state: ng.ui.IStateService, $scope: ng.IScope):void {
        let screenWidth = $window.innerWidth;
        console.log('in');
        if (screenWidth < 1050) {
            templateUrl = rootUrl + $state.current.name + '/'+ $state.current.name + '-mobile.html';
        } else if (screenWidth >= 1050) {
            templateUrl = rootUrl + $state.current.name + '/' + $state.current.name  + '-desktop.html';
        }
        console.log('change' + templateUrl);
    };

}

class AdaptViewComponent implements ng.IComponentOptions {
    public bindings: any;
    public controller: any;
    public controllerAs: string;
    public templateUrl: string;

    constructor() {
        this.bindings = {};
        this.controller = AdaptViewComponentController;
        this.controllerAs = 'AdaptView';
        this.templateUrl = templateUrl;
        console.log(this.templateUrl);
    }
}

angular.module('rundeckManager.adapt')
    .component('adaptView', new AdaptViewComponent());

And because I changed the name of the component the home.html has this now :

<adapt-view></adapt-view>

As you see, there a lot of console.log because I wasn't understanding what was happening very well. But here I have a blank page rendered because the templateUrl is empty because the app can't call the function ' changeTemplate($window,$state,$scope)', I get the following error on screen resize :

Uncaught TypeError: this.changeTemplate is not a function
at AdaptViewComponentController.$window.onresize

The typescript compiler doesn't show any problems, though on execution my function is not recognized. I don't know why exactly, any help would be appreciated.

Daniel
  • 3,541
  • 3
  • 33
  • 46
Zakaria Sahmane
  • 210
  • 2
  • 16
  • you need to pass `this` from constructor to `onresize` callback – MysterX Aug 02 '17 at 09:36
  • Possible duplicate of [How does the "this" keyword work?](https://stackoverflow.com/questions/3127429/how-does-the-this-keyword-work) – Andreas Aug 02 '17 at 09:37

1 Answers1

0

bind the function to the class in the constructor.

constructor() {
    this.changeTemplate=this.changeTemplate.bind(this);
    $window.onresize = function () {
        this.changeTemplate($window,$state,$scope);
        $scope.$apply;
    }    
}
  • I'm thinking you should use an arrow function there. – Andrew Shepherd Aug 02 '17 at 09:42
  • You can use arrow function too. – Ajay Dharnappa Poojary Aug 02 '17 at 09:45
  • This didn't work at first, but when i combined it with an arrow function it worked just fine ! constructor($window: Window, $state: ng.ui.IStateService, $scope: ng.IScope) { this.changeTemplate = this.changeTemplate.bind(this); $window.onresize = () => { this.changeTemplate($window,$state,$scope); $scope.$apply; } }; thanks a lot ! – Zakaria Sahmane Aug 02 '17 at 09:50
  • @AjaySuvarna No, you cannot use the `function` keyword in this instance. If you use `function`, then `this` will be a pointer to the `$window` instance. If you use the arrow function then `this` will be a pointer to `AdaptViewComponent`. – Andrew Shepherd Aug 02 '17 at 10:35
  • I forgot to change that to arrow function. – Ajay Dharnappa Poojary Aug 02 '17 at 11:11