Binding clicks to dynamic symbols in Adobe Edge

This one took me, frankly, far too long to work out and I just couldn’t find the solution online so I am posting it here for your and my reference!

The Scenario

I want to dynamically add 10 child symbols to the stage and be able to click them and evaluate their ID so I know who they are (and then do stuff with them).

Sounds pretty simple right? Well you’d think so (and now I know how to do it, it is!) but Edge has its own quirks, syntax and structure that we have to deal with and, couple that with poor jQuery/JS debugging, getting to the solution was a bit painful.

The Solution

First of all create an array to store references to all the menu items you’re going to create.

Draw a rectangle for your menu item and convert it to a symbol called “menuItem” – you don’t need to add it to the stage because we’re just going to pull it from the library and add 10 items directly to the stage.

In the compositionReady panel paste this:

//the array that will hold references to your new symbols.
imageSymbolArray = [];
//a function to call to make sure we know it’s working!
function traceSelected (symbolInTheArray){
 alert("You clicked a menuItem with the id of: "+symbolInTheArray.getVariable("id"));
}
for (var i = 0; i < 10; i++){
 // Create an instance element of a symbol as a child of the
 // given parent element
 var mySymbolObject = sym.createChildSymbol("menuItem", "Stage");
 //set the value of a Symbol variable
 mySymbolObject.setVariable("id", i);
 //push it into the array
 imageSymbolArray.push(mySymbolObject);
}
//a 'for each' loop through the newly populated array.
$.each(imageSymbolArray, function( count, symbolInTheArray ){
 //create jQuery reference to the item - not really needed here but shows how to do it.
 var menuItem = $(symbolInTheArray);
 //create a jQuery reference to the DIV element inside the symbol.
 var menuElement = $(symbolInTheArray.getSymbolElement());
 //now you can bind interactivity to the menu items' DIVs
 menuElement.bind ("click",function(){traceSelected(symbolInTheArray);});
 menuElement.bind ("mouseover",function(){menuElement.animate({opacity: 0.2, left:"-=25px"});});
 menuElement.bind ("mouseout",function(){menuElement.animate({opacity: 1, left:"+=25px"});});
}
)
 

And that’s it! Now when you click an item it should create a JS alert to say ‘You clicked a menuItem with the id of: 4’.

I hope this is of some use to you – feel free to ask questions in the comments.

Click here to view the demo

Click here to download the Edge project

Update 10-11-2014 – There are some awful bugs in the Edge Animate CC release 2014.1, one of which is that it sets some symbol elements’ ‘position’ to ‘absolute’. So please add this line into your code:


menuElement.css({'position':'relative'});

36 thoughts on “Binding clicks to dynamic symbols in Adobe Edge

      1. Hi Chris,
        I’d love an Edge file please, I can’t seem to get the code to work. I’m probably doing something dumb but I’ve only been using Edge for a few weeks and its still very new.
        Many Thanks
        Ben

  1. Hey Ben,

    The reason why this example wasn’t working is that WordPress had mucked around with the formatting and put a line of code onto a commented out line.

    I’ve sorted it and it should work now if you follow the instructions – I’ve simplified it so you only need to create one ‘menuItem’ symbol – no longer a need for a ‘holder’ symbol as this example now adds the items directly to the stage.

    Let me know how you get on. If you’re still having problems I’ll fire over the Edge project.

    1. Hi Chris, I now get the symbols lined up vertically on the stage but don’t get any interaction with them on mouseover etc, could you please send me an Edge file?

      This will sound like a stupid question but where can I view the output from the function traceSelected (symbolInTheArray){
      alert(“You clicked a menuItem with the id of: “+symbolInTheArray.getVariable(“id”));
      }

      I’m trying to migrate from Flash and had an output panel previously

      Thanks again
      Ben

    1. Chris, thank you for your help, I was being an idiot and filling in the array with symbol names rather than leaving it blank.
      It works beautifully, now I’ve just got to figure out how to tailor it to fit my project and make the button stay faded out when clicked

      Many Thanks
      Ben

  2. Hi Chris, I was searching for hours today and when I found your code I thought I’d be able to convert it quite easily but I was sorely mistaken, I’m not even close to that level yet.
    What I’m trying to create in Edge is the same menu I used in Flash that works like this http://www.baselinehost.com/menuExample/menu.html
    None of the buttons are dynamically placed on the stage so I can move them around easily.
    Could you point me in the right direction please? I can’t find a tutorial that will show me how to make the buttons stay in a mouseover state when clicked and I need to use an array as sometimes I have 10+ buttons
    Tell me to stop hassling you and I’ll understand but a leg up would be much appreciated if you have time
    Ben

    1. That’s perfect! Well almost, how can I bypass the part where the buttons get added to the stage and add them manually in various locations?
      That’s the last question I promise

  3. Add the buttons to your stage and call them ‘menuItem0’, ‘menuItem1’, ‘menuItem2’ etc.

    Now replace the line in the for..loop:

    var mySymbolObject = sym.createChildSymbol(“menuItem”, “Stage”);

    for this line:

    var mySymbolObject = sym.getSymbol(“menuItem” +i);

    Make sure you add the same number of menuItems as the for..loop’s maximum loop value (in this instance it’s 10).

    1. You’re a star, thank you so much for your help
      Even the code to tween without the timeline is priceless!
      Hope you blog some more enlightening code soon

      1. Glad it’s helped you – check out my other demos with source too. Lots of (hopefully helpful) goodies!

    1. @Lucid It’s a pleasure! It can be quite a trauma learning new stuff with new syntax, especially if you come from a different coding background. Glad it helped.

  4. Hi Chris,
    I’ve discovered this fantastic blog yesterday… I’m studying your tutorials. Sorry for my very bad english…
    Can you tell me something about symbolInTheArray.
    Is this a property of the array? is this a property of jQuery language ?

    Thank’s

    Regards

    Alessandro

    1. Hi Alessandro,

      Glad you’re finding the blog useful.

      The variable name ‘symbolInTheArray’ is not a jQuery reserved name. It’s simply a reference to a symbol in the array. I named it like that so that it was easier to understand what was going on 🙂

  5. Hello, I would like to know how to place dynamic text on each item. I tried to put it here using:

    for (var i = 0; i < 10; i++){
    // Create an instance element of a symbol as a child of the
    // given parent element
    var mySymbolObject = sym.createChildSymbol("menuItem", "Stage");

    / / ************* Place text inside the item ***************
    var texto = mySymbolObject.createChildSymbol("texto", "Stage")
    texto.$("text").html("Item "+ i);
    / / ************************************************ **************

    //set the value of a Symbol variable
    mySymbolObject.setVariable("id", i);
    //push it into the array
    imageSymbolArray.push(mySymbolObject);
    }

    But I find a problem when mouse over in the item. Could you help me?

  6. @alinegoncalvesf,

    I’m assuming you have a text field inside your ‘texto’ symbol object called ‘text’ – is that right?

    What code are you using on mouse over?

  7. Hey Chris! Thanks for the code.
    I was developing a similar thing from scratch and couldn’t quite get there because I didn’t know how to set an ID in edge. ( mySymbolObject.setVariable(“id”, i); )

    I have a problem that the menu items seem to move back and forth even though my mouse is hovering over the menu item.
    I got rid of the part of the function that changes the position and it still changes back and forth several times with the opacity.

    Any ideas?

  8. FINALLY! Thanks so much. I am an AS3 guy diving into edge and there are a few things that have been slipping past me and this was a big one. Much appreciated.

  9. Nowadays I tend to avoid EA’s setVariable and use an object in the jQuery bind like this:

    myBtn.bind('click', {id:i}, onClick);

    function onClick (e) {
    var passedId = e.data.id;
    //passedId is the value of i
    };

    Or maybe even use jQuery’s built-in data(); attribute like this:

    myBtn.data({id:i});

    //..somewhere later evaluate it

    console.log(myBtn.data().id); // logs out the value of i

    Check out this discussion on StackOverflow about their differences

    http://stackoverflow.com/questions/3247917/jquery-data-vs-eventdata

    http://api.jquery.com/data/

    Cool eh?

  10. …got a question bud, a bit unrelated. May even stomp you 🙂

    Dynamically creating a symbol…
    sym.createChildSymbol(“box”, “Stage”);

    Creates two grouped divs with wierd id’s…
    id=”eid_1409920391497″ >> id=”eid_1409920391497_box”

    Why is it so?

    More importantly, I would like to able to remove the the symbol at some point, but cant since it is not named “box”
    sym.getComposition().getStage().getSymbol(“box”).deleteSymbol();

    Any workarounds? Like say maybe getting the weird name edge created as the id?

    1. Simply assign a variable to your createChildSymbol() call.

      So:

      myBox = sym.createChildSymbol(“box”, $('#Stage'));

      …later

      myBox.deleteSymbol();

      1. ah. so here is the thing. Your idea works.
        But I need to specifically reference or know that weird Id it generates or tell edge to stick to my naming convention.

        To explain what im doing:

        so im adding html in a text element like below
        sym.$(“plcholder”).html(”)

        But I cant get it to animate. for two reasons I found.
        One: Edge on a normal element created in the application will render with a prefix in this case “Stage_” cause the text is on the stage. which will now look like this.

        Two: even if I hardcode the sym.$(“plcholder”).html id to …… edge still when compiled still wont know that its an element it can talk too.

        So…. to correct ( and maybe im over-correcting) …. i decided to first make a symbol named box, using the application, so that it registers…. then delete said symbol (cause I dont need it)……. then draw up the code sym.$(“plcholder”).html(”)

        —————-

        //with box already created using the GUI. copy/patse in Stage compositionReady
        //
        sym.getComposition().getStage().getSymbol(“box”).deleteSymbol();
        sym.$(“plcholder”).html(”)
        sym.getComposition().getStage().$(“box”).animate({opacity: 1, left:”+=400px”});

        //This works.
        —————-

        So now im trying to repeat the steps, but this time without using the GUI, but call in (at least the box for now) dynamically, with my specific id’s.

        Sorry for the long explanation though.

      2. Why not just use jQuery using .attr(); to append your own id to the one EA gives it? Or maybe assign a class instead? Or cache your elements in an array?

        The possibilities are many, if I understand you correctly.

      3. var box = sym.createChildSymbol(“box”, “Stage”);
        box.getSymbolElement().attr(‘id’,’newID’);

        Thank you sir. Owe you a beer. Cheers.

      4. Hey Chris…
        I got various ways to get attr() to work. However this one stomps me…. It’s just the last line. The path is not correct. Can you glance at it for me see what I’m missing.

        sym.setVariable(“box”, sym.createChildSymbol(‘box’,’Stage’)) ;
        sym.getVariable(“box”).getSymbolElement().attr(‘id’,”newId”);
        var boxId = sym.getVariable(“box”).getSymbolElement().attr(‘id’);

        //bottom not firing
        sym.getVariable(“box”).$(boxId).animate({opacity: 1, left:”+=400px”});

  11. Hi Chris,

    Thank you for giving us some of knowledge.

    I’d like to ask you how is possible to take data from JSON file instead of the created array as in your example?

    1. You can do it in pure JS like this:


      function loadJSON(){
      //new XMLHttpRequest
      var xhr = new XMLHttpRequest();
      //assign its onreadystatechange event handler to anonymous function
      xhr.onreadystatechange = function(){
      //4 means request finished and response is ready
      if(xhr.readyState === 4 ){
      //200 means 'OK' - 404 means page not found
      if(xhr.status === 200){
      //responseText is the built-in result string
      //ref to the the parsed JSON object
      jsonData = JSON.parse(xhr.responseText);
      //do stuff here
      } else {
      alert('JSON loading error');
      }
      }
      };
      //open an aysnchronous stream to the file
      xhr.open("GET", jsonPath, true);
      //send the arguments to the XMLHttpRequest instance (basically it loads it)
      xhr.send();
      };

      Or jQuery like this:


      function loadJSON(){
      $.ajax({
      dataType: "json",
      url: 'data.json',
      success: function(data){
      jsonData = data;
      //do stuff here
      },
      error:function(e){
      alert('JSON load error')
      }
      });
      };

  12. Thank you for the reply Chris.

    It seems that jQuery would be easier but i’ll see it in the action. 🙂

    I wish all the best!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s