27 votes

Comment animer des éléments ng-repeat par rapport aux événements de clic provoquant la modification

Je suis en train d'animer un utilisateur de sélectionner les éléments à partir de différents ensembles d'éléments. L'élément doit animer à partir de l'cliqué sur installer à sa nouvelle position dans la liste des éléments sélectionnés.

Dans le dessous de démonstration, considérons les cases roses comme des éléments disponibles et le bordé de la boîte de la liste des éléments sélectionnés (boîtes bleues). L'utilisateur peut sélectionner un élément en cliquant sur l'une des cases roses:

angular.module('test', ['ngAnimate'])
  .controller('testCtrl', function($scope) {
    $scope.products = [{}, {}, {}, {}];
    $scope.purchased = [{}];
    $scope.purchase = function(dir) {
      $scope.direction = dir
      $scope.purchased.push($scope.products.pop());
    };
  })
  .directive('testDir', function($animate) {
    return {
      link: function(scope, element) {
        $animate.on('enter', element, function(element, phase) {
          $target = scope.direction == 'left' ? $('.stock:first') : $('.stock:last');
          element.position({
            my: 'center',
            at: 'center',
            of: $target,
            using: function(pos, data) {
              $(this).css(pos);
              $(this).animate({
                top: 0,
                left: 0
              });
            }
          });
        });
      }
    };
  });
.stock {
  display: inline-block;
  width: 50px;
  height: 50px;
  background: hotpink;
}
.stock.right {
  margin-left: 100px;
}
.product {
  height: 50px;
  width: 50px;
  border: 1px solid;
}
.purchased {
  height: 60px;
  margin-top: 100px;
  border: 2px dotted;
}
.purchased .product {
  display: inline-block;
  margin: 5px;
  background: dodgerblue;
}
<script src="https://code.jquery.com/jquery-2.1.3.min.js"></script>
<script src="https://code.jquery.com/ui/1.11.2/jquery-ui.js"></script>
<script src="https://code.angularjs.org/1.4.8/angular.js"></script>
<script src="https://code.angularjs.org/1.4.8/angular-animate.js"></script>
<div ng-app="test" ng-controller="testCtrl">
  <div class="stock" ng-click="purchase('left')"></div>
  <div class="stock right" ng-click="purchase('right')"></div>
  <div class="purchased clearfix">
    <div class="product" ng-repeat="product in purchased" data-test-dir>
    </div>
  </div>
</div>

Eh bien, ça fonctionne, mais je suis en utilisant jQuery ui pour trouver la position de départ (position de boîtes de rose sera variable en responsive design) et jquery animate méthode pour animer l'élément.

J'ai également de stocker les cliqué sur l'orientation dans le champ d'application et je suis à la fois la position initiale et de l'animation à la fin de la position dans l' enter écouteur d'événement.

J'ai lu et expérimenter beaucoup avec construit dans l'animation des crochets angulaires, mais ne pouvait pas trouver un bon moyen d'animer les éléments du rapport/positions dynamiques.

Est-il une meilleure façon de réaliser la même expérience utilisateur en angular js façon..?

1voto

GHB Points 136

si j'ai bien compris votre question(dites-moi si ce n'); je pense qu'une façon de gérer le problème, qui va comme ceci:

tout en assumant la taille(largeur) de vos produits afin d'être constant -set de 50px ou quelque chose - la ; vous pouvez définir la rose des éléments en position absolue; utilisez ng-repeat pour les éléments roses, avec une brève ng-attribut de style à l'intérieur de l'html comme ceci:

<div ng-repeat="item in products" ng-style="{'left': $index*50 + 'px'}" ng-click="add-to-purchased($index)"></div>

et sur les produits achetés: au lieu d'utiliser ng-repeat sur les "acquis" de tableau, à l'intérieur de "ajouter à l'acquis" de la fonction, après avoir pousser le produit vers le "acheté" tableau, vous pouvez simplement animer le produit dans le "top: 'la hauteur distance du bordé "élément" et de "gauche" égal à {$scope.acheté.longueur*50 + 'px'}. puis ajouter une classe à l'aide de ng-classe (avec un interrupteur) pour la coloration et autres css, etc... (vous pouvez aussi envisager de transition pour les changements de couleur. comme vous le savez probablement)

je pense aussi que vous pouvez gérer différentes hauteurs et les sommets de problème(dans le cas où le nombre de produits devient plus qu'une ligne de capacité) avec un ng de classe qui ajoute des classes avec de nouvelles "top" des valeurs basées sur: ($index > quelques-nombre), et un autre ng-classe de l'élément supérieur(l'élément qui est au sommet de la bordée élément), en changeant la hauteur ...

j'espère que cela vous a été utile


Mise à jour:

malheureusement, je n'avais pas compris la question. mais en regardant le problème maintenant, je pense qu'il y a un moyen de le faire de façon plus dynamique.

à l'intérieur de l' $scope.purchase fonction, vous pouvez envoyer des messages à vos directive $broadcast et en passant l'élément cliqué comme ceci (pour n'importe quel élément en stock, soit il a créé avec ng-repeat ou pas):

<div class="stock" ng-click="purchase($event)"></div>

et:

$scope.purchase = function(event) {
  $scope.purchased.push($scope.products.pop());
  $scope.$broadcast('purchaseHappened', event.target);
};

et à l'intérieur de votre directive, mettez l'écouteur d'événement:

scope.$on('purchaseHappened', function(event, target) {
     //catch target in here, and then use it's position to animate the new elements...
})

je pense que vous pouvez également utiliser target.getBoundingClientRect() pour obtenir l'élément de la position, par rapport à la fenêtre d'affichage (.top , .left ,...) au lieu de jquery-ui .position si vous voulez...

est-il plus proche de la solution?

0voto

Joe Enzminger Points 2532

Cette solution est une amélioration en ce qu'il élimine le besoin d'ajouter de l'information à la portée de la fonction d'Achat et il permet d'éviter de mélanger les données du modèle et les détails de l'INTERFACE utilisateur en utilisant une "source" de la directive et le stockage des informations d'origine dans un contrôleur de la propriété. L'exemple est simplifié et peuvent bien sûr être améliorée. Le point clé est que les données nécessaires pour gérer le processus n'est jamais exposée via la portée.

Si l'élément cible est sous réserve d'être retiré de la DOM (j'.e il fait partie d'une ng-repeat, puis cette solution devrait être légèrement modifié pour calculer et stocker l'animation de démarrage des positions en tant que partie de l'écran.cliquez sur gestionnaire plutôt que de stocker l'élément cible elle-même.

La méthode de l'animation me semble être arbitraire. Cet exemple utilise l'OP jqueryUI animation de la méthode, mais il fonctionne tout aussi bien avec les transitions css ou à l'aide de $animer.

Un exemple complet est ici

angular.module('app', [])
.controller('main', function($scope) {
  $scope.products = [{},{}];
  $scope.purchased = [{}];
  $scope.Purchase = function() {
    $scope.purchased.push({});
  };
})
.directive('source', function(){
  return {
    controller: function($scope) {
    }
  };
})
.directive('originator', function(){
  return{
    require: '^source',
    priority: 1,
    link:{
      pre: function(scope, element, attr, ctrl){
        element.on('click', function(evt){
          ctrl.target = evt.target;    
        });
      } 
    }
  };
})
.directive('sink', function(){
  return {
    require: '^source',
    link: function(scope, element, attr, ctrl){
      var target = ctrl.target;
      if(target){
        var $target = $(target);
        //animate from target to current position
        element.position({
            my: 'center',
            at: 'center',
            of: $target,
            using: function(pos, data) {
              $(this).css(pos);
              $(this).animate({
                top: 0,
                left: 0
              });
            }
          });
        ctrl.target = undefined;
      }
    }
  };
});

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X