I have javascript file that has onscroll event handler. When a webpage includes this javascript file, and when the page gets scrolled event handler gets called and it does the required work on scroll.
It is working fine and many web pages work successfully. But, today one webpage that uses AngularJS framework included my javascript file, window.onscroll handler is not getting called.
Could anyone suggest how to handle Angular pages without breaking existing ones? Thank you so much.
Javascript file structure is like this
(function() {
window.onscroll = function() {
/* on scroll work logic */
}
})(this);
What change can I suggest to page owner so that their angular app can somehow let window.onscroll method in my javascript file to execute during page scroll?
please note that I don't own angular app. I own simple javascript file with window.onscroll handler.
You can use $window replica of window object
app = angular.module('exampleApp', []);
app.directive("scroll", function ($window) {
return function(scope, element, attrs) {
angular.element($window).bind("scroll", function() {
//code
});
};
});
Related
I'm writing an AngularJS application, but I'm quite new to it, so in the code below, please point out any issues that you have.
I do have my AngularJS application defines like that:
var OfficeUIModule = angular.module('OfficeUI', ['ngSanitize']);
Then, I do have a couple of services that loads data from various JSon files.
But i won't post the code here, because I do believe that irrelevant.
Then I do have my controller which basically looks like this:
OfficeUIModule.controller('OfficeUIController', function($scope) { });
Now, I want the controller to execute some logic on startup and show a DIV element on it.
Here's the case what I want to do:
Show a Loading DIV element during initial setup.
Show a Displaying DIV element when the initialization has been done.
Let's say that in my controller I do have method to initialize the application:
OfficeUIModule.controller('OfficeUIController', function($scope) {
function Init() {
// I'll load all the data from the services here.
}
});
In order to call this method on startup, I just define it in my controller like so:
OfficeUIModule.controller('OfficeUIController', function($scope) {
Init();
function Init() {
// I'll load all the data from the services here.
}
});
And the HTML which I would like to use is the following:
<body>
<div id="loading">LOADING</div>
<div id="displaying">DISPLAYING</div>
</body>
When the page is initially loaded, I would like to show the element 'Loading'.
When the page has been loaded, I would like to show the element 'Displaying'.
In order to make this testable, I've changed my controller method Init to include a timeout of 5 seconds, just like below:
OfficeUIModule.controller('OfficeUIController', function($scope) {
Init();
function Init() {
setTimeout(function() {
alert('Page has been loaded. When you click OK the displaying DIV should be showed.');
}, 5000);
}
});
So, in this particular case, I would like to make sure that the page is being loaded, displaying the LOADING div and after 5 seconds, display the DISPLAYING div.
I would also like not to see any flickering, and therefore ng-cloak can be used I've read, but I can't manage to configure it correctly.
Here's what I've tried already:
LOADING
DISPLAYING
However, that setup doesn't work quite well.
I've included a Plunker so that you can test the solution you provide.
It happens because you are using setTimeout with anonymous function and angularjs isn't aware of model change
http://plnkr.co/edit/FJ2lnrmtG7P3HXZuxRkH?p=preview
if you use angularjs $timeout it works
$timeout(function() {
$scope.initialized = true;
}, 5000);
you could also use $scope.$digest() or $scope.$apply to make it work
You can use the angular version of window load event.
angular.element($window).bind('load', function(e) {
// code to execute
});
In an Angular (1.3) app, I am displaying list of records using ng-repeat. There is a directive with a template inside the ng-repeat. Within the template I'm using ShareThis controls which are activated after the DOM is loaded.
On initial load of the app, the ShareThis Javascript works correctly and activates the buttons. On route change it does not activate. I've found to references to activate the controls manually via stButtons.makeButtons() or stButtons.locateElements();, but I'm unsure where to call this function in the directive or page cycle. I've tried within:
the directive link function - using $timeout or scope.$watch
the template <script>stButtons.locateElements();</script> - activates before model binding
the controller after binding - activates before DOM rendered
My understanding is the function to activate needs to be called after binding and after DOM rendering, but Angular does not know when the DOM is ready. There is a method to dynamically render the ShareThis controls using only Javascript, but I want the HTML defined in the template not Javascript for this case.
I've seen several questions out there related, but none of the answers seem to work 100% for my scenario (and many are broken as of Angular 1.3).
item-list.html (view)
<div ng-repeat="item in vm.itemList">
<item-directive item="item"></item-directive>
</div>
item-list.cs (controller)
{ ... vm.itemList = getItems(...) ... }
item-directive.js (directive)
(function () {
angular.module('app');
function itemDirective() {
var directive = { templateUrl: 'item.html', link: linkFunc, controller: ItemDirective };
return directive;
function linkFunc(scope, element, attr, ctrl) { var item = scope.item }
}
ItemDirective.$inject = ['$scope'];
function ItemDirective($scope) { ... }
}
item.html (directive template)
...
<div class="item-share-section">
<span class='st_sharethis_large' st_url="{{vm.item.url}}" st_title="{{vm.item.name}}"></span>
</div>
...
if I understood well, you want to call the function after the dom is completely render, right? Try this inside the postLink of your directive:
$scope.$watch('viewContentLoaded', stButtons.locateElements())
While my solution is a little hackish, I still prefer it over using $watch, since that is inefficient. Instead, I initialize the function which loads the buttons when the particular view you want to load the buttons with is rendered. The technique is as follows:
Here is the function which you should put in your controller:
$scope.loadShareThis = function() {
stButtons.makeButtons();
}
You'd then add to your item-list.html as such:
<div ng-repeat="item in vm.itemList" ng-init="loadShareThis()">
<item-directive item="item"></item-directive>
</div>
The dynamic URL's might give you additional problems, but that's another issue all together.
The typeahead display gets stuck to the body when using append to body in combination with routing.
typeahead-append-to-body="true"
I used the Angular seed project and one of the simple Typeahead examples and replicated the problem: http://plnkr.co/WSNIRKLqOCLqO87jp3an
Load page
Select 'view2'
Select 'view1'
Type alpha character 'a' into the input
Observe the typeahead display attached to the body
Select view2
Observe display is still attached to the body
Problem happens in all the browsers I tried.
I see the click bindings to the document fire but the dismissClickHandler is not called if the page is has been routed to before. Meaning it works fine the first time, but when you go back to a page that you have been to before it never firs the dismissClickHandler.
https://github.com/angular-ui/bootstrap/blob/master/src/typeahead/typeahead.js
// Keep reference to click handler to unbind it.
var dismissClickHandler = function (evt) {
if (element[0] !== evt.target) {
resetMatches();
scope.$digest();
}
};
$document.bind('click', dismissClickHandler);
originalScope.$on('$destroy', function(){
$document.unbind('click', dismissClickHandler);
});
var $popup = $compile(popUpEl)(scope);
if ( appendToBody ) {
$document.find('body').append($popup);
} else {
element.after($popup);
}
Any thoughts?
Please note that this is fixed using the latest versions of Angular (1.4.7) and Angular UI Bootstrap (0.14.3) - at the time of this writing. As such, I've closed https://github.com/angular-ui/bootstrap/issues/2551.
I believe this is a bug of the angular-bootstrap to not call $popup.remove() when its scope has been destroyed.
The reason it seems to work fine at the first time is because when you navigate to view 2, the template has't been ready in a cache yet, so it take sometime to load, and that allow the dismissClickHandler() to get executed and hide a popup.
But just hidding the popup is not enough. It should be removed from the DOM.
In your plunker, if you navigate back and forth between views a few times, then inspect the DOM, you will see a lot of dangling ui elements are still there but hidden in the document.body.
runTarm put me on the right track. This is my (quite dirty) fix, I remove the typeahead from the DOM on destroy of the scope:
originalScope.$on('$destroy', function(){
$document.find('[id^=typeahead]').remove();
$document.unbind('click', dismissClickHandler);
});
I submitted a bug: https://github.com/angular-ui/bootstrap/issues/2551
I'm using JQuery UI components in a view of AngularJS/JQuery application.
I need something like this (does not work) in my JavaScript code:
$(document).ready(function () {
var elem = $('div[ng-view]')[0];
var $scope = angular.element(elem).scope();
$scope.$on('$viewContentLoaded', function() {
// multiple JQuery statements
// to support JQuery-UI componenets
});
});
This code is included as <script> into index.html that has <div class="container" ng-view> element.
My thinking was that we need a two-step process:
First JQuery reacts on document-ready HTML event and attaches a listener to Angular's $viewContenLoaded using $scope retrieved using [ng-view] element.
Then each time a view is loaded my JQuery code will be executed and JQuery UI components get activated and wired.
Apparently my logic is flawed somewhere. Please point me in the right direction.
ADDITIONAL INFO (posted 03/31/14):
The rest of my code (controllers, service, routing) is written in TypeScript.
That element needs to be compiled in order to bind angulars scope to that element. You could try something like:
var scope = angular.injector(['ng']).get('$rootScope').$new();
var compile = angular.injector(['ng']).get('$compile');
compile(elem)(scope);
scope.$on('$viewContentLoaded', function(){
// Your code
});
Though I would suggest putting your code in a directive. The code I shown above is nothing more than a hack and dangerous since now you have global access to your services.
I'm trying to intercept clicks on this link:
<a id="test-button" href="#">Test</a>
with this js:
(function() {
$('#test-button').click(function (event) {
console.log("This code never gets called.")
event.preventDefault();
$('#alert-placeholder').html(['<div class="alert"><a class="close"',
'data-dismiss="alert">×</a>',
'<span>"+message+"</span></div>'].join())
return false;
})
console.log("yes, this code loads");
debugger;
})();
but the URL '#' loads and the code in the click() function doesn't run. What am I missing?
I'm using this code in a flask app using bootstrap.
Seems like you're trying to attach an event handler to the element that doesn't exist yet
(function() {
})();
only creates a local scope but doesn't guarantee DOM to load. To confirm it - add console.log($('#test-button').length); to your code.
What you need is to wrap your code with
$(function() {
// your code is here
});
instead