4

I am using Angularjs for my frontend development. Recently I started implementing Webpack then I realized that angular.element($window).scrollTop() stopped working and started throwing error as "windowElement.width is not a function". Following are old code and new code with webpack.

Old working code:

app.directive("ajnav", ['$window', '$location', function ($window, $location) {
        return {
            restrict: "E",
            templateUrl: "/templates/common/AJNav.html",
            replace: true,
            scope: {
                seo: '=',
                conf: '='
            },
            link: function (scope, element, attrs) {
                //Bind event change the postion of AJ Nav on scroll
                var windowElement = angular.element($window);
                var onScrollHandler = function () {                    
                    //Get current height of iNav.
                    var iNavHeight = $("#iNavNGI_Header").height();
                    if (windowElement.scrollTop() > iNavHeight) {
                        $(element).addClass('navbar-fixed-top');
                        $(element).removeClass('aj-nav-container-absolute');
                    }
                    else {
                        $(element).removeClass('navbar-fixed-top');
                        $(element).addClass('aj-nav-container-absolute');
                    }
                };
                //Bind event handler on scroll
                windowElement.on('scroll', scope.$apply.bind(scope, onScrollHandler));                
            }

        };
    }]);

New code with webpack is throwing error:

var $ = require("jquery");
var angular = require("angular");
var Utilities = require("./../../utilities/Utilities");
var AppUtilities = require("./../../utilities/AppUtilities"); 
module.exports = ['$window', '$location', function ($window, $location) {
        return {
            restrict: "E",
            templateUrl: "/templates/common/AJNav.html",
            replace: true,
            scope: {
                seo: '=',
                conf: '='
            },
            link: function (scope, element, attrs) {
                //Bind event change the postion of AJ Nav on scroll
                var windowElement = angular.element($window);
                var onScrollHandler = function () {
                    //Get current height of iNav.
                    var iNavHeight = $("#iNavNGI_Header").height();
                    if (windowElement.scrollTop() > iNavHeight) {
                        $(element).addClass('navbar-fixed-top');
                        $(element).removeClass('aj-nav-container-absolute');
                    }
                    else {
                        $(element).removeClass('navbar-fixed-top');
                        $(element).addClass('aj-nav-container-absolute');
                    }
                };
                //Bind event handler on scroll
                windowElement.on('scroll', scope.$apply.bind(scope, onScrollHandler));                
            }

        };
    }];

Follownig is stacktrace for the exception I am getting.

TypeError: windowElement.scrollTop is not a function
    at module.exports.link.onScrollHandler (site.min.js:42181)
    at Scope.$get.Scope.$eval (ite.min.js:25066)
    at Scope.$get.Scope.$apply (site.min.js:25165)
    at eventHandler (site.min.js:12594)

I am binding this directive in my entry poing App.js as below

app.directive("ajnav", require("./directives/common/AJNav"));

I tried all the option I could but not able to fix it. Please help.

joy
  • 3,669
  • 7
  • 38
  • 73

2 Answers2

7

scrollTop function is added by jquery, you must be loading jquery after angular. In that case you wont get $.fn functions added to the angular.element instance. You could as well do $.fn.scrollTop.call($window) in that case. or $($window).scrollTop() or load jquery before angular so that your current code works as is.

Side Note: You don't have to do $(element), element is already jq(lite/query) wrapped which has add/removeClass function available already.

PSL
  • 123,204
  • 21
  • 253
  • 243
  • what i found during debugging $window.$ is undefined, however in my old code $window.$ has full jqery object. I changed the order to require('jquery') however still facing same problem. How can i fix $window object? – joy Jun 04 '15 at 21:29
  • @joy what happens when you do `$($window).scrollTop()`, Do you get `$` at all (console log `$` after `var $ = require("jquery");`)? – PSL Jun 04 '15 at 21:30
  • When I changed code to use $($window).scrollTop() then it worked. But it would be better I don't have to change my code :-) – joy Jun 04 '15 at 21:31
  • @joy for that you need to load jquery script before loading angular itself. Also you don't need to do `$(element).addClass` instead `element.addClass` should just work – PSL Jun 04 '15 at 21:31
  • @joy Also [see this](http://stackoverflow.com/questions/19938419/angular-requirejs-loading-in-the-wrong-order) to fix your loading order. You are doing manual bootstrap right? – PSL Jun 04 '15 at 21:33
  • Thank you. Very helpful. – joy Jun 04 '15 at 21:36
  • & yes...i removed $(element) to "element" and its working :-) learning day by day!!! – joy Jun 04 '15 at 21:44
0

Angular is loading before JQuery.

It's also worth mentioning why you get that error instead of "scrollTop is undefined".

It's because scrollTop is also a property of Element.

https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollTop

Mark Lu
  • 1,348
  • 1
  • 15
  • 19