2

Supposedly I have the following HTML

<div ng-if="running">
    <div id="someid"></div>
</div>
<span ng-click="myfunc">Click</span>

In angular controller I set a function when click a button

$scope.myfunc = function(){
    $scope.running = true;

    //attach some jquery event
    $('#someid').on('animationend', function(){...})
}

I want to update the DOM right after running=true because if I dont or put the attached event somewhere else, it doesn't work because the DOM didnt exist yet. ng-if seems to remove it and it only shows the div only when the function ends. I tried $scope.$digest() right after running not work either and it shows error.

So what's the proper way to attach the event above?

2
  • 2
    It looks like a Directive would solve that - I would have a read about Angular directives and how you can manipulate the element and attach events to it :) Commented Aug 10, 2016 at 15:56
  • If you want you can see my example with an Angular directive. Commented Dec 30, 2017 at 11:14

2 Answers 2

1

Try using $timeout in your controller, in this way:

    myApp.controller('exampleController', ['$scope', '$timeout', function($scope, $timeout) {

                $scope.myfunc = function(){
                   $scope.running = true;            

                   var timeout = $timeout(function({
                     $('#someid').on('animationend', function(){...})  

                     $timeout.cancel(timeout);  
                   }, 0)
                }
            }]);

Shortly speaking, $timeout with 0 as interval lets you to wait for the next digest cycle.

Sign up to request clarification or add additional context in comments.

1 Comment

This is a workaround. Please see my example, using an Angular directive.
0
<div ng-if="running">
    <div id="someid"></div>
</div>
<span ng-click="myfunc()">Click</span>

//in controller
    $('#someid').on('animationend', function(){
     $scope.$apply(function() {
       //$scope.blabla = 'hello';
     })
    });

$scope.myfunc = function(){
    $scope.running = true;
}

But you should make a directive

EDIT:

var app = angular.module('myApp', []);

app.directive('startAnimate', function () {
	return {
		scope: {
			startAnimate: '@', //animation name (string)
			seconds: '@', //duration in seconds (int)
			startOnCreation: '=?', //start on creation of element (boolean) - optional
			onAnimationEnd: '=?', //callback at end - optional
			workspace: '=?' //create an object to allow two-way data binding with primitive values (boolean, int, ...) - optional
		},
		link: function (scope, element, attributes) {
			var animation = scope.startAnimate + ' ' + scope.seconds + 's';

			if (!scope.workspace) {
				scope.workspace = {};
			}

			scope.workspace.running = false;

			var setElementSAnimation = function (animation) {
				element.css({
					WebkitAnimation: animation,
					animation: animation
				});
			}

			var startAnimation = function () {
				setElementSAnimation(animation);

				scope.workspace.running = true;
			}

			if (scope.startOnCreation) {
				startAnimation();
			}

			element.click(function () {
				scope.$apply(function () {
					startAnimation();
				});
			});

			if (!scope.onAnimationEnd) {
				scope.onAnimationEnd = function () { };
			}

			var oldAnimationEnd = scope.onAnimationEnd;

			scope.onAnimationEnd = function () {
				oldAnimationEnd();

				//clean animation to allow to repeat it
				setElementSAnimation('');

				scope.$apply(function () {
					scope.workspace.running = false;
				})
			};

			element.on("webkitAnimationEnd animationend", scope.onAnimationEnd);
		}
	}
});

app.controller('myCtrl', function ($scope) {
	$scope.myfunc = function () {
		alert('finish');
	}

	$scope.showElement = false;

	$scope.workspace = {
		running: false
	}
});
#myDIV {
	width: 100px;
	height: 100px;
	background: orange;
	position: relative;
}

@-webkit-keyframes mymove {
	from {
		top: 0px;
		left: 0px;
	}

	to {
		top: 80px;
		left: 160px;
	}
}

@keyframes mymove {
	from {
		top: 0px;
		left: 0px;
	}

	to {
		top: 80px;
		left: 160px;
	}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>

<div data-ng-app="myApp" data-ng-controller="myCtrl">
	<div data-ng-if="workspace.running">
		Yes, it's running!
	</div>

	<div id="myDIV" data-ng-if="showElement" data-start-animate="mymove" data-start-on-creation="true" data-seconds="4" data-on-animation-end="myfunc" data-workspace="workspace">
		<span>Click me to start the animation.</span>
	</div>

	<button type="button" data-ng-click="showElement = !showElement">Toggle element</button>
</div>

4 Comments

$('#someid') not exists because ng-if remove that div from the DOM
"But you should make a directive" I answered in August of last year. Sorry for the delay, now I showed you the correct way.
There's too much code compare to the accepted answer... ty for trying
Accepted answer is a workaround, bad practice. The code you have to see is the html code. The directive is reusable. data-start-animate="mymove" data-start-on-creation="true" data-seconds="4" data-on-animation-end="myfunc" data-workspace="workspace"

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.