Animation on ngShow skips first time - angularjs

I am trying to animate a twitter bootstrap panel body opening/closing that is shown with ng-show in angular (version 1.3.2), by using a simple jQuery slideUp/slideDown.
(I tried at first with css transitions, but couldn't do it because of unknown body height, and max-height animation was giving me problems on closing, so I decided to go with JS)
I've succeeded in making the animation, but it does not work the first time
the animation is toggled.
So the first body showing is not animated, then the hiding is animated, and after that everything is fine (both show and hide animate).
Javascript part:
app.animation('.animate-panel-body-slide', function(){
return {
addClass : function(element, className, done) {
$(element).slideUp(400, done);
return function(isCancelled) {
if(isCancelled) {
$(element).stop();
}
}
},
removeClass : function(element, className, done) {
$(element).slideDown(400, done);
return function(isCancelled) {
if(isCancelled) {
$(element).stop();
}
}
}
}
});
HTML part:
<div class="panel panel-default">
<div class="panel-heading">
HEADING
</div>
<div class="panel-body animate-panel-body-slide" ng-show="isPanelOpen">
SOME HTML IN BODY...
</div>
</div>
Am I missing something?

When removeClass is executed it's because ng-hide (which sets display: none) was removed from the element.
The first time this happens the element will have display: block which means the element will appear immediately and the slideDown animation will not be apparent.
When the panel is closed the slideUp animation will add style="display: none;" to the element, which means the next time it's opened it will work as expected.
If you add it manually like this:
<div class="panel-body animate-panel-body-slide" ng-show="isPanelOpen" style="display: none">
It will work as long as the panel always begins as closed.
If you want it to work for both cases you can add this:
removeClass: function(element, className, done) {
element.css('display', 'none');
element.slideDown(400, done);
...

Related

How to show some HTML until screen is loaded in Angular / Ionic?

I am using Ionic and I can't find the solution for my problem. What I want to do, is to show some HTML before the screen is loaded. You can use the default $ionicLoading, but that just gives me an overlay, while I don't want that. I am a newbie to Angular and Ionic, so it might be a very simple question, but I just can't solve it.
To do so, I have added HTML to the screen I wanted it to be added. I made it like this:
<div class="preload-wrapper" ng-show="removeAfterLoad">
<p>Please wait, the page is being loaded </p>
</div>
And I know I need to use this, but I don't know how to bind it to the HTML I am using.
$ionicPlatform.ready(function removeAfterLoad () {
// I need to make sure that the HTML is only shown while the screen is being loaded.
// After it is loaded, I want to remove the HTML.
});
Is it something like $scope.hide I need to use. If so, how do I bind that to my HTML snippet?
I would recommend using ng-cloak
adding ng-cloak to a tag will hide it until the page is fulling loaded, and can be used in the inverse manner.
Step 1
Add this style between your <head> tag.
[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
display: none !important;
}
[ng-cloak].loading {
margin-top: 150px;
text-align: center;
display: block !important;
}
.loading {
display: none;
}
Step 2:
Add this to your index.html
<div class="loading" ng-cloak>
<i class="fa fa-spinner fa-pulse fa-3x fa-fw"></i>
<span class="sr-only">Loading...</span>
</div>
<div class="container" ng-cloak>
.....content goes here
</div>
After the page has fully loaded, ng-cloak will add "hidden" to the loading div and display the container div.
It's Actually Quiet Simple:
Inside Your Controller, you need to add $ionicLoading as below -
$ionicLoading.show({
template: '<ion-spinner></ion-spinner> <br/> Please wait, the page is being loaded'
});
And Hide after the function is successfully Callback:
$ionicLoading.hide();
You can actually override $ionicLoading template/overlay with your own html code. Here are the docs: http://ionicframework.com/docs/api/service/$ionicLoading/
You can even override the default template for any view.
In your example you could do:
angular.module('LoadingApp', ['ionic'])
.controller('LoadingCtrl', function($scope, $ionicLoading) {
$scope.show = function() {
$ionicLoading.show({
template: '<div class="preload-wrapper" ng-show="removeAfterLoad"> '+
'<p>Please wait, the page is being loaded </p> '+
'</div>',
duration: 3000,
//if you want to hide the background overlay
noBackdrop: true
}).then(function(){
console.log("The loading indicator is now displaying your html");
});
};
$scope.hide = function(){
$ionicLoading.hide().then(function(){
console.log("The loading indicator is now hidden");
});
};
});
An nice way to show and hide loading is using ionic view events: http://ionicframework.com/docs/api/directive/ionView/
$scope.$on("$ionicView.beforeLeave", function(event, data){
// show loading
});
$scope.$on("$ionicView.beforeEnter", function(event, data){
// hide loading
});

Angular JS UI Bootstrap tabs (ui.bootstrap.tabs) causes page to scroll/jump on select

Selecting tabs causes the page to scroll randomly for e.g selecting a tab can scroll the page almost all the way to the top then I would have to scroll down to see the content of the tab, if I select another tab the page scrolls again.
The tabs' content is of variable size some having more elements than others so they are naturally of different heights but I am not sure if this is the reason of the random page scrolling.
I tried some jquery to disable the link default actions with no luck.
$(function () {
$('body').on('click', 'a[ng-click="select()"]', function (event) {
event.preventDefault();
});
});
The other solution which is ugly is that I wrapped the tabset in a div and set a height on the div
<div class="col-md-12" id="profile-nav-tabs" style="
height:500px;
overflow-y: auto;
overflow-x:hidden
">
<tabset justified="true">
<tab heading="{{::strings.profile}}">
<br />
<div ng-include="'tab-profile.php'"></div>
</tab>
.... more tabs
</tabset>
</div>
I encountered the same problem. After tracing the code, I think this is a bug of tabset directive.
The solution is (step-by-step):
Modify tabset.html, delete [ng-class="{active: tab.active}"]
Modify [tab] directive's scope.$watch('active')'s handler.
Use angular.element's addClass and removeClass function to add/remove active class.
link: function(scope, elm, attrs, tabsetCtrl, transclude) {
scope.$watch('active', function(active) {
/*if (active) {
tabsetCtrl.select(scope);
}*/
var idx = tabsetCtrl.tabs.indexOf(scope);
var elmPane = angular.element(elm[0]).parent().next().children()[idx]; //li->ul->div(tab-content)->div(tab-pane)
if (active) {
tabsetCtrl.select(scope);
angular.element(elmPane).addClass('active');
}
else {
angular.element(elmPane).removeClass('active');
}
});

popup a div on mouseover in Angularjs

I'm new in AngularJS, how can i show popup a div on mouseover using AngularJS. If i resize a div on mouseover, it changes whole structure, how to show popup div without disturbing neighbors elements.
Markup
<div ng-repeat="x in images | filter:test" style="float:left; width:30%" ng-mouseover="count=1" ng-mouseleave="count=0" >
<img ng-src="{{x.path}}"
style="width: 100px; height:100px"><div> {{x.company}}</div>
<div style="background-color:#E6E6FA;text-align: center;"ng-show="count">
price:{{x.price}}</br>
size:{{x.size}}</br>
</div>
</img>
<div/>
I added extra things in markup like company,size on mouseover. help me in pop a image on mouseover. Thanks in advance
You have to do two things. First you have to position your popover element absolute, so that it doesn't disturb the flow of the other elements when it pops up. Something like this (z-index is what makes it to be over the other elements):
.popover {
position: absolute;
z-index: 100;
}
And in your html-markup you can use the ng-mouseover directive.
<div ng-mouseover="showPopover()" ng-mouseleave="hidePopover()">
more info
</div>
<div class="popover" ng-show="popoverIsVisible">Popover Content</div>
Your angular controller will probably look something like this
$scope.showPopover = function() {
$scope.popoverIsVisible = true;
};
$scope.hidePopover = function () {
$scope.popoverIsVisible = false;
};
If you have more than one, you are probably better of putting all that stuff into a directive

Manage the heights of two panels dynamically using directive in angularjs

There are two panels in html page, set with the min-height.I want to equate the heights of two panels dynamically based on the height of highest panel using directive.I have worked with the following directive,
app.directive('setHeightmaster', function ($timeout) {
return function (scope, element, attrs) {
scope.$watch(function () {
element.css("min-height", $('#mp').css("height"));
});
});
app.directive('setHeightpanel', function ($timeout) {
return function (scope, element, attrs) {
scope.$watch(function () {
element.css("min-height", $('#hm').css("height"));
});
}
});
In html file, I have included the directive for two panels section.
<div class="col-lg-2 col-md-2 col-sm-2 pad-left-3 pad-right-1">
<section class="panel panel-success sideMealPanel" id="hm" set-heightmaster>
<div class="panel-heading panel-title">
<span>Meal
</span>
</div>
<div class="panel-body panel-body-height-without-footer pad-0">
<div class="pad-15" ng-include="'..MealtimeDetail.html'"></div>
</div>
</section>
</div>
<div class="col-lg-10 col-md-10 col-sm-10 pad-left-1 pad-right-0 page-table">
<section class="panel panel-success" id="mp" set-heightpanel>
</div>
When the height of one panel changes, other panel's height should be dynamically set to the height of first panel and vice a versa. The above code equates the heights of two panels leaving the blank space at the bottom of content in both panels. I want to remove that extra space and eauate the heights without leaving the space in both panels at the bottom.
Where am i wrong with above code? How can i solve this?
Thank you.
I believe you can't do this in this way.
Your directive would only be executed only once or the first time content is loaded. So, when your content has changed, there is no way for the directive to know that it has to work its magic again.
You need to make sure that code runs again after content is loaded again.
After you content has changed, broadcast an event from the controller, and catch it in the directive and then re-adjust the heights.
Watch doesn't works over CSS properties.
And Event mechanism works much better.

Template-expanding directives not rendering on the DOM

I've created a JSFiddle demonstration of a problem I've been facing, where my template-expanding directives are not functioning correctly.
In the JSFiddle, there are three buttons, where each toggles a different colored box.
redBox {
height: 50px;
width: 50px;
background-color: red;
border: 2px solid black;
}
// etc, etc.
Clicking a button toggles the display of one of the colored boxes.
<body ng-app="boxApp">
<div ng-controller="NavCtrl">
<nav>
<button ng-click="shownSection = 'red'">Show red box</button>
<button ng-click="shownSection = 'blue'">Show blue box</button>
<button ng-click="shownSection = 'green'">Show green box</button>
</nav>
<article>
<redBox ng-show="shownSection == 'red'"></redBox>
<blueBox ng-show="shownSection == 'blue'"></blueBox>
<greenBox ng-show="shownSection == 'green'"></greenBox>
</article>
</div>
</body>
Lastly, each fooBox element corresponds to an AngularJS directive that I would like to create a new DOM element based on a simple template.
var app = angular.module("boxApp", []);
app.controller("NavCtrl", function ($scope) {
$scope.shownSection = "";
});
app.directive('redBox', function() {
return {
restrict: "E",
template: '<div>red box</div>',
}
});
app.directive('greenBox', function() {
return {
// etc.
}
});
It doesn't work. In fact, the application behaves the same way regardless of whether or not I define the directives in the first place: it toggles each DOM element as intended, but displays the element as empty - ignoring the height and width properties but not the border property.
I assumed that the fooBox elements would render on the page because AngularJS would recognize these directives when it initially traverses the DOM, but it doesn't seem to do anything, and I don't get any console errors.
What am I doing incorrectly?
A few things.
You named your directives redBox / blueBox / greenBox the camel-case means a - goes between the letters.
So in the html it needs to look like this:
<red-box />
<blue-box />
<green-box />
Your CSS also needs to change to red-box { }.
Also put display:block; within your CSS for the blocks. That's why the height & width are being ignored.
jsFiddle updated*

Resources