I've been trying to create a typewriter effect in Angular2.
My question basically is what is the best approach. The only way I've been able to do this is through CSS animiations. This does not give me the desired result yet. I've tried three approaches so far.
CSS approach
Created a component, with a separate style sheet.
@import url(http://fonts.googleapis.com/css?family=Anonymous+Pro);
.typewriter h2 {
margin: 0 auto;
border-right: .15em solid white;
text-align: center;
white-space: nowrap;
overflow: hidden;
transform: translateY(-50%);
animation: typewriter 2.5s steps(28) 1s 1 normal both,
blinkTextCursor 500ms steps(28) infinite normal;
}
@keyframes typewriter{
from { width: 0 }
to { width: 100% }
}
@keyframes blinkTextCursor{
from{border-right-color: rgba(255,255,255,.75);}
to{border-right-color: transparent;}
}
#typewriterbox {
display: inline-block;
}
Next the HTML in which the component will be added.
<div class="page-title">
<animated-typing>CSS Typewriter effect</animated-typing>
</div>
And the component file:
import {Component} from '@angular/core'
@Component({
moduleId: module.id,
selector : 'animated-typing',
styleUrls: ['animated-typing.component.css'],
template: `<div id="typewriterbox" class="typewriter"><h2><ng-content></ng-content></h2></div>`
})
export class AnimatedTypingComponent {}
Then the other two approaches I've tried, both of which didn't work. Which basically just meant adding a script to my index.html.
Javascript approach
This is some typewriter code I got from codepen. http://codepen.io/gavra/pen/tEpzn
This part fails when getting the HTML.
var destination = document.getElementById("typedtext");
The script uses getElementById, which returns null. Then breaks when it tries to set destination.value. From what I've understood so far this is Not the way to go, but I wanted to see if it's possible.
<script type="text/javascript" src="js/test.js"></script>
// set up text to print, each item in array is new line
var aText = new Array(
"There are only 10 types of people in the world:",
"Those who understand binary, and those who don't"
);
var iSpeed = 100; // time delay of print out
var iIndex = 0; // start printing array at this posision
var iArrLength = aText[0].length; // the length of the text array
var iScrollAt = 20; // start scrolling up at this many lines
var iTextPos = 0; // initialise text position
var sContents = ''; // initialise contents variable
var iRow; // initialise current row
function typewriter()
{
sContents = ' ';
iRow = Math.max(0, iIndex-iScrollAt);
var destination = document.getElementById("typedtext");
while ( iRow < iIndex ) {
sContents += aText[iRow++] + '<br />';
}
destination.innerHTML = sContents + aText[iIndex].substring(0, iTextPos) + "_";
if ( iTextPos++ == iArrLength ) {
iTextPos = 0;
iIndex++;
if ( iIndex != aText.length ) {
iArrLength = aText[iIndex].length;
setTimeout("typewriter()", 500);
}
} else {
setTimeout("typewriter()", iSpeed);
}
}
typewriter();
Then finally the approach of which I think is what 'Angular' intended. I have however not been able to get that working. Meaning the 'typerwiter' code is in the component ts file. Or maybe through a directive. Since 'all valid javascript code' should also work in typescript I just copied the javascript. Nothing yet though.
Angular2 approach
This is the component file I created. While figuring out Angular 2 I'm also learing typescript so new at that as well. It gives a reference error on the typewriter function. The HTML part in the template stays the same as before.
import {Component} from '@angular/core';
@Component({
moduleId: module.id,
selector : 'animated-typing',
template: `<div><h2><ng-content></ng-content></h2></div>`,
host: {
'id':'typedtext'
}
})
export class AnimatedTypingComponent {
constructor(){
typewriter();
}
}
function typewriter()
{
// set up text to print, each item in array is new line
var aText = new Array(
"I",
"Love",
"to",
"Code."
);
var iSpeed = 100; // time delay of print out
var iIndex = 0; // start printing array at this posision
var iArrLength = aText[0].length; // the length of the text array
var iScrollAt = 20; // start scrolling up at this many lines
var iTextPos = 0; // initialise text position
var sContents = ''; // initialise contents variable
var iRow; // initialise current row
sContents = ' ';
iRow = Math.max(0, iIndex-iScrollAt);
var destination = document.getElementById("typedtext");
while ( iRow < iIndex ) {
sContents += aText[iRow++] + '<br />';
}
destination.innerText = sContents + aText[iIndex].substring(0, iTextPos) + "_";
if ( iTextPos++ == iArrLength ) {
iTextPos = 0;
iIndex++;
if ( iIndex != aText.length ) {
iArrLength = aText[iIndex].length;
setTimeout("typewriter()", 500);
}
} else {
setTimeout("typewriter()", iSpeed);
}
}
Lastly I've added app.module.ts for good measure. Where the component is imported:
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HttpModule } from '@angular/http';
import { AppComponent } from './app.component';
import { AnimatedTypingComponent } from './components/features/animated-typing.component';
@NgModule({
imports: [ BrowserModule, HttpModule ],
declarations: [ AppComponent, AnimatedTypingComponent ],
bootstrap: [ AppComponent ]
})
export class AppModule { }