How to handle jQuery(window).scroll functions efficiently in jQuery? - javascript

This is my current code and feels like it's not very efficient and would perhaps be better if Timer/Timeout is used. However, I'm lost as to how to go about it.
Could someone help? Not very efficient with javascript. My JS guy is on leave.
app.directive('ScrollBar', function () {
return {
restrict: 'A',
scope: {},
link: function postLink(scope, elem, attrs) {
jQuery(window).scroll(function(){
var SBar = jQuery("#ScrollStop").offset();
var screenPosition = jQuery(document).scrollTop() + window.innerHeight;
if (screenPosition < SBar.top) {
jQuery(".ScrollClass").fadeIn();
}
if (screenPosition >= SBar.top) {
jQuery( ".ScrollClass" ).fadeOut();
}
});
}
};
})

It would be good if you differentiate the scroll direction by binding scroll function ,I have a fiddle,hope it helps.
http://jsfiddle.net/kavinhuh/17hca7wa/
myApp.directive('scrolly', function () {
return {
restrict: 'A',
link: function (scope, element, attrs) {
var lastScrollTop = 0;
var raw = element[0];
console.log('loading directive');
element.bind('scroll', function () {
console.log('in scroll');
if(raw.scrollTop < lastScrollTop)
{
alert("scroll up");
lastScrollTop = raw.scrollTop;
}
else{
lastScrollTop = raw.scrollTop;
}
if (raw.scrollTop + raw.offsetHeight > raw.scrollHeight) {
scope.$apply(attrs.scrolly);
}
});
}
};
});

Related

How to solve the infinite digset loop error for directive consists of multiple directive?

I am getting infinite digest looping error for the directive which consists of sub-directives.How to solve this error as I consists of multiple directives.
Here is my directive code:
app.directive('autoCompDrctve', function ($timeout) {
return {
scope: {
selectedIndex: '=',
suggestions: '=',
dropdownid: '#',
select: '&'
},
link: function (scope, element) {
scope.selectedIndex = 0;
var elem = angular.element(document.getElementById('autotext'));
var list =
angular.element(document.getElementById(scope.dropdownid));
list.css('display', 'none');
elem.bind('focus', function () {
scope.selectedIndex = 0;
scope.$apply();
list.css('display', 'block');
});
elem.bind('blur', function () {
$timeout(
function () {
list.css('display', 'none');
}, 100
)
});
elem.bind("keydown", function (event) {
if (list.css('display') === 'none') {
list.css('display', 'block');
}
if (event.keyCode === 40) { //down key, increment selectedIndex
event.preventDefault();
if (scope.selectedIndex + 1 === scope.suggestions.length) {
scope.selectedIndex = 0;
} else {
scope.selectedIndex++;
}
scope.$apply();
} else if (event.keyCode === 38) { //up key, decrement
selectedIndex
event.preventDefault();
if (scope.selectedIndex === 0) {
scope.selectedIndex = scope.suggestions.length - 1;
} else {
scope.selectedIndex--;
}
scope.$apply();
} else if (event.keyCode === 13 || event.keyCode === 9) {
//enter pressed or tab
elem.val(scope.suggestions[scope.selectedIndex].Name);
list.css('display', 'none');
scope.hmSelect(scope.suggestions[scope.selectedIndex]);
scope.$apply();
} else if (event.keyCode === 27) {
list.css('display', 'none');
}
})
}
};
}).directive('hoverClass', function () {
return {
restrict: 'A',
link: function (scope, element, attr) {
element.on('mouseenter', function () {
angular.element(document.getElementsByClassName(attr.hoverClass)).removeClass(attr.hoverClass);
element.addClass(attr.hoverClass);
});
element.on('mouseleave', function () {
element.removeClass(attr.hoverClass);
});
}
};
})
.directive('SelectDown', function () {
return {
restrict: 'A',
scope: {
hmSelectDown: '&'
},
link: function (scope, elem, attr) {
var list =
angular.element(document.getElementById(scope.hmDropdownid));
elem.bind('click', function () {
scope.hmSelectDown();
list.css('display', 'none');
});
}
};
})
.filter('highlight', function ($sce) {
return function (text, phrase) {
if (phrase)
text = text.replace(new RegExp('(' + phrase + ')', 'gi'), '<span
class="highlighted">$1</span>');
return $sce.trustAsHtml(text);
}
});
The error which is shown below in image:

Postion().top is not consistant due angular DOM still loading

Position top is not consistant every time ,
If user scrolls down when dom is still loading position will be different.
angular.module('users').directive('appplyProperty', ['$window', '$timeout',
function ($window, $timeout) {
var $win = angular.element($window);
return {
restrict: 'A',
link: function (scope, element, attrs) {
var = offsetTop = element.offset().top;
$win.on('scroll', function (e) {
var checkTheTop = $window.scrollY - offsetTop;
if (checkTheTop > 0) {
// apply css property top = checkTheTop ;
} else {
//do something
}
});
});
}
}]);
How to make sure position is calculated only after DOM is loaded or condition that now nothing is happening in the dom calculate position ?
Use ready method to ensure that your angular DOM is ready.
angular.element(document).ready(function () {
$win.on('scroll', function (e) {
var checkTheTop = $window.scrollY - offsetTop;
if (checkTheTop > 0) {
// apply css property top = checkTheTop ;
} else {
//do something
}
});
});

Access link of a directive in a service

is it possible to have access on link or data of a directive in a service?
my service:
myApp.service('myService', function () {
this.analyze = function (data) {
for (var i = 0; i < data.length; i++) {
if( data[i].x == ) //<--- here i want to compare data with data in directive
}
}
});
my directive:
myApp.directive('dateInfo', function ($interval) {
return {
restrict: 'A',
scope: {
},
//templateUrl: '123/Scripts/directives/html/dateInfo.html',
link: function (scope, element, attrs) {
element.html('<div class="panel panel-primary">' +
'<div class="panel-heading">test</div>' +
'<div class="panel-body"></div></div>');
$interval(function () {
var rect = element[0].getBoundingClientRect();
x = rect.left;
y = rect.top;
w = rect.right - rect.left;
h = rect.bottom - rect.top;
}, 3000);
}
};
});
I want access to "element"
How is it possible?
thix in advance

ionic want e.detail.scrollBottom

.directive('scrollWatch', function($rootScope) {
return function(scope, elem, attr) {
var start = 0;
var threshold = 150;
elem.bind('scroll', function(e) {
if(e.detail.scrollTop - start > threshold) {
$rootScope.slideHeader = true;
} else {
$rootScope.slideHeader = false;
}
console.log('e'+ e.detail.scrollTop);
if ($rootScope.slideHeaderPrevious >= e.detail.scrollTop - start) {
$rootScope.slideHeader = false;
}
console.log($rootScope.slideHeader);
$rootScope.slideHeaderPrevious = e.detail.scrollTop - start;
$rootScope.$apply();
});
};
})
This give me e.detail.scrollTop
But I want e.detail.scrollBottom. I cannot get about this.
help me
Simple! basic formula for scrollbottom is
$(document).height() - $(#element).scrollTop() - $(#element).height();
since i do not have your entire code i can not give exact solution. But with some trail you can get it. Just simply follow the formula.
that is
document height - current element position - current element window
height
and your code will be like this.
.directive('scrollWatch', function($rootScope) {
return function(scope, elem, attr) {
var start = 0;
var threshold = 150;
elem.bind('scroll', function(e) {
if(e.detail.scrollTop - start > threshold) {
$rootScope.slideHeader = true;
} else {
$rootScope.slideHeader = false;
}
console.log('e'+ e.detail.scrollTop);
if ($rootScope.slideHeaderPrevious >= e.detail.scrollTop - start) {
$rootScope.slideHeader = false;
}
console.log($rootScope.slideHeader);
$rootScope.slideHeaderPrevious = $(document).height()-e.detail.scrollTop - e.detail.height();
$rootScope.$apply();
});
};
})

AngularJS Directive Not Firing On-Change Callback

I've created a numeric stepper for use with CSS styles, but am having issues getting it to fire the ng-change when you type in it manually.
I created a log on the plunker to illustrate when the callback is being fired. As you can see from playing with it, it works fine when you click on the stepper arrows, but not when you type in the box directly.
Current Code Example: Plunker
HTML:
<div class="stepper-container">
<input type="text" ng-model="ngModel">
<button class="stepper-up fa fa-chevron-up" ng-click="increment()"></button>
<button class="stepper-down fa fa-chevron-down" ng-click="decrement()"></button>
</div>
JavaScript:
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.myModel = null;
$scope.log = [];
$scope.someMethod = function () {
$scope.log.push('Change event on ' + $scope.myModel);
}
});
app.directive('numericStepper', function () {
return {
restrict: 'EA',
require: 'ngModel',
scope: {
ngModel: '='
},
replace: true,
templateUrl: 'numeric-stepper.html',
link: function (scope, element, attrs, ngModelCtrl) {
console.log('NumericStepper::link', ngModelCtrl.$viewValue);
var sizingUnit = null;
var css3Lengths = [
// Percentage
'%',
// Font Relative
'em', 'ex', 'ch', 'rem',
// Viewport Relative
'vw', 'vh', 'vmin', 'vmax',
// Absolute
'cm', 'mm', 'in', 'px', 'pt', 'pc'
];
scope.$watch(function () {
return ngModelCtrl.$modelValue;
}, function (newValue, oldValue) {
updateValue();
});
ngModelCtrl.$formatters.unshift(function (value) {
value = isNaN(parseInt(value)) ? 0 : value;
return value;
});
scope.increment = function () {
updateValue(1)
};
scope.decrement = function () {
updateValue(-1);
};
function updateValue(amount) {
var matches = ngModelCtrl.$viewValue.toString().split(/(-?\d+)/);
var value = (parseInt(matches[1]) || 0) + (amount || 0);
sizingUnit = matches[2].trim();
ngModelCtrl.$setViewValue(value + sizingUnit);
sanityCheck();
}
function sanityCheck() {
var validity = css3Lengths.indexOf(sizingUnit) != -1;
ngModelCtrl.$setValidity('invalidUnits', validity);
}
}
}
});
Change your template text box to include an isolate scope call for ngChange. In that function, use timeout to allow the model update/digest to happen before calling parent controllers change function...
So change your template textbox:
<input type="text" ng-model="ngModel" ng-change="textChanged()">
Then change your directive:
// $timeout works better here than watch
app.directive('numericStepper', function ($timeout) {
return {
restrict: 'EA',
require: 'ngModel',
scope: {
ngModel: '=',
ngChange: '&' // add me!
},
replace: true,
templateUrl: 'numeric-stepper.html',
link: function (scope, element, attrs, ngModelCtrl) {
console.log('NumericStepper::link', ngModelCtrl.$viewValue);
var sizingUnit = null;
var css3Lengths = [
// Percentage
'%',
// Font Relative
'em', 'ex', 'ch', 'rem',
// Viewport Relative
'vw', 'vh', 'vmin', 'vmax',
// Absolute
'cm', 'mm', 'in', 'px', 'pt', 'pc'
];
/********** DONT NEED THIS
// scope.$watch(function () {
// return ngModelCtrl.$modelValue;
// }, function (newValue, oldValue) {
// updateValue();
// });
******************/
// Add this function
scope.textChanged = function() {
$timeout(function(){
updateValue();
scope.ngChange(); }, 500); // could be lower
}
ngModelCtrl.$formatters.unshift(function (value) {
value = isNaN(parseInt(value)) ? 0 : value;
return value;
});
scope.increment = function () {
updateValue(1)
};
scope.decrement = function () {
updateValue(-1);
};
function updateValue(amount) {
var matches = ngModelCtrl.$viewValue.toString().split(/(-?\d+)/);
var value = (parseInt(matches[1]) || 0) + (amount || 0);
sizingUnit = matches[2].trim();
ngModelCtrl.$setViewValue(value + sizingUnit);
sanityCheck();
}
function sanityCheck() {
var validity = css3Lengths.indexOf(sizingUnit) != -1;
ngModelCtrl.$setValidity('invalidUnits', validity);
}
}
}
});
And a working plunker
addon to what #doog abides already said
you can use $timeout interval as 0 and it will work the same then
scope.textChanged = function() {
$timeout(function(){
updateValue();
scope.ngChange(); }, 0); // could be Zero

Categories