angularJS scrolling not recognized in ng-view - angularjs

Does anyone know why this basic scroll directive doesn't work when I scroll in a template within ng-view? I know this is super vague but I can't find anything on the web. I have tried multiple variations of a scroll directive but none of them recognize scrolling within the template. I appreciate any help I can get. Thanks in advance!
I'm using this basic directive
directive("scroll", function ($window) {
return function(scope, element, attrs) {
angular.element($window).bind("scroll", function() {
if (this.pageYOffset >= 100) {
scope.boolChangeClass = true;
} else {
scope.boolChangeClass = false;
}
scope.$apply();
});
};
});
Here is the HTML
<ng-view><ng-view>
and a basic template for the view
<div scroll>
<blah></blah>
</div>
I should also not that I am using the ngRoute to supply views to ng-view.

I found the issue. Everything in my code was correct. The problem is that I had a piece of css that was hiding my overflow-x. Once I removed that the scroll event started firing.

in my case
<div ng-view></div>
I used to use directive example
<input type="password" class="form-control" scroll="user.password" required>
directive
app.directive("scroll", function () {
return {
};
});

Related

Change the view based on screen size

I am aware of a similar question being asked before:
Change the templateUrl of directive based on screen resolution AngularJS
This was first asked over a year ago and since then AngularJS got changed a bit. I am curious to find out if there are any other ways to achieve something similar as I haven't found many information about templateUrl swapping, so maybe I am barking up the wrong tree here.
I have a single page app without any routes.
html:
<body ng-app="App">
// lots of html same for both desktop/mobile
<my-dir></my-dir>
// even more here
</body>
template 1:
<p>Mobile</p>
template 2:
<p>Desktop</p>
I would like to render template 1 when the screen goes below 700px and template 2 otherwise. The templates change just what is inside my-dir directive. For example Template 1 renders list and template 2 renders table.
Another requirement would be to make it responsive if possible(aka templates would change as you resize the window)
At the moment I can use the solution from the above questions but are there any other ways to do it?
In your controller:
$scope.includeDesktopTemplate = false;
$scope.includeMobileTemplate = false;
var screenWidth = $window.innerWidth;
if (screenWidth < 700){
$scope.includeMobileTemplate = true;
}else{
$scope.includeDesktopTemplate = true;
}
html template:
<body ng-app="App">
<p ng-if="includeMobileTemplate">Mobile</p>
<p ng-if="includeDesktopTemplate">Desktop</p>
</body>
Hope it helps
You can add window resize and scroll event listener on my-dir directive:
angular.module("App").directive('myDir', ['$window', '$timeout', function($window, $timeout){
return {
restrict: 'EA',
scope: {},
template:'<div>
<p ng-if="showFirstTemplate">Mobile</p>
<p ng-if="showSecondTemplate">Desktop</p>
</div>',
link: function(scope, element, attr){
function checkTemplateVisible(event){
//use $timeout to make sure $apply called in a time manner
$timeout(function(){
//pageYoffset is equal to window scroll top position
if($window.pageYOffset > 700){
scope.showFirstTemplate = true;
scope.showSecondTemplate = false;
}else{
scope.showFirstTemplate = false;
scope.showSecondTemplate = true;
}
})
})
//scroll event make sure checkTemplateVisible called on browser scrolling
$window.on('scroll', checkTemplateVisible)
//resize event make sure checkTemplateVisible called on browser resizing
$window.on('resize', checkTemplateVisible)
}
}
}])

AngularJS scroll directive - How to prevent re-rendering whole scope

I have an AngularJS Application with a scroll directive implemented as the following:
http://jsfiddle.net/un6r4wts/
app = angular.module('myApp', []);
app.run(function ($rootScope) {
$rootScope.var1 = 'Var1';
$rootScope.var2 = function () { return Math.random(); };
});
app.directive("scroll", function ($window) {
return function(scope, element, attrs) {
angular.element($window).bind("scroll", function() {
if (this.pageYOffset >= 100) {
scope.scrolled = true;
} else {
scope.scrolled = false;
}
scope.$apply();
});
};
});
The HTML looks the following:
<div ng-app="myApp" scroll ng-class="{scrolled:scrolled}">
<header></header>
<section>
<div class="vars">
{{var1}}<br/><br/>
{{var2()}}
</div>
</section>
</div>
I only want the class scrolled to be added to the div once the page is scrolled more than 100px. Which is working just fine, but I only want that to happen! I don't want the whole scope to be re-rendered. So the function var2() should not be executed while scrolling. Unfortunately it is though.
Is there any way to have angular only execute the function which is bound to the window element without re-rendering the whole scope, or am I misunderstanding here something fundamentally to AngularJS?
See this fiddle:
http://jsfiddle.net/un6r4wts/
Edit:
This seems to be a topic about a similar problem:
Angularjs scope.$apply in directive's on scroll listener
If you want to calculate an expression only once, you can prefix it with '::', which does exactly that. See it in docs under One-time binding:
https://docs.angularjs.org/guide/expression
Note, this requires angular 1.3+.
The reason that the expressions are calculated is because when you change a property value on your scope, then dirty check starts and evaluates all the watches for dirty check. When the view uses {{ }} on some scope variable, it creates a binding (which comes along with a watch).

Angular strap tooltip visible by default

I using http://mgcrea.github.io/angular-strap/#/tooltips#tooltips
and i can't use Scope methods ($show(), $hide()). Help me please. How i can use this methods?
I have input in ng-repeat
<div ng-repeat="item in data.queue" >
<input type="text" maxlength="40" bs-tooltip data-animation="am-flip-x" data-title="{{item.file.tooltip_title}}">
<div>
And i need to set visible tooltips if item.file.flag=== true, and then hide tooltip of beyond the 5 second.
To get show() and hide() methods you gotta do everything on javascript side. Something like this:
markup
<div id="div1">some</div>
directive
app.directive('someThing', ['$tooltip', '$timeout', function($tooltip, $timeout){
return {
link: function($scope){
$scope.someFunction = function (item){
$timeout(function(){
var target = angular.element(document.getElementById('div1'));
var myTooltip = $tooltip(target, { title:'tip!!', trigger:'manual', placement:'top'});
myTooltip.$promise.then(function() { myTooltip.show(); });
$timeout(function(){
myTooltip.$promise.then(function() { myTooltip.hide(); });
}, 4000);
}, 1500);
};
}
};
}]);
The Angular way of solving your problem is using, for instance, data-bs-show="item.file.flag".
It will show your tooltip while item.file.flag == true.
The bsShow attribute expects a boolean value, so if you need to hide after 5 seconds, you might have another flag and set it to false after this time using $timeout.
It is possible to use $show()/$hide() but it's tricky and ugly so I'd avoid that if possible.

Angular directive is not working when used with two HTML elements?

I am new to AngularJS. I have created one directive using AngularJS which is working fine for me, but when i used this same directive with another HTML element then its not working.
basecampModule.directive("slideElement", function () {
function link($scope, element, attributes) {
var expression = attributes.slideElement;
if (!$scope.$eval(expression)) {
element.hide();
}
$scope.$watch(expression, function (newValue, oldValue) {
if (newValue === oldValue) {
return;
}
if (newValue) {
element.stop(true, true).slideDown("fast");
$('html, body').animate({
scrollTop: $(element).offset().top
}, 1000);
} else {
element.stop(true, true).slideUp("fast");
}
});
}
return ({
link: link,
restrict: "A"
});
});
HTML Part
<div class="row well" id="detailsBugs" slide-element="FilterBugsDetails.ShowPanel">
//FIRST ELEMENT
</div>
<div class="row well" id="detailsTasks" slide-element="FilterTaskDetails.ShowPanel">
//SECOND ELEMENT
</div>
its working with first element but not with second element.
Please let me know what is wrong is that part. ??
A very wilde guess : you should isolate the scope of you directive. Since both instances of this directive are using the same $scope they're probably conflicting :
http://www.egghead.io/video/fYgdU7u2--g
When I first looked at this I couldn't quite work out what was going on.
The watched would fire for once but not a second time for the second directive.
However, turns out the directive is actually watching two different properties (maybe this was obvious to others but I completely missed it). From the question it sounded like the poster wanted the directive to watch the same element.
Anyway it works fine in my plunker here
<button ng-click="FilterBugsDetails.ShowPanel = !FilterBugsDetails.ShowPanel;">Toggle Bugs</button>
<button ng-click="FilterTaskDetails.ShowPanel = !FilterTaskDetails.ShowPanel;">Toggle Tasks</button>
<button ng-click="FilterTaskDetails.ShowPanel = !FilterTaskDetails.ShowPanel; FilterBugsDetails.ShowPanel = !FilterBugsDetails.ShowPanel;">Toggle Tasks And Bugs</button>

AngularJS ng-keydown directive only working for <input> context?

I am pretty new to AngularJS but found it quite to my liking so far. For my current project I need hotkey functionality and was happy to see that it is supported since the 1.1.2 release.
The ng-keydown directive (http://code.angularjs.org/1.1.3/docs/api/ng.directive:ngKeydown) works as expected for input types but fails me for any other context like div etc. which seems odd given that the documentation says otherwise.
Here is an minimal example (http://jsfiddle.net/TdXWW/12/) of the working respectively the not working:
<input ng-keydown="keypress($event)">
<div ng-keydown="keypress($event)">
NOTE: I know this could be handled with plain jQuery (http://www.mkyong.com/jquery/how-to-check-if-an-enter-key-is-pressed-with-jquery/) but I much prefer to understand how to deal with it in AngularJS.
I was having the same problem and was able to fix it by following this simple tip provided in this comment: https://stackoverflow.com/a/1718035/80264
You need to give the div a tabindex so it can receive focus.
<div id="testdiv" tabindex="0"></div>
Thanks! To wrap this up I got this working by, injecting $document into my directive, then:
MyApp.directive('myDirective', function($document) {
return {
...
$document.keydown(function(e){
console.log(e)
})
}
This was the way I got it working in the end.
Add ng-app to the html element and ng-keyup and ng-keydown to the body element:
<html ng-app="myApp" ng-controller="MainCtrl">
.....
<body ng-keydown="keyPress($event);" ng-keyup="keyRelease($event);">
Then the funcitons in my controller deal with the event calling event.which to get the key code (in my implementation I set a var to the rootScope but you could also broadcast to other controllers)
$scope.keyPress = function(eve) {
if (eve.which === 16) { // shift
// $rootScope.$broadcast('doShift');
$rootScope.shiftOn = true;
};
};
The comment by charlietfl cleared things up and binding the event to $(document) worked as expected! Take away message: The AngularJS documentation is not really exhaustive, i.e. demands background knowledge.
angular.module('app').directive('executeOnEnter', function () {
return {
restrict: 'A',
link: function (scope, el, attrs, $rootScope) {
$('body').on('keypress', function (evt) {
if (evt.keyCode === 13) {
el.trigger('click', function () {
});
}
})
},
controller: function ($rootScope) {
function removeEvent() {
$("body").unbind("keypress");
}
$rootScope.$on('$stateChangeStart', removeEvent);
}
}
})
it worker fine for me, just add tabindex attribute. make sure that ng-keydown contains correct angularjs expression
<div ng-keydown="keypress($event)" tabindex="0">
$scope.keypress = function(ev) {
console.log('keyprez', ev);
}

Resources