2

I am currently trying to do a CSS3 animation in Angular.js.
Before animating I try to set the initial css properties using Javascript.
So, is there a way to initialize an animation using Javascript and then continue the animation using CSS3?

My situation:
When the user clicks on a div, a dialog should appear. The dialog should start out exactly over the original div (same size, same position), and then grow to a larger size.

I am able to animate the dialog from a predefined position and size:

CSS:

.dialog {
    position: absolute;
    z-index: 10;
    width:600px;
    height:400px;
    margin-left: -300px;
    left:50%;
    margin-top: 50px;
}
.dialogHolder.ng-enter .dialog {
    transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 1s;
    width:0;
    height:0;
    margin-left: 0px;
}
.dialogHolder.ng-enter-active .dialog {
    width:600px;
    height:400px;
    margin-left: -300px;
}

I would like to animate the dialog starting at the size of the clicked div. So far my code (not working yet) looks like this:

HTML:

<div ng-repeat="course in data.courses" ng-click="showDialog($event)">
    {{ course.cursus }}
</div>

<!-- Placeholder for blokDialogs -->
<div class="dialogHolder" ng-include="dialogTemplate.url">
    DIALOG WILL BE LOADED HERE
</div>

Javascript:

app.controller('blockController', function($scope) {

    $scope.showDialog = function(evt) {
        // get position and size of the course block
        $scope.dialogTemplate.clientRect = evt.target.getBoundingClientRect();

        // load the html to show the dialog
        $scope.dialogTemplate.url = 'partials/blokDialog.html';

        // SHOULD I DO SOMETHING HERE?
    };

});

// OR SHOULD I DO SOMETHING LIKE THIS?
app.animation('.dialogHolder', function(){
    return {
        // SOMEHOW SET THE WIDTH, HEIGHT, TOP, LEFT OF .dialog
    };
});

I'd prefer to do this without jQuery to keep the page weight low.

Regards, Hendrik Jan

Hendrik Jan
  • 4,396
  • 8
  • 39
  • 75

2 Answers2

1

You want to use ng-animate http://docs.angularjs.org/api/ngAnimate

If you are using ng-repeat, you can animate when elements enter, leave and move around your repeater. The magic is that you don't even have to put an extra directive in your html, just define your CSS animations accordingly.

So in your case something like this

.repeater.ng-enter, .repeater.ng-leave, .repeater.ng-move {
  -webkit-transition:0.5s linear all;
  transition:0.5s linear all;
}

.repeater.ng-enter { }
.repeater.ng-enter-active { }
.repeater.ng-leave { }        
.repeater.ng-leave-active { }
.repeater.ng-move { }        
.repeater.ng-move-active { }

and your HTML

<div ng-repeat="..." class="repeater"/>
NicolasMoise
  • 7,261
  • 10
  • 44
  • 65
  • Or if you want to animate the div with ng-include you can use the same logic (but only with enter and leave animations) – NicolasMoise Jan 27 '14 at 15:51
  • Thank you Nicolas. That is what I am using now. My problem is that I want the initial state to depend on the event. So the CSS in ng-enter and ng-leave is different every time the animation starts. Maybe I should have been a bit clearer when explaining my intend.. – Hendrik Jan Jan 28 '14 at 08:15
1

In the end, I found the following solution:


HTML:
Create an onClick handler and a placeholder where the dialog is loaded.

<!-- Element on which the user clicks to initialize the dialog -->
<div ng-repeat="course in data.courses"
     ng-click="showDialog($event, course)">
 {{ course.name }}
</div>

<!-- Placeholder for blokDialogs -->
<div class="dialogHolder"
     ng-include="dialogTemplate.url"
     onload="showDialogLoaded()">
</div>


HTML Template:
partials/blokDialog.html sets it's style using ng-style.

<div ng-style="dialogTemplate.initialStyle">
...
</div>


Javascript:
The onClick handler sets the initial CSS before the animation starts.

$scope.showDialog = function(evt, course) {

    // Load the dialog template
    $scope.dialogTemplate.url = 'partials/blokDialog.html';

    // set the css before the animation starts
    // get position and size of the course block
    var clientRect = evt.target.getBoundingClientRect();
    $scope.dialogTemplate.initialStyle = {
        left: clientRect.left + 'px',
        top: clientRect.top + 'px',
        width: clientRect.width + 'px',
        height: clientRect.height + 'px',
        backgroundColor: getComputedStyle(evt.target).backgroundColor
    };

};

The style needs to be removed before the animation ends but after the animation started.
The animation starts at the end of the onLoad handler. If we remove the style in the onLoad handler (i.e. in showDialogLoaded), then we are to early.
We use setTimeout to make sure that the removal of the style is done after the animation was started.

$scope.showDialogLoaded = function() {
    // remove the style that we set in showDialog
    setTimeout(function(){
        $scope.dialogTemplate.initialStyle = {};
        // we need to $apply because this function is executed
        // outside normal Angular handling, so Angular does not know
        // that it needs to do a dirty check
        $scope.$apply();
    }, 0);
};

I hope this can be helpful for others.
Regards,
HJ

Hendrik Jan
  • 4,396
  • 8
  • 39
  • 75