robotsushi robotsushi - 3 months ago 10
CoffeeScript Question

Click Event only triggered from last object in list of layers, not clicked object

I'm new to FramerJS and Coffee Script, but I'm not new to programming. I'm creating some beginner projects to learn about prototyping mobile apps in FramerJS. I'm working on a scroll app with "cards". When a card is clicked it is supposed to scale to the size of the screen. And when you tap it again it will go back into it's previous frame position.

However, what happens is when any card is clicked, the last card in the list is the one that is scaled to the center of the screen. I'm not sure what's going on exactly. Can anyone take a look at the code and see what's going on?

Thanks in advance!

Example 2-column Scroll App

# Project Info
# This info is presented in a widget when you share.
# http://framerjs.com/docs/#info.info

Framer.Info =
title: ""
author: ""
twitter: ""
description: ""


Screen.backgroundColor = "#000"

scroll = new ScrollComponent
width: Screen.width, height: Screen.height
contentInset:
top: 10
bottom: 10
left: 20
right: 10
scroll.scrollHorizontal = false

numCards = 10
cardHeight = 300
rowPadding = 20
columnPadding = 10
cardBorderRadius = 15
cardColumns = 2
cardWidth = (Screen.width / cardColumns) - (columnPadding *2) - scroll.contentInset.right
totalCardWidth = cardWidth + (columnPadding *2)
totalRowHeight = cardHeight + rowPadding

allCards = []
for i in [0...numCards]
card = new Layer
height: cardHeight
width: cardWidth
x: totalCardWidth * (i % cardColumns)
y: if i % cardColumns is 0 then totalRowHeight * (i / cardColumns); lastX = totalRowHeight * (i / cardColumns); else lastX
opacity: 1
borderRadius: cardBorderRadius
superLayer: scroll.content
html: i + 1
backgroundColor: Utils.randomColor(0.95)
card.style =
"font-size": "125px",
"font-weight": "100",
"text-align": "center",
"line-height": "#{card.height}px"
allCards.push card

for c in allCards
c.on Events.Click, (event, layer) ->
currentCard = c.copy()
currentCard.opacity = 1
currentCard.frame = c.screenFrame
c.animate
properties:
midY: Screen.height / 2
scale: Screen.width / currentCard.width
x: Align.center
y: Align.center
curve: 'spring(200,20,0)'
time: 0.2

Answer

In your last loop, you add a click event to each card like so:

for c in allCards
    c.on Events.Click, (event, layer) ->
        currentCard = c.copy()
        currentCard.opacity = 1
        currentCard.frame = c.screenFrame
        c.animate
        ...

When the loop finishes, the global variable c is set to the last card in the allCards array and remains that way, so when any of these click events is called, the last card is the one that is copied and animated.

Instead, one option would be to reference it via the local layer variable in the block:

for c in allCards
    c.on Events.Click, (event, layer) ->
        currentCard = layer.copy()
        currentCard.opacity = 1
        currentCard.frame = layer.screenFrame
        layer.animate
        ...

On a side note, you are animating the original layer when I would expect it would be the copy instead. Was this your intention?

Hopefully this is enough to get you going!