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

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
}
});
});

Related

Document Click Event Stopped on Filter

I have an Event that is called when the document loads to make it able to click each element with the Class 'header' to expand and show more details:
$(document).ready(function () {
InitClick();
});
Here is the function:
function InitClick() {
$('.header').click(function () {
$(this).nextUntil('tr.header').slideToggle();
});
}
Now the issue is when the results get filtered, it will then cause that click event to stop until I re-initialise it, then it will start working again... Until the Data is filtered again or has to update.
Now my main question is, has anyone got a link to something that could assist me, I've tried putting is on a $watch but the main issue I keep having is that this is called before the filtered data is returned, causing it to initialise before the data is there.
Here is MyApp.js if it helps?
var MyApp = angular.module('MyApp', []);
MyApp.controller('MyAppCtrl', function ($scope, $filter) {
$scope.Users = tJSONData;
$scope.currentPage = 0;
$scope.pageSize = 3;
$scope.Pages = [];
$scope.search = '';
$scope.Completed = '';
$scope.getData = function () {
return $filter('filter')($scope.Users, $scope.search || $scope.Completed);
}
$scope.numberOfPages = function () {
return Math.ceil($scope.getData().length / $scope.pageSize);
}
$scope.$watch('numberOfPages()', function (newVal, oldVal) {
var tPages = [];
for (i = 0; i < $scope.numberOfPages(); i++) {
tPages.push(i + 1);
}
if ($scope.currentPage >= $scope.numberOfPages()) {
$scope.currentPage = $scope.numberOfPages() - 1;
}
if ($scope.currentPage == -1) {
$scope.currentPage = 0;
}
return $scope.Pages = tPages;
})
$scope.updatePage = function () {
$scope.$apply(function () {
$scope.Users = tJSONData
})
}
$scope.limitPagination = function () {
if ($scope.currentPage == 0) {
return $scope.currentPage;
} else if ($scope.currentPage == 1) {
return $scope.currentPage - 1
} else {
return $scope.currentPage - 2;
}
}
});
MyApp.filter('startFrom', function () {
return function (input, start) {
start =+ start; //parse to int
return input.slice(start);
}
});
Any help is appreciated :)
In a nutshell, when you call $(selector).click (or any other event), it will only set up the event for the elements that were grabbed at the time of the call. If the elements are removed and replaced (as seems to be your case), the new elements won't automatically have it.
Instead of using $(selector).click(callback), use $(document).on('click', selector, callback)
In your case, it looks like this should do the trick:
$(document).on('click', '.header', function () {
$(this).nextUntil('tr.header').slideToggle();
});
The difference is that this way, the event is actually bound to the document itself, which never changes. You then filter so it'll only trigger when you click a .header, but it'll apply to all of them, even those added after this bit is called.

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

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);
}
});
}
};
});

how to Trigger the event in Angular when user change the windows height ?

I need to count the element's position each time the user change windows height.so I create a directive.
'use strict';
angular.module "myApp"
.directive 'uibPosition',['$position','$document','$timeout', ($position,$document,$timeout)->
return {
restrict: 'EAC',
link: (scope, element, attr) ->
//I want to Trigger this event when user change windows height
$timeout ->
if $document.height() - $position.position(element).top < 500
element[0].querySelector('.custom-popup-wrapper').style.top = 'auto'
element[0].querySelector('.custom-popup-wrapper').style.bottom = 40 + 'px'
else
element[0].querySelector('.custom-popup-wrapper').style.top = $position.position(element).top+40+'px'
}
]
how to do it?I really appreciate it
You can add the watcher to the directive:
var w = angular.element($window);
scope.getWindowDimensions = function () {
return {
"h": w.height(),
"w": w.width()
};
};
var watcherTimeout;
scope.$watch(scope.getWindowDimensions, function (newValue) {
$timeout.cancel(watcherTimeout);
watcherTimeout = $timeout(function(){
scope.callback(); // call callback function
}, 300);
}, true);
w.bind("resize", function () {
scope.$apply();
});

Angularjs Directive to slide show and hide content

I have used Slide up/down effect with ng-show and ng-animate as a base for my issue. However, the directive only allow for one element to be hidden/displayed. When there are 2, only the first shows:
Here's a plunker: http://plnkr.co/edit/YtPgcUcnapiQfAR5hxiE?p=preview
If you click on Link 2, it'll show the first content.
angular.module('app', [])
.directive('sliderToggle', function() {
return {
restrict: 'AE',
link: function(scope, element, attrs) {
var target = element.parent()[0].querySelector('[slider]');
attrs.expanded = false;
element.bind('click', function() {
var content = target.querySelector('.slideable_content');
if(!attrs.expanded) {
content.style.border = '1px solid rgba(0,0,0,0)';
var y = content.clientHeight;
content.style.border = 0;
target.style.height = y + 'px';
} else {
target.style.height = '0px';
}
attrs.expanded = !attrs.expanded;
});
}
}
})
.directive('slider', function () {
return {
restrict:'A',
compile: function (element, attr) {
// wrap tag
var contents = element.html();
element.html('<div class="slideable_content" style="margin:0 !important; padding:0 !important" >' + contents + '</div>');
return function postLink(scope, element, attrs) {
// default properties
attrs.duration = (!attrs.duration) ? '1s' : attrs.duration;
attrs.easing = (!attrs.easing) ? 'ease-in-out' : attrs.easing;
element.css({
'overflow': 'hidden',
'height': '0px',
'transitionProperty': 'height',
'transitionDuration': attrs.duration,
'transitionTimingFunction': attrs.easing
});
};
}
};
});
The flaw occurs here:var target = element.parent()[0].querySelector('[slider]');. This statement element.parent()[0] will return the parent of the current element which will always be <article>.
Further more: I assume the element.parent()[0].querySelector('[slider]') will select the first child of article according to the doc for 'querySelector':
Returns the first element within the document (using depth-first
pre-order traversal of the document's nodes) that matches the
specified group of selectors
You should use var target = element.next()[0]; if you want to select a slider exactly after your button.
Or var target = element.next('[slider]')[0]; if it is not directly after;
Here is a plunker
Hope this helps!
A quick fix:
http://plnkr.co/edit/uvjNUxzROqBob7ZgCgxh?p=preview
Changing
var target = element.parent()[0].querySelector('[slider]');
with
var target = element.next('[slider]')[0];

ng-click firing when selecting text or dragging

When using ng-click on a div:
<div ng-click="doSomething()">bla bla</div>
ng-click fires even if the user only selects or drags the div. How do I prevent that, while still enabling text selection?
In requiring something similar, where the usual text selection behavior is required on an element which should otherwise respond to ngClick, I wrote the following directive, which may be of use:
.directive('selectableText', function($window, $timeout) {
var i = 0;
return {
restrict: 'A',
priority: 1,
compile: function (tElem, tAttrs) {
var fn = '$$clickOnNoSelect' + i++,
_ngClick = tAttrs.ngClick;
tAttrs.ngClick = fn + '($event)';
return function(scope) {
var lastAnchorOffset, lastFocusOffset, timer;
scope[fn] = function(event) {
var selection = $window.getSelection(),
anchorOffset = selection.anchorOffset,
focusOffset = selection.focusOffset;
if(focusOffset - anchorOffset !== 0) {
if(!(lastAnchorOffset === anchorOffset && lastFocusOffset === focusOffset)) {
lastAnchorOffset = anchorOffset;
lastFocusOffset = focusOffset;
if(timer) {
$timeout.cancel(timer);
timer = null;
}
return;
}
}
lastAnchorOffset = null;
lastFocusOffset = null;
// delay invoking click so as to watch for user double-clicking
// to select words
timer = $timeout(function() {
scope.$eval(_ngClick, {$event: event});
timer = null;
}, 250);
};
};
}
};
});
Plunker: http://plnkr.co/edit/kkfXfiLvGXqNYs3N6fTz?p=preview
I had to deal with this, too, and came up with something much simpler. Basically you store the x-position on mousedown and then compare new x-position on mouseup:
ng-mousedown="setCurrentPos($event)"
ng-mouseup="doStuff($event)"
Function setCurrentPos():
var setCurrentPos = function($event) {
$scope.currentPos = $event.offsetX;
}
Function doStuff():
var doStuff = function ($event) {
if ($event.offsetX == $scope.currentPos) {
// Only do stuff here, when mouse was NOT dragged
} else {
// Do other stuff, which includes mouse dragging
}
}

Categories