Learn Conditional Rendering with Funny Gangnam Style Dancing using LWC

 

By Smriti Sharan and Shatarchi Goyal

Hello Friends, In this chapter I would like to make your learning awesome fun so that you cannot stop yourself to learn Lightning Web Component. 🙂

Note: Not used any third party library or flash animation. It’s Pure LWC magic ! 

Topics Covered:

Conditional Rendering in LWC

CSS Animation in Lightning Web Component

Code Snippet

Understanding Code Line by Line

Let’s get Started …..

Much awaited code to learn conditional rendering by Funny Gangnam Style Dance made using LIghtning Web Component is below:

Gangnam.html

<template>
     <h1>Gangnam Style</h1>
       <div class="toggleGroup">
        <lightning-input type="toggle" label="Music" onchange={toggleMusic}></lightning-input>
        <lightning-input type="toggle" label="Dance" onchange={toggleDance}></lightning-input>
        <lightning-input type="toggle" label="Clone" onchange={toggleClone}></lightning-input>
     </div>
        <audio class="music" loop="loop" src={musicres}></audio>
        <div class="dancers">  
        <div class="character"></div>
        <div class="character_clone"></div>
       </div>
</template>

Gangnam.js

import { LightningElement} from 'lwc';
import MUSIC_RESOURCE from '@salesforce/resourceUrl/gangnammusic';
export default class App extends LightningElement {

    musicres = MUSIC_RESOURCE;

    toggleMusic(event){
        this.playMusic = event.target.checked;
        this.audio = this.template.querySelector('.music');

        console.log(this.playMusic);
        if(this.playMusic){
            this.audio.play();
        }else{
            this.audio.pause();
        }
    }

    toggleDance(event){
        this.doDance =  event.target.checked;
        this.dance = this.template.querySelector('.character');
        this.dance_clone = this.template.querySelector('.character_clone');

        if(this.doDance){
            this.dance.classList.add('characterDance');
            this.dance_clone.classList.add('characterDance');

        }else{
            this.dance.classList.remove('characterDance');          
            this.dance_clone.classList.remove('characterDance');
        }

    }
    toggleClone(event){
        this.playClone = event.target.checked;
        this.clone = this.template.querySelector('.character_clone');
        if(this.playClone){
            this.clone.style.display = 'block';
        }else{
            this.clone.style.display = 'none';
        }
    }

}

Gangnam.css

.dancers{
  display: flex;
  background: radial-gradient( farthest-corner circle at left bottom,#4bffee,#f9fbb6);
  margin: 0 auto;
  border:15px solid blue;
  padding: 2rem 1rem;
  border-image: url("data:image/svg+xml;charset=utf-8,%3Csvg width='100' height='100' viewBox='0 0 100 100' fill='none' xmlns='http://www.w3.org/2000/svg'%3E %3Cstyle%3Epath%7Banimation:stroke 5s infinite linear%3B%7D%40keyframes stroke%7Bto%7Bstroke-dashoffset:776%3B%7D%7D%3C/style%3E%3ClinearGradient id='g' x1='0%25' y1='0%25' x2='0%25' y2='100%25'%3E%3Cstop offset='0%25' stop-color='%232d3561' /%3E%3Cstop offset='25%25' stop-color='%23c05c7e' /%3E%3Cstop offset='50%25' stop-color='%23f3826f' /%3E%3Cstop offset='100%25' stop-color='%23ffb961' /%3E%3C/linearGradient%3E %3Cpath d='M1.5 1.5 l97 0l0 97l-97 0 l0 -97' stroke-linecap='square' stroke='url(%23g)' stroke-width='3' stroke-dasharray='388'/%3E %3C/svg%3E") 1;

}
.toggleGroup{
  display: flex;
  margin-left:50px;
  margin-top:50px;
}
.character{
  width: 225px; 
  height: 400px;
  background-image: url(https://estelle.github.com/10/files/sprite.png);
}
.characterDance {
  animation: gangham 4s steps(23,start) infinite,
    movearound 12s steps(69,end) infinite alternate 44ms;
  animation-direction: normal, alternate;
}
.character_clone{
  display:none;
  width: 225px; 
  height: 400px;
  background-image: url(https://estelle.github.com/10/files/sprite.png);
  filter: grayscale(100%);
  margin-left:250px;
}
@keyframes gangham {
  0% {background-position: 0 0}
  100% {background-position: -5175px 0}
}
@keyframes movearound {
  0% {transform: translatex(0)}
  100% {transform: translatex(600px);}
}
h1{
  font-size: 90px;
  text-align: center;
  font-family: comic sans ms;
  font-weight: bold;
  color: #0189fe;
  text-shadow: 4px 4px #00e7ff;
}

Understanding Code Line by Line : HTML

<lightning-input type=”toggle” label=”Music” onchange={toggleMusic}>

Created input base component of type toggle for music and onchange of it invoked toggleMusic

<lightning-input type=”toggle” label=”Dance” onchange={toggleDance}>

Created input base component of type toggle for dance and onchange of it invoked toggleDance

<lightning-input type=”toggle” label=”Clone” onchange={toggleClone}>

Created input base component of type toggle for clone and onchange of it invoked toggleClone

<audio class=”music” loop=”loop” src={musicres}>

  • The <audio> tag is used to embed sound content in a document, such as music or other audio streams.
  • The loop attribute is a boolean attribute. When present, it specifies that the audio will start over again, every time it is finished.
  • The audio tag contains one or more source tags with different audio sources. The browser will choose the first source it supports. Here I have taken music from static resource and {musicrec} is coming from JavaScript
  • There are three supported audio formats in HTML: MP3, WAV, and OGG.

<div class=”dancers”>

Created a div with class name “dancers” it is a wrapper div holding “character” and “character_clone” div classes

<div class=”character”>

This class is used to display the first character on the screen

<div class=”character_clone”>

This class is used to display clone character on the screen.

Understanding Code Line by Line : JavaScript

import MUSIC_RESOURCE from ‘@salesforce/resourceUrl/gangnammusic’;

I am importing music named gangnammusic from static resource

musicres = MUSIC_RESOURCE;

Expose the static resource URL for use in the template

toggleMusic(event){
this.playMusic = event.target.checked;
this.audio = this.template.querySelector('.music');

if(this.playMusic){
this.audio.play();
}else{
this.audio.pause();
}
}

toggleMusic(event)

Created a function named toggleMusic. This function is invoked when toggle is moved from inactive to active

this.playMusic = event.target.checked;

The target event property returns the element that triggered the event and saves the value in playMusic.

checked

The checked property sets or returns the checked state of a checkbox.

this.audio = this.template.querySelector(‘.music’);

The Audio object represents the <audio> element given in the template.

You can access an <audio> element by using querySelector() and getting classname of the audio element

if(this.playMusic){

this.audio.play();

}

if playMusic is there i.e. toggle is active or checked then play music.The play() method starts playing the current audio.

else{
this.audio.pause();
}

Else pause the music.Pause() method pauses the current audio

    toggleDance(event){
        this.doDance =  event.target.checked;
        this.dance = this.template.querySelector('.character');
        this.dance_clone = this.template.querySelector('.character_clone');

        if(this.doDance){
            this.dance.classList.add('characterDance');
            this.dance_clone.classList.add('characterDance');

        }else{
            this.dance.classList.remove('characterDance');          
            this.dance_clone.classList.remove('characterDance');
        }

toggleDance(event)

toggle dance function is invoked when user checks toggle dance.

this.doDance = event.target.checked;

the checked value is saved in this.doDance

this.dance = this.template.querySelector(‘.character’);

Gets the character by doing QuerySelector on character class name

this.dance_clone = this.template.querySelector(‘.character_clone’);

Gets the clone character by doing QuerySelector on clone character class name

if(this.doDance)

if element toggle is checked

this.dance.classList.add(‘characterDance’);

classList

  • The classList property returns the class name(s) of an element, as a DOMTokenList object.
  • This property is useful to add, remove and toggle CSS classes on an element.
  • The classList property is read-only, however, you can modify it by using the add() and remove() methods.

Here we are adding characterDance class to character class

this.dance_clone.classList.add(‘characterDance’);

Here we are adding characterDance class to clone character class

else{
this.dance.classList.remove(‘characterDance’);
this.dance_clone.classList.remove(‘characterDance’);
}

Else if element toggle is not checked then remove CharacterDance class from Character and Clone_Character class. This way characters will stop dancing.

toggleClone(event){
this.playClone = event.target.checked;
this.clone = this.template.querySelector('.character_clone');
if(this.playClone){
this.clone.style.display = 'block';
}else{
this.clone.style.display = 'none';
}
}

toggleClone(event)

This function is invoked when clone toggle is activated or checked

this.playClone = event.target.checked;

this. playClone stores the checked value of the toggle

this.clone = this.template.querySelector(‘.character_clone’);

get the character_clone class by using querySelector

if(this.playClone){
this.clone.style.display = ‘block’;}

if Toggle Clone is checked then display clone character

else{
this.clone.style.display = ‘none’;
}

else if Toggle Clone is unchecked then do not display clone character.

Understanding Code Line by Line : CSS

h1{
font-size: 90px;
text-align: center;
font-family: comic sans ms;
font-weight: bold;
color: #0189fe;
text-shadow: 4px 4px #00e7ff;
}

h1 class handles the text “Gangnam Style” at the top

text-shadow – gives the shadow to the text

.dancers{
  display: flex;
  background: radial-gradient( farthest-corner circle at left bottom,#4bffee,#f9fbb6);
  margin: 0 auto;
  border:15px solid blue;
  padding: 2rem 1rem;
  border-image: url("") ;
}
.dancers
Dancers class is used to wrap the two images
 display: flex;

The flex sets how a flex item will grow or shrink to fit the space available in its flex container

background: radial-gradient( farthest-corner circle at left bottom,#4bffee,#f9fbb6);

The radiant-gradiant CSS function creates an image consisting of a progressive transition between two or more colors that radiate from an origin

margin: 0 auto;

Auto as second parameter tells the browser to automatically determine the left and right margins itself, which it does by setting them equally. It guarantees that the left and right margins will be set to the same size.

 border:15px solid blue;

The CSS Border properties allow you to specify the style, width, and color of an element’s border.

padding: 2rem 1rem;

The CSS padding properties are used to generate space around an element’s content, inside of any defined borders.

border-image: url(“”);

The border-image property allows to specify an image to be used as the border around an element.

.toggleGroup{

display: flex;

margin-left:50px;

margin-top:50px;

}

.toggleGroup   this class handles the three input of type of toggle

Creating the character 

.character{
width: 225px;
height: 400px;
background-image: url(https://estelle.github.com/10/files/sprite.png);
}

.character

This class handles the styling of the first character .To animate our character, we’ll first create a rule where we define the width and height dimensions and display the main sprite sheet as a background image.

Image Sprites

An image sprite is a collection of images put into a single image so it has been taken as background-image

Think about cinema film. We have single strip of film with many frames in it. Each frame represent distinct motion breakpoint.

Now think like this, if we could just flash each frame at equal interval, we could see the animation. What we can do is, pull the sprite film to the left, that way we could see the animation. In CSS world, we are setting sprite as background image. By default, div is covering first frame. Then using @keyframes, animating horizontally.

.character_clonedisplay:none;
width: 225px;
height: 400px;
background-image: url(https://estelle.github.com/10/files/sprite.png);
filter: grayscale(100%);
margin-left:250px;
}

.character_clone :

Handles the the clone character. To animate our clone character, we’ll first create a rule where we define the width and height dimensions and display the main sprite sheet as a background image.

Creating the animation

@keyframes gangham {
0% {background-position: 0 0}
100% {background-position: -5175px 0}
}

The @keyframes Rule

When we specify CSS styles inside the @keyframe rule, the animation will gradually change from the current style to the new style at certain times.

To get an animation to work, we must bind the animation to an element.

Next, we need to create a keyframe rule that animates the background position of the sprite sheet. The sprite sheet’s total width is 5175px, so let’s animate it right-to-left by giving it a final background position of -5175px.

Running the animation

.characterDance {
animation: gangham 4s steps(23,start) infinite,
movearound 12s steps(69,end) infinite alternate 44ms;
animation-direction: normal, alternate;
}

animation: gangham 4s

The animation CSS property specifies the name of an animation you will supply, gangham in this case, and its overall duration of 4 second. Both are required

infinite

The infinite keyword indicates that the animation repeats indefinitely. If not specified, the animation executes only once.

steps()

steps() is a timing function that allows us to break an animation or transition into segments, rather than one continuous transition from one state to another.

Start and End

The optional  start and end values define where these steps take place. Perhaps the values are best understood as beats in music:

  • A value of Start , on the other hand, is playing “before the beat”:
  • End (the default) means that movement that steps () make is played “on the beat”

steps(23,start)

To achieve the desired frame-by-frame animation effect, we’ll need to include the steps() timing function in the animation value. Since the sprite sheet contains 23 image sprites, we can say that it’s made up of 23 frames––or steps.

animation-direction

The animation-direction property sets whether an animation should play forward, backward, or alternate back and forth between playing the sequence forward and backward.

 

I hope you enjoyed the chapter!

 

Conclusion: Creativity is contagious. Pass it on.

 

Together we can learn faster !

Join LWC study group on Telegram 

Subscribe to Youtube channel and blog to get latest updates

 

Reference

Making things move with CSS3 animation

Did you enjoy this article?
Signup today and receive free updates straight in your inbox.
I agree to have my personal information transfered to MailChimp ( more information )
50% LikesVS
50% Dislikes