Académique Documents
Professionnel Documents
Culture Documents
WhatifcomponentsinAngular2werewiredalwayshaveaninternalstatewhichallowedfor
otherpartsoftheframeworktodopreparatoryUIrelatedworksothatwhenthatstatechanges
Angularcanattempttotakeonasmuchoftheanimationaspossible.
Settingthefoundationforanimations
AnimationsinAngular2.0arenothereyet,however,statechangesbetweenacomponentor
multiplestatechangesamongmultiplecomponentswouldbeaniceplatformforAnimationsto
betriggeredon.
BasicStateChange
Letsimaginethatwehaveacomponentcalled<zippy>whichisdesignedtoopenandclose.
Bydefinitiontherearetwostatesandthesetwostatesarestatesthatthecomponentmanages
itselfwithinitsdefinition:
@Component({
selector:zippy
})
classZippy{
open:Boolean
}
Triggeringanimations,however,isnonexistentsinceAngulardoesntknowthattheopen/close
booleanvaluedictatesthestateofthecomponent.Thereforewewillplaceavaluewithinthe
annotationtoreflectthat:
@Component({
selector:zippy
state:open//the`open`booleanmembervalueiswatched
})
Nowwhentheopenstatechangesitwillimposethatchangeontoitscomponentcontainer.
Nowitswhenthestatechangeoccursthattheanimationwilltakeoff.Letsimaginethatour
CSStransitioncodebelowwillmatchthestatechangeforthezippycomponent:
/*rememberthatyoucanalsoplaceaclassontheelementand
targetthatonespecifically*/
zippy.fromclosed.toopen{
transition:0.5slinearall
}
NoticehowthereisnoactualCSSstylingcodeinheretotellthetransitionwhattodo?Allthat
wehavehereisatransitionvaluewhichwillthenactivatethestatetransitionforus.Nowwhat
abouttheactualstylechangesthatoccurforthezippyforitsopenandclosedstates?Since
thosestateshavenothingtodowithanimation,andarearequiredpiecetoexistforwhenthe
zippyisopenorclosed,theCSSstylesforthezippyaredefinedwithinthecomponent
container.
zippy.ngopen{
maxheight:500px
}
zippy.ngclosed{
maxheight:500px
}
Sinceweprovidedatransitionforthestatechangethenthatsallrequiredforthecomponentto
doitsthing.
ImplicitStatesEnter/Leave/Move
WhenacomponentisinsertedintotheDOMthenthatisastatechangefromdetachedto
whateverstatethecomponentwillbeoradefaultstatecalledngdefault.Whena
componentisremovedthenitwillbemovedfromitscurrentstatetodetached.
SoifwesetourzippytobeopenbydefaultwhenitisplacedintheDOMthenthestateshould
gofromdetachedtoopen.
<zippy*ngif=yes[open]=yes></zippy>
zippy.ngdetached{
opacity:0
}
zippy.ngopen{
maxheight:500px
}
zippy.fromdetached.toopen{
transition:0.5slinearall
}
Nowwhentheitemisinsertedthenitwillperformthisanimationautomatically.
GroupbasedStateChangeSequencing
Statechangesbecomepowerfulwhenthereareamultitudeofstatechangesthatoccur
betweenacollectionofelements.LetssayforexamplewehadthefollowingHTMLcodeforour
viewonourpage:
<!home.html
<h2>HomePage</h2>
<div*ngif=showUsersclass=userscontainer>
<div*ngfor=#userofusersclass=user>
{{user.name}}
</div>
</div>
NowwhathappensifshowUserschangestotrue?Theoutercontainerisevaluatedand
insertedintothepageandtheinnercontainerisalsoevaluatedanditslistofusersisalso
insertedintothepage.Ifnoanimationsaredetectedthennothinghappens,however,if
animationsaredetectedonboththe.userscontainerand.userelementcontainersthenthe
parentcontainer(inthiscase.userscontainer)willwinandtheinnerelementswillnotanimate.
HoweverifweusesomespecialCSScodethenwecanperformananimationsequence
statechangeorchestration.
Togetstartedwiththisletsreiteratethepresenceofthestatechangesforbothsetsof
elements.Theoutercontainerisbeinginsertedandtheinnercontainersaswell.Sowecan
startbydefiningananimationontheoutercontainer:
.userscontainer.fromdetached{
opacity:0
}
.userscontainer.fromdetached.todefault{
transition:0.5slinearall/*thiselementwillfadein*/
}
Nowtheinner.userelementsarealsobeinginsertedfromdetachedtoany,buttheparent
containermaynotknowtheexactdetailsabouttheinnerstatechanges.Soinorderforit
topickupanystatechangeamongitschildrenthenwecouldissueaCSSselectortopickthat
up.
<!thiswillgofromdetachedtoitsdefaultstate
<!butanystatechangewillalsohaveaCSSclassof
ngstatechange>
<div*ngfor=#userofusersclass=user>
{{user.name}}
</div>
Wheneveranycomponentperformsastatechangeatemporaryclassofngstatechange
willbeappliedtotheelementsthatarechangingstate.ThisallowsforaCSSselectortoquery
theinner,changingelementsandissuesomekindofdelayorstaggerorchestration.
ButhowdowedothisinCSS?
CSSCustomStyles/Properties
CustomCSSStyles/PropertiesarepossiblewithahackwhichmakesuseoftheCSScontent
propertybypreparingalistofkey/valueproperties,creatingaJSONobject,andpastingthe
contentsofthatJSONintothatcontentpropertyontheelement.
body{
content:{custom:value}
}
ThisworksinallbrowsersotherthanIE,butifweduplicatethecontenttagandprependitwitha
hyphenthenitworksinIEwhenaccessedviatheelement.currentStylehashobject.
body{
content:{custom:value}
content:{custom:value}
}
TomakethislessuglywewilluseabuildstepinourAngular2.0buildpipelinethatwillmake
custompropertiesconvertthemselvestothis.
Sothis
body{
custom:value
}
Becomesthis:
body{
custom:value
content:{custom:value}
content:{custom:value}
}
ThenngAnimatecanreadthesecustomvaluesdirectlyviagetComputedStyleand
element.currentStyle.
CustomPropertiestoOrchestrateAnimations
SincewecanusecustompropertieswecanputtogetherauniquepropertythattellsngAnimate
toholdofffromanimationsthatoccuronchildelements.
Wecanhaveourparentcontainercalled.userscontainertellthechildanimationstowait:
.userscontainer.fromdetached.todefault{
/*runallchildanimationsfor0.5sandstaggerby0.1s*/
nganimatechildren:*.ngstatechange0.5s0.1s
}
Orissueaspecifictransitionorkeyframetorun
.userscontainer.ngenter{
nganimatechildren:
*.ngstatechange(.someclass0.5s)0.1s
nganimatechildren:
*.ngstatechange(@keyframe0.5s)0.1s
nganimatechildren:
*.ngstatechange(@keyframe0.5s,.someclass0.5s)
0.1s
}
Thenicethinghereisthatthechildanimationsstillanimatetheirownway,buttheparent
container/componentcanoverrideandreorganizetheirbehaviour.
TheJSdriverequivalentcandothesamething.
classPageAnimator{
@Animate({
target:.userscontainer,
children:*.ngstatechange
})
usersAnimation(target,children){
//dowhateveryouwantonthechildelements
varpromises
children.forEach(function(child){
promises.push(newPromise(resolve){
setTimeout(function(){
child.animate(resolve)
},i*100)
}))
})
returnPromise.all(promises)
}
}
AnimatingNonAngularElements
SincebothCSSandJSsequencinguseCSSstyleselectorsthismeansthatwecansequence
animationsonelementsthatarenotassociatedwithAngularorngAnimate.
Thereforesomethinglikethiscouldbeusedtoanimatetheparentelementandthechild
animationswithasingleselector.
.ifcontainer.fromdetached.todefault{
nganimate:*(.fade0.5s)serial
}
<div*ngif=exp>
<p>...</p>
<p>...</p>
<div[css.hide]=exp>...</div>
<p>...</p>
<p>...</p>
</div>
Everythinginherenowanimatesonebyone.
IntegrationwiththeRouter
Sinceeachcontainercontainsastate,therouterwillautomaticallyissuestatesbasedonthe
aliasvaluedefinedineachroute.
@RouteConfig({
/:{as:home,component:HomeCmp},
/about:{as:about,component:AboutCmp},
})
Nowwhentheroutechanges,thecomponentcontainerwillautomaticallyincludethestate
change:
appcomponent.fromhomeroute.toaboutroute{
nganimate:*.todetached(.fadeout0.5s)serial,
*.fromdetached(.fadein0.5s)serial
}
CustomStatesfromthetemplate
Sincestatechangesareissuedfromwithinthecomponent,itgetsdifficulttoapplyyourown
statevaluesfromwithinthetemplatewithoutcreatingacomponentofyourown.Sayfor
examplewehad*ngifandwewantedtohaveourownstateworkwithit:
<!theonlystateshereareenter/leave>
<div*ngif=exp></div>
Butifweusethengstateattributethenitwillwork:
<!theonlystateshereareenter/leave>
<div*ngif=exp[ngstate]=myCustomState></div>