Tengo una buena lista de tarjetas generadas por CSS. Contienen iconos y texto y tienen una agradable animación para expandir una vez que los toca, para revelar más iconos y opciones. Codifiqué la lista y conseguí que se viera y se comportara exactamente como yo quería.

Ahora, tengo algunos datos JSON en una base de datos y quiero usar esos datos para llenar la lista dinámicamente.

Problema : funciona muy bien, excepto las animaciones CSS, que son activadas por jQuery toggleClass () ya no se aplican.

¿Cómo puedo arreglar esto? Aquí está mi código.

HTML :

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no, minimal-ui">
    <link rel="stylesheet" href="css/customFitStyling.css" type="text/css">
    <link rel="stylesheet" href="css/w3c_v4.css" type="text/css">
    <script type="text/javascript" src="js/jquery-3.2.1.min.js"></script>
    <script type="text/javascript" src="js/customFitFunctions.js"></script>
  </head>
  <body>

    <!--APPEND CARDS-->
    <ul id="cardList" class="cards">

    </ul>
  </body>
</html>

JavaScript :

    // Sync with Firebase in real time.
    dbRef.on("value", snap =>
    {
      var workouts = snap.val();

      for (var i = 0, len = workouts.length; i < len; i++) // Populate list.
      {
        $("#cardList").append("<li><div class='card transform'>\n\
        <div class='cardInfo'><h3>" + workouts[i].title + "</h3><p>10 min.</p><a class='startIt' href='timer.html'>\n\
        <img src='images/playIcon.png' width='70' alt='' /></a><div class='infoIcons'>\n\
        <img src='images/thorso.png' width='48' alt='' /><img src='images/legs.png' width='28' alt='' />\n\
        <img src='images/cardio.png' width='48' alt='' /></div><div class='timeIcon'>\n\
        <img src='images/tenMinutes.png' width='66' alt='' /></div></div>\n\
        <div class='disappear'><div class='playIt'><a class='playButton' href='timer.html'>\n\
        <img src='images/playButtonUp.png' width='100' alt='' /><img src='images/playButtonDown.png' width='95' alt='' /></a>\n\
        </div><div class='deleteIt'><a class='deleteButton' href='#'>\n\
        <img src='images/thrashButtonUp.png' width='60' alt='' />\n\
        <img src='images/thrashButtonDown.png' width='55' alt='' /></a></div><div class='modifyIt'>\n\
        <a class='modifyButton' href='#'><img src='images/cogButtonUp.png' width='100' alt=''/>\n\
        <img src='images/cogButtonDown.png' width='95' alt='' /></a></div></div></div></li>");
      }
    });

Jquery:

  // Triggers CSS animation for cards.
  $(".card").click(function()
  {
    $(this).toggleClass("transformActive");
    $(".disappear", this).toggleClass("appear");
  });

Css:

/**
* ROUTINE CARDS SECTION
*
*/
/* Style cards and content */
.cards
{
  position: absolute;
  width: 100%;
  top: 60px;
  list-style: none;
  text-decoration: none;
  text-align: center;
  z-index: -1;
}

.cards li
{
  position: relative;
  width: 100%;
  padding-bottom: 10px;
}

.card
{
  position: relative;
  background-color: #ffffff;
  height: 150px;
  width: 100%;
  left: -6%;
  border-radius: 8px;
  box-shadow: 2px 2px 2px #686868;
}

.transform
{
  -webkit-transition: all 0.2s ease;
  -moz-transition: all 0.2s ease;
  -o-transition: all 0.2s ease;
  -ms-transition: all 0.2s ease;
  transition: all 0.2s ease;
}

.transformActive
{
  background-color: #ffffff;
  height: 260px;
  width: 100%;
  box-shadow: 6px 6px 6px #888888;
}

/* CARD CONTENT SECTION */
.cardInfo
{
  position: relative;
  margin: auto;
  width: 95%;
  height: 130px;
  text-align: left;
}

.cardInfo h3
{
  position: relative;
  top: 5px;
}

.cardInfo p
{
  position: relative;
  color: black;
  text-align: right;
  top: -40px;
}

.startIt
{
  position: absolute;
  bottom: 0px;
}

.timeIcon
{
  position: absolute;
  bottom: 0px;
  left: 78%;
}

.infoIcons
{
  position: relative;
  margin: auto;
  top: -20px;
  width: 52%;
  height: 100px;
}

.infoIcons img
{
  margin-left: 6px;
}

#holder
{
  position: relative;
  width: 100%;
  height: 80px;
}

/* CARD ANIMATION */
.disappear
{
  position: relative;
  width: 95%;
  height: 40%;
  top: 8%;
  margin: auto;
  opacity: 0;
}

.appear
{
  -webkit-animation: appearFade 1.2s ease forwards;
  -moz-animation: appearFade 1.2s ease forwards;
  -o-animation: appearFade 1.2s ease forwards;
  -ms-animation: appearFade 1.2s ease forwards;
  animation: appearFade 1.2s ease forwards;
}

@keyframes appearFade
{
  0%
  {
    opacity: 0;
  }
  100%
  {
    opacity: 1;
  }
}

/* CARD OPTIONS ICONS */
.playIt
{
  position: absolute;
  left: 0px;
}

.playButton img:last-child
{
  display: none;
}

.playButton:hover img:first-child
{
  display: none;
}

.playButton:hover img:last-child
{
  display: inline-block;
  position: relative;
  left: 3px;
  top: 3px;
}

.deleteIt
{
  position: relative;
  margin: auto;
  top: 25px;
}

.deleteButton img:last-child
{
  display: none;
}

.deleteButton:hover img:first-child
{
  display: none;
}

.deleteButton:hover img:last-child
{
  display: inline-block;
  position: relative;
  left: 2px;
  top: 2px;
}

.modifyIt
{
  position: absolute;
  right: 0px;
  top: 0px;
}

.modifyButton img:last-child
{
  display: none;
}

.modifyButton:hover img:first-child
{
  display: none;
}

.modifyButton:hover img:last-child
{
  display: inline-block;
  position: relative;
  left: 0px;
  top: 3px;
}
0
Brian 20 oct. 2017 a las 00:26

3 respuestas

La mejor respuesta

Dado que los elementos .card se agregan después de que se haya adjuntado su escucha de clics, no funcionará. El elemento debe estar presente en el momento en que vincula al oyente. Debe usar eventos delegados.

Adjunte el detector de clics a su elemento contenedor y luego use event.target como el elemento en el que hizo clic:

$('#cardList').on('click', '.card', (event) => {
  // $(event.target) is the element you clicked
  $(event.target).toggleClass('transformActive');
});
0
Austin Greco 19 oct. 2017 a las 21:46

Entonces, sospecho que el problema no es el toggleClass, sino el controlador de clics. Para que jQuery actúe sobre un elemento DOM, ese elemento debe estar presente en el momento en que el sitio complete la carga inicial.

Si está completando el contenido después de la carga utilizando JSON, no podrá actuar sobre los elementos DOM en los que reside el contenido.

Todas sus clases iniciales se están agregando en el contenido JSON, por lo que ninguna de ellas existe en la carga, jQuery no sabe nada sobre su existencia.

Sus objetivos de clic deben estar presentes en la carga para resolver su problema. Por lo tanto, no ponga elementos DOM en su JSON. Hágalos ya poblados y alimente los datos JSON en los elementos existentes. O: vincule sus eventos de clic a un elemento DOM más arriba que exista en la carga. Entonces los elementos dinámicos podrán burbujear y jQuery tendrá algo que ver.

0
Korgrue 19 oct. 2017 a las 21:34

El problema es que está agregando el controlador de clic antes de agregar los elementos, por lo que solo los elementos iniciales tienen ese evento de clic en ellos. En su lugar, puede agregar el controlador de clics a body pero filtrarlo.

$('body').on('click', '.card', function(){ ... }

De esta manera, el evento de clic está en todo el documento, pero la función no se activará a menos que haya hecho clic en una tarjeta.

0
Austin Ezell 19 oct. 2017 a las 21:33