AngularJS Typed Effect

by Gareth Whittaker

HTML

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.7/angular.js"></script>
<div ng-app="myApp" ng-controller="MyController as vm">
    <p typed-effect text="'hi there, I use a typed effect ...'" blink="false"></p>
    <p typed-effect text="'my start can be delayed ...'" delay="4000" blink="false"></p>
    <p typed-effect text="'you can vary my speed ...'" delay="7500" speed="50" blink="false"></p>
    <p typed-effect text="'or customise my cursor. '" delay="9500" cursor="&blk14;" callback="vm.typed()"></p>
</div>

CSS

body {
    font-family: Arial;
    font-size: 2rem;
    color: #555;
}

@-webkit-keyframes blink {
    50% {
        opacity: 0;
    }
}

@-moz-keyframes blink {
    50% {
        opacity: 0;
    }
}

@-o-keyframes blink {
    50% {
        opacity: 0;
    }
}

@keyframes blink {
    50% {
        opacity: 0;
    }
}

.blink {
    -webkit-animation: blink 1s infinite;
    -moz-animation: blink 1s infinite;
    -o-animation: blink 1s infinite;
    animation: blink 1s infinite;
}

JavaScript

(function() {
    'use strict';
    
    angular
        .module('myApp', ['angularJSTypedEffect'])
        .controller('MyController', MyController);
        
    function MyController() {
        var vm = this;
        
        vm.typed = typed;
        
        function typed() {
            console.log('callback demo - this function was triggered after typing finished');
        }
    }
})();
    
/////////////

(function() {
    'use strict';

    angular
        .module('angularJSTypedEffect', [])
        .directive('typedEffect', typedEffect);

    typedEffect.$inject = ['$interval', '$timeout'];

    function typedEffect($interval, $timeout) {
        var directive = {
            restrict: 'A',
            scope: {
                text: '<',
                callback: '&'
            },
            link: link
        };

        return directive;

        function link(scope, element, attrs) {
            var i = 0, interval,
                text = scope.text || '',
                delay = parseInt(attrs.delay) || 0,
                speed = parseInt(attrs.speed) || 100,
                cursor = attrs.cursor || '|',
                blink = attrs.blink ? attrs.blink === 'true' : true;

            cursor = angular.element('<span>' + cursor + '</span>');

            $timeout(typeText, delay);

            function typeText() {
                typeChar();
                interval = $interval(typeChar, speed);

                function typeChar() {
                    if (i <= text.length) {
                        element.html(text.substring(0, i)).append(cursor);
                        i++;
                    } else {
                        $interval.cancel(interval);

                        if (blink) {
                            cursor.addClass('blink');
                        } else {
                            cursor.remove();
                        }

                        if (attrs.callback) {
                            scope.callback();
  ...