I'm triying to add an nganimation for my main loader page with no luck :(. This is how I'm trying to achieve this. Im using a directive:
<html>
...
<loader-gui></loader-gui>
</html>
which has this code inside:
<div class="loader-gui" loader>
<img src="img/loader.gif"/>
</div>
with this directive:
angular.module('myapp.directives', [])
.directive('loaderGui', function() {
return {
restrict: 'E',
templateUrl: 'partials/loader-gui.html'
}
})
.directive('loader', ['$http', function ($http) {
return {
restrict: 'A',
link: function ($scope, element, attrs) {
$scope.isLoading = function () {
return $http.pendingRequests.length > 0;
};
$scope.$watch($scope.isLoading, function (value) {
if (value) {
element.removeClass('ng-hide');
} else {
element.addClass('ng-hide');
}
});
}
};
}]);
So, this is working perfect, after load all the resources and http requests my loader-gui dissapears. But I want to make it more fancy using nganimate to make a fadeout effect, simple.
I've added the library, the module into my app with out any errors and my custom CSS.
myapp.css
.ng-hide {
opacity:0;
-webkit-transition:all linear 0.5s;
transition:all linear 0.5s;
}
myapp.js
angular.module('myapp', ['ngAnimate', 'myapp.directives']);
But it's not working, it's just dissapear without any effect. Am I missing something? Any advice? I've read samples with methods fired up trough a $scope but not using a directive.
If you haven't included ngAnimate as a dependency in your main module, you certainly would want to do so here.
angular.module('myapp.directives', ['ngAnimate'])
Nowadays the best practice to make animation for ngHide and some other directives is by handling the "transition" classes which automatically added and removed during transition by the ngAnimate. For ngHide and ngShow the transition classes is named .ng-hide-add and .ng-hide-remove.
On the official angular documentation for ngHide they give good example to playing with those 2 classes. Please check this out for more detail example how to do that : https://docs.angularjs.org/api/ng/directive/ngHide#example . Please pay attention at the animate-hide which they add to the element that need to be animate. And also the CSS file which contain detail of class styling for the animation.
Related
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 {
};
});
I've included a Plunker here: http://plnkr.co/edit/4vqV8toHo0vNjtfICtzI?p=preview
I'm trying to add a button to the DOM and when clicked should execute the function bound to it. In this case it should alert "testing". Here is the code.
controller
app.controller('MainCtrl', function($scope, $sce) {
$scope.trustedHtml = $sce.trustAsHtml('<button ng-click="testAlert()">Submit</button>');
$scope.testAlert = function () {
alert('testing')
};
});
HTML
<body ng-controller="MainCtrl">
<div ng-bind-html="trustedHtml"></div>
</body>
$sce.trustAsHtml and ng-bind-html are not meant to build HTML with directives. This technique will not work.
This is because angular works by first compiling and then linking. See the conceptual overview for a good explaination.
In short, by the time you link the HTML defined in your trustAsHtml, it is too late for angular to compile (and therefore understand) the ng-click directive.
In order to dynamically add HTML, you should be looking at the $compile service (and/or directives). Docs are here.
For Angular 1.6.1, I found a solution that worked for me.
template:
<div ng-bind-html="trustAsHtml(content);" init-bind> </div>
In controller:
$scope.trustAsHtml = function(string) {
return $sce.trustAsHtml(string);
};
Directive:
.directive('initBind', function($compile) {
return {
restrict: 'A',
link : function (scope, element, attr) {
attr.$observe('ngBindHtml',function(){
if(attr.ngBindHtml){
$compile(element[0].children)(scope);
}
})
}
};
})
On page load the console log prints but the toggleClass/click won't work I even use angular.element but it has the same result.I need to change state in order for the toggleClass to work.I dunno what's wrong in my code.
.run(['$rootScope', function ($rootScope) {
console.log('test');//this prints test and it's ok
//this part won't load at the first loading of page.
$('.toggle-mobile').click(function(){
$('.menu-mobile').toggle();
$(this).toggleClass('toggle-click');
});
//....
}])
even doing it this way doesn't work.
$rootScope.$on('$viewContentLoaded', function () {
angular.element('.toggle-mobile').on('click', function (event) {
angular.element(this).toggleClass('toggle-click');
angular.element('.menu-mobile').toggle();
event.preventDefault();
});
});
The Angular way to render items is different from "On DOM Ready" that is why we need to treat these as 2 separate things.
Angular could render items later on even after DOM is ready, this could happen for example if there is an AJAX call($http.get) and that is why a directive may be the recommended approach.
Try something like this:
<body ng-controller="MainCtrl">
<div toggle-Me="" class="toggle-mobile"> Sample <div class="menu-mobile">Sample 2</div>
</div>
<script>
var myApp = angular.module('myApp', []);
myApp.controller('MainCtrl', ['$scope', function ($scope) {}]);
myApp.directive("toggleMe", function() {
return {
restrict: "A", //A - means attribute
link: function(scope, element, attrs, ngModelCtrl) {
$(element).click(function(){
$('.menu-mobile').toggle();
$(this).toggleClass('toggle-click');
});
}
};
});
...
By declaring the directive myApp.directive("toggleMe",... as an attribute toggle-Me="" every time angular generates the input element it will execute the link function in the directive.
Disclaimer: Since the post lacks from a sample html I made up something to give an idea how to implement the solution but of course the suggested html is not part of the solution.
I am having an issue in Angularjs where there is a flicker in my HTML before my data comes back from the server.
Here is a video demonstrating the issue: http://youtu.be/husTG3dMFOM - notice the #| and the gray area to the right.
I have tried ngCloak with no success (although ngCloak does prevent the brackets from appearing as promised) and am wondering the best way to hide content until the HTML has been populated by Angular.
I got it to work with this code in my controller:
var caseCtrl = function($scope, $http, $routeParams) {
$('#caseWrap').hide(); // hides when triggered using jQuery
var id = $routeParams.caseId;
$http({method: 'GET', url: '/v1/cases/' + id}).
success(function(data, status, headers, config) {
$scope.caseData = data;
$('#caseWrap').show(); // shows using jQuery after server returns data
}).
error(function(data, status, headers, config) {
console.log('getCase Error', arguments);
});
}
...but I have heard time and time again not to manipulate the DOM from a controller. My question is how can I achieve this using a directive? In other words, how can I hide the element that a directive is attached to until all content is loaded from the server?
In your CSS add:
[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
display: none !important;
}
and just add a "ng-cloak" attribute to your div like here:
<div id="template1" ng-cloak>{{scoped_var}}<div>
doc: https://docs.angularjs.org/api/ng/directive/ngCloak
On your caseWrap element, put ng-show="contentLoaded" and then where you currently have $('#caseWrap').show(); put $scope.contentLoaded = true;
If the caseWrap element is outside this controller, you can do the same kind of thing using either $rootScope or events.
Add the following to your CSS:
[ng\:cloak],[ng-cloak],.ng-cloak{display:none !important}
The compiling of your angular templates isn't happening fast enough.
UPDATE
You should not do DOM manipulation in your controller. There are two thing you can do...
1. You can intercept changes to the value within the scope of the controller via a directive! In your case, create a directive as an attribute that is assigned the property you want to watch. In your case, it would be caseData. If casedata is falsey, hide it. Otherwise, show it.
A simpler way is just use ngShow='casedata'.
Code
var myApp = angular.module('myApp', []);
myApp.controller("caseCtrl", function ($scope, $http, $routeParams, $timeout) {
$scope.caseData = null;
//mimic a delay in getting the data from $http
$timeout(function () {
$scope.caseData = 'hey!';
}, 1000);
})
.directive('showHide', function () {
return {
link: function (scope, element, attributes, controller) {
scope.$watch(attributes.showHide, function (v) {
if (v) {
element.show();
} else {
element.hide();
}
});
}
};
});
HTML
<div ng-controller='caseCtrl' show-hide='caseData'>using directive</div>
<div ng-controller='caseCtrl' ng-show='caseData'>using ngShow</div>
JSFIDDLE:http://jsfiddle.net/mac1175/zzwBS/
Since you asked for a directive, try this.
.directive('showOnLoad', function() {
return {
restrict: 'A',
link: function($scope,elem,attrs) {
elem.hide();
$scope.$on('show', function() {
elem.show();
});
}
}
});
Stick (show-on-load) in your element, and in your controller inject $rootScope, and use this broadcast event when the html has loaded.
$rootScope.$broadcast('show');
I have used Zack's response to create a 'loading' directive, which might be useful to some people.
Template:
<script id="ll-loading.html" type="text/ng-template">
<div layout='column' layout-align='center center'>
<md-progress-circular md-mode="indeterminate" value="" md-diameter="52"></md-progress-circular>
</div>
</script>
Directive:
directives.directive('loading', function() {
return {
restrict: 'E',
template: 'll-loading.html',
link: function($scope,elem,attrs) {
elem.show();
$scope.$on('loaded', function() {
console.log("loaded: ");
elem.hide();
});
}
}
});
This example uses angular-material in the html
The accepted answer didn't work for me. I had some elements that had ng-show directives and the elements would still show momentarily even with the ng-cloak. It appears that the ng-cloak was resolved before the ng-show returned false. Adding the ng-hide class to my elements fixed my issue.
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);
}