How to animate ng-repeat items relative to click events causing the change

后端 未结 2 1761

I\'m trying to animate a user selecting items from different sets of items. The item should animate from the clicked set to it\'s new position in list of selected items.

相关标签:
2条回答
  • 2021-02-03 23:27

    if I've understood your question correctly(tell me if not); i think one way to handle the problem, goes like this:

    while assuming the size(width) of your products to be constant -set to 50px or something- ; you can set the pink elements' position to absolute; then use ng-repeat for pink elements, with a brief ng-style attribute inside the html like this:

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

    and about the purchased products: instead of using ng-repeat on the "purchased" array, inside "add-to-purchased" function, after pushing the product to the "purchased" array, you can simply animate the product to the "top: 'the height distance to the bordered element'" and "left" equal to {$scope.purchased.length*50 + 'px'}. then add a class using ng-class (with a toggle) for coloring and other css stuff... (you can also consider transition for color changes. as you probably know)

    i also think that you can handle different heights and tops problem(in case that the number of products becomes more than one line's capacity) with an ng-class which adds classes with new "top" values based on: ($index > some-number), and another ng-class for the upper element(the element that's on top of the bordered element), changing it's height ...

    i hope this was helpful


    Update:

    unfortunately i hadn't understood the question well. but looking at the problem now, i think there is a way of doing this more dynamically.

    inside the $scope.purchase function, you can message your directive with $broadcast and passing the clicked element like this (for any element in stock, either it's created with ng-repeat or not):

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

    and:

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

    and inside your directive, put the event listener:

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

    i think you can also use target.getBoundingClientRect() to get the element's position, relative to the viewport (.top , .left ,...) instead of jquery-ui's .position if you want...

    is it closer to the solution?

    0 讨论(0)
  • 2021-02-03 23:38

    This solution is an improvement in that it eliminates the need to add information to the scope in the Purchase function and it avoids mixing model data and UI details by using a "source" directive and storing origin information in a controller property. The example is simplified and can of course be improved. The key point is that the data required to manage the process is never exposed via the scope.

    If the target element is subject to being removed from the DOM (i.e it's part of an ng-repeat, then this solution would have to be modified slightly to calculate and store the animation start positions as part of the monitor.click handler rather than store the target element itself.

    The method of animation seems to me to be arbitrary. This example uses the OP's jqueryUI animation method, but it would work just as well with css transitions or using $animate.

    A full example is here

    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;
          }
        }
      };
    });
    
    0 讨论(0)
提交回复
热议问题