I want to implement a text animation so following:
https://stackblitz.com/edit/text-animation-demo-with-animejs?file=src%2Fapp%2Fapp.component.html,src%2Fapp%2Fapp.component.ts
i copied to my file the code:
export class HeroSectionMainTextComponent {
ngAfterViewInit(): void {
// Wrap every letter in a span
const textWrapper = document.querySelector('.an-1');
textWrapper.innerHTML = textWrapper.textContent.replace(
/\S/g,
"<span class='letter'>$&</span>",
);
anime
.timeline({ loop: true })
.add({
targets: '.an-1 .letter',
scale: [4, 1],
opacity: [0, 1],
translateZ: 0,
easing: 'easeOutExpo',
duration: 950,
delay: (el, i) => 70 * i,
})
.add({
targets: '.an-1',
opacity: 0,
duration: 1000,
easing: 'easeOutExpo',
delay: 1000,
});
}
}
but i got an error:
TS18047: 'textWrapper' is possibly 'null'.
so i tried adding ?. like this:
const textWrapper = document.querySelector('.an-1');
textWrapper?.innerHTML = textWrapper?.textContent.replace(
/\S/g,
"<span class='letter'>$&</span>",
);
but it didnt work. How to make it work and why on stackblitz it works?
EDIT:
import { Component, AfterViewInit } from '@angular/core';
declare var anime: any; // declare like this
import 'zone.js';
@Component({
selector: 'app-hero-section-main-text',
standalone: true,
imports: [],
templateUrl: './hero-section-main-text.component.html',
styleUrl: './hero-section-main-text.component.css',
})
export class HeroSectionMainTextComponent {
ngAfterViewInit(): void {
// Wrap every letter in a span
const textWrapper = document.querySelector('.an-1');
if (textWrapper) {
textWrapper.innerHTML =
textWrapper?.textContent?.replace(
/\S/g,
"<span class='letter'>$&</span>",
) || '';
}
anime
.timeline({ loop: true })
.add({
targets: '.an-1 .letter',
scale: [4, 1],
opacity: [0, 1],
translateZ: 0,
easing: 'easeOutExpo',
duration: 950,
delay: (el: any, i: any) => 70 * i,
})
.add({
targets: '.an-1',
opacity: 0,
duration: 1000,
easing: 'easeOutExpo',
delay: 1000,
});
}
}
now i dont get any error but the animation simply doesnt start..
>Solution :
We just need to check the left hand side textWrapper property is not null, we can use a if condition to check this! also added || '' so that the right hand side does not return undefined but empty string instead!
You have strictNullChecks enabled in typescript, could also be due to strict enabled in tsconfig.json
const textWrapper = document.querySelector('.an-1');
if (textWrapper) {
textWrapper.innerHTML =
textWrapper?.textContent?.replace(
/\S/g,
"<span class='letter'>$&</span>"
) || '';
}
full code
import { Component, AfterViewInit } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
import { AppModule } from './app.module';
declare var anime: any; // declare like this
import 'zone.js';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
imports: [AppModule],
standalone: true,
})
export class AppComponent implements AfterViewInit {
ngAfterViewInit(): void {
// Wrap every letter in a span
const textWrapper = document.querySelector('.an-1');
if (textWrapper) {
textWrapper.innerHTML =
textWrapper?.textContent?.replace(
/\S/g,
"<span class='letter'>$&</span>"
) || '';
}
anime
.timeline({ loop: true })
.add({
targets: '.an-1 .letter',
scale: [4, 1],
opacity: [0, 1],
translateZ: 0,
easing: 'easeOutExpo',
duration: 950,
delay: (el, i) => 70 * i,
})
.add({
targets: '.an-1',
opacity: 0,
duration: 1000,
easing: 'easeOutExpo',
delay: 1000,
});
}
}
bootstrapApplication(AppComponent);