Scroll Bottom Angularjs Directive - angularjs

I am working on chat app, and the problem seems to be that directive for scroll bottom, to the last item in ng-repeat is not working properly when there are images in messages.
So it just doesn't scroll all the way bottom.
I think the reason is that directive scrolls before the image is fully loaded.
// Scroll to bottom directive
.directive('schrollBottom', function ($timeout) {
return {
scope: {
schrollBottom: "="
},
link: function (scope, element) {
scope.$watchCollection('schrollBottom', function (newValue) {
if (newValue)
{
$timeout(function() {
$(element[0]).scrollTop($(element)[0].scrollHeight);
}, 0, false);
}
});
}
}
})

Check here to see how to wait for an image to load before doing something. You can add a class to all images and wait for all images with that class to load before scrolling.
I would keep what logic you have, and put it inside of an img.onload callback handler. Then any scrolling to the bottom will only occur once all images have loaded.

Related

AngularJS application loader

I am trying to create a loader, and after the partial has rendered, I want to fade away the loader and display my application.
I have created the loader like so:
app.directive(
"mAppLoading",
function ($animate) {
return ({
link: link,
restrict: "C"
});
function link(scope, element, attributes) {
// NOTE: Am using .eq(1) so that we don't animate the Style block.
$animate.enabled(true);
scope.$on('$viewContentLoading', function () {
if (!!element) {
$animate.leave(element.children().eq(1)).then(
// Remove the root directive element.
element.remove();
// Clear the closed-over variable references.
scope = element = attributes = null;
}
);
}
});
}
}
);
This code above will remove the loader and the page will show up, but at the wrong time. The page is still not loaded. Is there an event that I can use when the partial is done rendering inside <div ui-view></div>?
It is the $viewContentLoaded event which you should use to determine if the content is loaded successfully.
scope.$on('$viewContentLoaded', function () {
...
Here is a tutorial on this

offset ui-router autoScroll

I am using ui-router's autoScroll to scroll down to a div (ui-view) when page loads/route change. It currently does so. Is there any way to offset autoScroll? I need to leave 100px above the element visible for menu and am confused on how to acchomplish this.
app.directive('scrollTop', function($uiViewScroll) {
var linker = function (scope, element, attr, $elm) {
$uiViewScroll(element);
};
return {
restrict: 'A',
link: linker
}
});
HTML:
<ui-view [autoscroll="true"]/>
autoscroll directive allows you to set the scroll behavior of the browser window when a view is populated.
By default, $anchorScroll is overridden by ui-router's custom scroll service, $uiViewScroll. This custom service let's you scroll ui-view elements into view when they are populated during a state activation.
Try to decorate the default $uiViewScroll service, overriding the default behaviour.
app.config(function ($provide) {
$provide.decorator('$uiViewScroll', function ($delegate) {
return function (uiViewElement) {
// var top = uiViewElement.getBoundingClientRect().top;
// window.scrollTo(0, (top - 30));
// Or some other custom behaviour...
};
});
});
See http://corpus.hubwiz.com/2/angularjs/22290570.html

AngularJS watcher not binding/ watching

I'm trying to implement the "infinite-scroll" feature in a list using a directive, which should load progressively a new set of "orders" when the scroll of the html element reaches or exceeds 75% of the scrollable height and append it to the existing list.
Unfortunately, the watcher doesn't trigger when i scroll the list.
The directive is located in the right tag and the watcher triggers the listener function only the first time, when the element is rendered by the browser.
The strange thing is that if i change path and then i return to the path where the list is, the watcher start behaving correctly and trigger the listener function everytime i perform a scroll.
<ol orders-loader class="orders-list">...</ol>
angular:
(function () {
angular.
module('myApp')
.directive('ordersLoader', ['$window', '$timeout', 'ordersResource', ordersloaderDirective])
function ordersloaderDirective($window, $timeout, loading, ordersResource) {
return {
restrict: 'A',
link: function (scope, element, attrs) {
scope.orders = ordersResource; /*ordersResource use $resource to api calls
and then stocks the data in a array exposed in the scope*/
$timeout(function () {
scope.$watch(function () { return element[0].scrollTop }, function () {
if (*the scroll exceedes more or less 75% of the total scrollHeight*/) {
/*asking for more orders*/
}
});
}, 0);
}
}
}
I can't figure out where is the problem.
Solved
As yeouuu suggested, there was no digest cycle after the list scroll event, so i added:
element.bind('scroll', function () {
scope.$apply();
});
just before the $timeout function.
Whenever using plugins outside of angularJs that should trigger watcher you need to explicitly apply them. Otherwise Angular won't be aware of these changes/events.
In your case that means adding scope.$apply(); after the event.
Your edited solution:
element.bind('scroll', function () {
scope.$apply();
});
More information can be found here about the scope life cycle: https://docs.angularjs.org/guide/scope#scope-life-cycle

AngularJS: Google Map Not Appearing

I'm trying to use Angularjs-Google-Maps in comibination with ui-router. I'm getting a weird issue where the map is only partially appearing.
I've managed to resolve it by creating a directive that triggers a 'resize' event to repaint the map:
function autoRefresh() {
return {
restrict: 'A',
link: function(scope, element, attrs) {
scope.$on('$stateChangeSuccess', function(){
google.maps.event.trigger(scope.map, 'resize');
console.log("this works!");
});
}
}
}
<map center="-34.397, 150.644" zoom="8" auto-refresh></map>
And this works great, once the initial page has loaded and I change the state, the map appears. But if I simply do a hard reload of the page in the browser, the map doesn't appear. I have to change the state before the map is visible.
Is there an alternative to '$stateChangeSuccess' that works on initial page load?
Any help is appreciated. Thanks in advance!

how to get event when user scroll to top in angular js?

could you please tell me how to get event when user scroll to top .Actually I am using ng-repeat in my example .I want to get event when user scroll to bottom and scroll to top .I have one div in which I used ng-repeat can we get event of top when user move to top after scrolling.Actually I need to show alert when user scroll to bottom and top of div in angular .here is my code
<body ng-controller="MyController">
<div style="width:90%;height:150px;border:1px solid red;overflow:auto">
<div ng-repeat="n in name">{{n.name}}</div>
</div>
You could put directives on your scrollable div that listen to the scroll event and check for the top or bottom being reached.
So, using your HTML, your div would look like this:
<div exec-on-scroll-to-top="ctrl.handleScrollToTop"
exec-on-scroll-to-bottom="ctrl.handleScrollToBottom"
style="width:90%;height:150px;border:1px solid red;overflow:auto">
<div ng-repeat="n in name">{{n.name}}</div>
</div>
With new directives exec-on-scroll-to-top and exec-on-scroll-to-bottom added. Each specifies a function in your controller that should execute when the particular event the directive is checking for occurs.
exec-on-scroll-to-top would look like this, just checking for the scrollable div's scrollTop property to be 0:
myapp.directive('execOnScrollToTop', function () {
return {
restrict: 'A',
link: function (scope, element, attrs) {
var fn = scope.$eval(attrs.execOnScrollToTop);
element.on('scroll', function (e) {
if (!e.target.scrollTop) {
console.log("scrolled to top...");
scope.$apply(fn);
}
});
}
};
});
And exec-on-scroll-to-bottom would look like this (keeping in mind that an element is fully scrolled when its (scrollHeight - scrollTop) === clientHeight):
myapp.directive('execOnScrollToBottom', function () {
return {
restrict: 'A',
link: function (scope, element, attrs) {
var fn = scope.$eval(attrs.execOnScrollToBottom),
clientHeight = element[0].clientHeight;
element.on('scroll', function (e) {
var el = e.target;
if ((el.scrollHeight - el.scrollTop) === clientHeight) { // fully scrolled
console.log("scrolled to bottom...");
scope.$apply(fn);
}
});
}
};
});
Here's a plunk. Open the console to see messages getting logged when the scrolling reaches the top or bottom.
This is a non angular way, but you can wrap it up in a directive which also allows reuse:
Use Javascript event listener:
div.addEventListener('scroll', function(){
if(this.scrollTop===0)
//do your stuff
});
Make sure to use $apply if you make any changes to the scope variables inside this listener.

Resources