如何仅使用角度指令将元素拖放到日历上 [英] How to drag&drop elements onto a calendar with angular directives only

查看:27
本文介绍了如何仅使用角度指令将元素拖放到日历上的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用角度指令实现拖放日历.日历使用 ui-calendar (https://github.com/angular-ui/ui-calendar),Arshaw FullCalendar 的完整 AngularJS 指令.

将元素拖放到日历上由 angular-dragdrop (https://github.com/codef0rmer/angular-dragdrop).

这是文件夹 demo/ui-calendar/demo 中的 我的尝试,但没有事件当我将一个元素放到日历上时曾经被触发...

html 简单如下:

 <头><style type="text/css">@charset "UTF-8";[ng\:cloak],[ng-cloak],[data-ng-cloak],[x-ng-cloak],.ng-cloak,.x-ng-cloak,.ng-hide{display:none !important;}ng\:form{display:block;}.ng-animate-block-transitions{transition:0s all!important;-webkit-transition:0s all!important;}</style><link rel="stylesheet" href="bootstrap.css"><link rel="stylesheet" href="fullcalendar.css"><link rel="stylesheet" href="calendarDemo.css"><script src="jquery.js"></script><script src="jquery-ui.js"></script><script src="angular.js"></script><script src="https://angular-ui.github.io/bootstrap/ui-bootstrap-tpls-0.9.0.js"></script><script src="fullcalendar.js"></script><script src="calendar.js"></script><脚本>$.fn.ngattr = 函数(名称,值){var element = angular.element(this).get(0);返回 element.getAttribute(name) ||element.getAttribute('data-' + name);};<身体><div ng-controller="dragdropController"><ul><li class="btn btn-primary"ng-repeat='item in list1'ng-show="item.title"数据拖动=真"data-jqyoui-options="{revert: 'invalid', helper: 'clone'}"ng-model="list1"jqyoui-draggable="{index: {{$index}}, animate: true, placeholder: 'keep'}">{{item.title}}</li><div class="alert-success calAlert" ng-show="alertMessage != undefined && alertMessage != ''"><h4>{{alertMessage}}</h4>

<div ng-controller="CalendarCtrl" select="renderCalender(myCalendar1);"><div class="btn-toolbar"><div class="btn-group"><button type="button" class="btn btn-primary" ng-click="addEvent()">添加事件</button>

<div data-drop="true"jqyoui-droppable="{multiple:true}"id=日历"类=日历"ng-model="事件源"日历=我的日历1"config="uiConfig.calendar"ui-calendar="uiConfig.calendar">

</html>

为了简单起见,我将所有指令、控制器和服务合并到以下 js 文件中:

function CalendarCtrl($scope) {/* 包含作用域上的自定义事件的事件源 */$scope.events = [{title: '全天活动',start: new Date()}];/* 添加自定义事件*/$scope.addEvent = function() {$scope.events.push({title: '芝麻开门',开始:新日期(),班级名称:['openSesame']});};$scope.drop = function(date, allDay){$scope.alertMessage = ('Event Droped on ' + date);};/* 配置对象 */$scope.uiConfig = {日历:{高度:450,可真实,标题:{左:'标题',中央: '',右:'今天上一个,下一个'},丢弃:$scope.drop}};/* 事件源数组*/$scope.eventSources = [$scope.events];}angular.module('calendarDemoApp', []).constant('uiCalendarConfig', {}).controller('dragdropController', ['$scope','$timeout', function($scope, $timeout) {var addEvent = 函数(标题,长度){长度 = 长度.长度 == 0 ?0":长度;标题 = 标题.长度 == 0 ?无标题事件("+长度+分钟)":标题+("+长度+分钟)";$scope.list1.push({'title': title, 'length': length});}$('#event_add').unbind('click').click(function () {var title = $('#event_title').val();var length = $('#event_length').val();添加事件(标题,长度);});$scope.list1 = [{title: '全面检查', 长度: '25'},{title: '美白', 长度: '90'},{标题:'填充',长度:'30'}];}]).controller('uiCalendarCtrl', ['$scope', '$timeout', function($scope, $timeout){var sourceSerialId = 1,eventSerialId = 1,来源 = $scope.eventSources,extraEventSignature = $scope.calendarWatchEvent ?$scope.calendarWatchEvent : angular.noop,wrapFunctionWithScopeApply = 函数(functionToWrap){var 包装器;如果(functionToWrap){包装器 = 函数(){//这发生在 angular 上下文之外,因此我们需要将其包装在具有隐含应用的超时中.//这样,函数将在下一个摘要中安全执行.var args = 参数;$超时(功能(){functionToWrap.apply(this, args);});};}返回包装器;};this.eventsFingerprint = function(e) {如果(!e.__uiCalId){e.__uiCalId = eventSerialId++;}//这会从事件中提取我们需要的所有信息.http://jsperf.com/angular-calendar-events-fingerprint/3return "" + e.__uiCalId + (e.id || '') + (e.title || '') + (e.url || '') + (+e.start || '') + (+e.end || '') +(e.allDay || '') + (e.className || '') + extraEventSignature(e) ||'';};this.sourcesFingerprint = 函数(源){返回源.__id ||(source.__id = sourceSerialId++);};this.allEvents = function() {//返回 sources.flatten();但我们没有flattenvar arraySources = [];for (var i = 0, srcLen = sources.length; i < srcLen; i++) {var 源 = 源 [i];如果(angular.isArray(源)){//事件源作为数组arraySources.push(source);} else if(angular.isObject(source) && angular.isArray(source.events)){//事件源为对象,即扩展形式var extEvent = {};for(源代码中的var键){if(key !== '_uiCalId' && key !== 'events'){extEvent[key] = source[key];}}for(var eI = 0;eI < source.events.length;eI++){angular.extend(source.events[eI],extEvent);}arraySources.push(source.events);}}返回 Array.prototype.concat.apply([], arraySources);};//通过为每个元素分配 id 标记并观察这些标记的变化范围来跟踪数组中的变化//参数://arraySource 函数数组,返回要观察的对象数组//tokenFn 函数(对象),返回给定对象的令牌this.changeWatcher = function(arraySource, tokenFn) {变量自我;var getTokens = function() {var 数组 = angular.isFunction(arraySource) ?数组源():数组源;var 结果 = [], token, el;for (var i = 0, n = array.length; i [6]varsubtractAsSets = function(a, b) {var 结果 = [], inB = {}, i, n;for (i = 0, n = b.length; i 

解决方案

还没有使用 angular-dragdrop,但文档说配置对象应该包含一个 onDrop 属性.尝试将 jqyoui-droppable="{multiple:true}" 替换为 jqyoui-droppable="{multiple:true, onDrop: 'drop'}".angular-dragdrop 似乎期望 onDrop 是一个字符串,其中包含作用域上的函数名称.

I am trying to implement a drag&drop calendar with angular directives. The calendar uses the ui-calendar (https://github.com/angular-ui/ui-calendar), a complete AngularJS directive for the Arshaw FullCalendar.

The drag&drop of the element onto the calendar is powered by angular-dragdrop (https://github.com/codef0rmer/angular-dragdrop).

Here is my try in the folder demo/ui-calendar/demo , but no event is ever fired when i drop an element onto the calendar...

The html is as simple as following:

    <html lang="en" ng-app="calendarDemoApp" id="top" class="ng-scope">
<head>
    <style type="text/css">@charset "UTF-8";[ng\:cloak],[ng-cloak],[data-ng-cloak],[x-ng-cloak],.ng-cloak,.x-ng-cloak,.ng-hide{display:none !important;}ng\:form{display:block;}.ng-animate-block-transitions{transition:0s all!important;-webkit-transition:0s all!important;}</style>
    <link rel="stylesheet" href="bootstrap.css">
    <link rel="stylesheet" href="fullcalendar.css">
    <link rel="stylesheet" href="calendarDemo.css">

    <script src="jquery.js"></script>
    <script src="jquery-ui.js"></script>
    <script src="angular.js"></script>
    <script src="https://angular-ui.github.io/bootstrap/ui-bootstrap-tpls-0.9.0.js"></script>
    <script src="fullcalendar.js"></script>
    <script src="calendar.js"></script>

    <script>
      $.fn.ngattr = function(name, value) {
        var element = angular.element(this).get(0);
        return element.getAttribute(name) || element.getAttribute('data-' + name);
      };
    </script>

</head>
    <body>
        <div ng-controller="dragdropController">

            <ul>
                <li class="btn btn-primary" 
                    ng-repeat='item in list1' 
                    ng-show="item.title" 
                    data-drag="true" 
                    data-jqyoui-options="{revert: 'invalid', helper: 'clone'}" 
                    ng-model="list1" 
                    jqyoui-draggable="{index: {{$index}}, animate: true, placeholder: 'keep'}">{{item.title}}</li>
            </ul>

            <div class="alert-success calAlert" ng-show="alertMessage != undefined && alertMessage != ''">
            <h4>{{alertMessage}}</h4>
            </div>

            <div ng-controller="CalendarCtrl" select="renderCalender(myCalendar1);">
                <div class="btn-toolbar">
                    <div class="btn-group">
                        <button type="button" class="btn btn-primary" ng-click="addEvent()">Add Event</button>
                    </div>
                </div>
                <div data-drop="true"
                     jqyoui-droppable="{multiple:true}" 
                     id="calendar" 
                     class="calendar" 
                     ng-model="eventSources" 
                     calendar="myCalendar1" 
                     config="uiConfig.calendar"
                     ui-calendar="uiConfig.calendar">
                </div>
            </div>

        </div>
    </body>
</html>

I merged all the directives, controlers and service in the following js file for the sake of simplicity:

function CalendarCtrl($scope) {
    /* event source that contains custom events on the scope */
    $scope.events = [
      {title: 'All Day Event',start: new Date()}
    ];

    /* add custom event*/
    $scope.addEvent = function() {
      $scope.events.push({
        title: 'Open Sesame',
        start: new Date(),
        className: ['openSesame']
      });
    };

   $scope.drop = function(date, allDay){
        $scope.alertMessage = ('Event Droped on ' + date);
    };

    /* config object */
    $scope.uiConfig = {
      calendar:{
        height: 450,
        editable: true,
        header:{
          left: 'title',
          center: '',
          right: 'today prev,next'
        },
        drop: $scope.drop
      }
    };
    /* event sources array*/
    $scope.eventSources = [$scope.events];

}

angular.module('calendarDemoApp', [])

.constant('uiCalendarConfig', {})

.controller('dragdropController', ['$scope','$timeout', function($scope, $timeout) {
    var addEvent = function (title, length) {
        length = length.length == 0 ? "0" : length;
        title = title.length == 0 ? "Untitled Event (" + length + " min)" : title + " (" + length + " min)";
        $scope.list1.push({'title': title, 'length': length});

    }

    $('#event_add').unbind('click').click(function () {
        var title = $('#event_title').val();
        var length = $('#event_length').val();
        addEvent(title, length);
    });

    $scope.list1 = [
        {title: 'Full check up', length: '25'},
        {title: 'Whitening', length: '90'},
        {title: 'Filling', length: '30'}];
}])

.controller('uiCalendarCtrl', ['$scope', '$timeout', function($scope, $timeout){

      var sourceSerialId = 1,
          eventSerialId = 1,
          sources = $scope.eventSources,
          extraEventSignature = $scope.calendarWatchEvent ? $scope.calendarWatchEvent : angular.noop,

          wrapFunctionWithScopeApply = function(functionToWrap){
              var wrapper;

              if (functionToWrap){
                  wrapper = function(){
                      // This happens outside of angular context so we need to wrap it in a timeout which has an implied apply.
                      // In this way the function will be safely executed on the next digest.

                      var args = arguments;
                      $timeout(function(){
                          functionToWrap.apply(this, args);
                      });
                  };
              }

              return wrapper;
          };

      this.eventsFingerprint = function(e) {
        if (!e.__uiCalId) {
          e.__uiCalId = eventSerialId++;
        }
        // This extracts all the information we need from the event. http://jsperf.com/angular-calendar-events-fingerprint/3
        return "" + e.__uiCalId + (e.id || '') + (e.title || '') + (e.url || '') + (+e.start || '') + (+e.end || '') +
          (e.allDay || '') + (e.className || '') + extraEventSignature(e) || '';
      };

      this.sourcesFingerprint = function(source) {
          return source.__id || (source.__id = sourceSerialId++);
      };

      this.allEvents = function() {
        // return sources.flatten(); but we don't have flatten
        var arraySources = [];
        for (var i = 0, srcLen = sources.length; i < srcLen; i++) {
          var source = sources[i];
          if (angular.isArray(source)) {
            // event source as array
            arraySources.push(source);
          } else if(angular.isObject(source) && angular.isArray(source.events)){
            // event source as object, ie extended form
            var extEvent = {};
            for(var key in source){
              if(key !== '_uiCalId' && key !== 'events'){
                 extEvent[key] = source[key];
              }
            }
            for(var eI = 0;eI < source.events.length;eI++){
              angular.extend(source.events[eI],extEvent);
            }
            arraySources.push(source.events);
          }
        }

        return Array.prototype.concat.apply([], arraySources);
      };

      // Track changes in array by assigning id tokens to each element and watching the scope for changes in those tokens
      // arguments:
      //  arraySource array of function that returns array of objects to watch
      //  tokenFn function(object) that returns the token for a given object
      this.changeWatcher = function(arraySource, tokenFn) {
        var self;
        var getTokens = function() {
          var array = angular.isFunction(arraySource) ? arraySource() : arraySource;
          var result = [], token, el;
          for (var i = 0, n = array.length; i < n; i++) {
            el = array[i];
            token = tokenFn(el);
            map[token] = el;
            result.push(token);
          }
          return result;
        };
        // returns elements in that are in a but not in b
        // subtractAsSets([4, 5, 6], [4, 5, 7]) => [6]
        var subtractAsSets = function(a, b) {
          var result = [], inB = {}, i, n;
          for (i = 0, n = b.length; i < n; i++) {
            inB[b[i]] = true;
          }
          for (i = 0, n = a.length; i < n; i++) {
            if (!inB[a[i]]) {
              result.push(a[i]);
            }
          }
          return result;
        };

        // Map objects to tokens and vice-versa
        var map = {};

        var applyChanges = function(newTokens, oldTokens) {
          var i, n, el, token;
          var replacedTokens = {};
          var removedTokens = subtractAsSets(oldTokens, newTokens);
          for (i = 0, n = removedTokens.length; i < n; i++) {
            var removedToken = removedTokens[i];
            el = map[removedToken];
            delete map[removedToken];
            var newToken = tokenFn(el);
            // if the element wasn't removed but simply got a new token, its old token will be different from the current one
            if (newToken === removedToken) {
              self.onRemoved(el);
            } else {
              replacedTokens[newToken] = removedToken;
              self.onChanged(el);
            }
          }

          var addedTokens = subtractAsSets(newTokens, oldTokens);
          for (i = 0, n = addedTokens.length; i < n; i++) {
            token = addedTokens[i];
            el = map[token];
            if (!replacedTokens[token]) {
              self.onAdded(el);
            }
          }
        };
        return self = {
          subscribe: function(scope, onChanged) {
            scope.$watch(getTokens, function(newTokens, oldTokens) {
              if (!onChanged || onChanged(newTokens, oldTokens) !== false) {
                applyChanges(newTokens, oldTokens);
              }
            }, true);
          },
          onAdded: angular.noop,
          onChanged: angular.noop,
          onRemoved: angular.noop
        };
      };

      this.getFullCalendarConfig = function(calendarSettings, uiCalendarConfig){
          var config = {};

          angular.extend(config, uiCalendarConfig);
          angular.extend(config, calendarSettings);

          angular.forEach(config, function(value,key){
            if (typeof value === 'function'){
              config[key] = wrapFunctionWithScopeApply(config[key]);
            }
          });

          return config;
      };
  }])

.directive('jqyouiDraggable', ['ngDragDropService', function(ngDragDropService) {
    return {
      require: '?jqyouiDroppable',
      restrict: 'A',
      link: function(scope, element, attrs) {
        var dragSettings, jqyouiOptions, zIndex;
        var updateDraggable = function(newValue, oldValue) {
          if (newValue) {
            dragSettings = scope.$eval(element.attr('jqyoui-draggable') || element.attr('data-jqyoui-draggable')) || {};
            jqyouiOptions = scope.$eval(attrs.jqyouiOptions) || {};
            element
              .draggable({disabled: false})
              .draggable(jqyouiOptions)
              .draggable({
                start: function(event, ui) {
                  zIndex = angular.element(jqyouiOptions.helper ? ui.helper : this).css('z-index');
                  angular.element(jqyouiOptions.helper ? ui.helper : this).css('z-index', 9999);
                  angular.startXY = angular.element(this).offset();
                  ngDragDropService.callEventCallback(scope, dragSettings.onStart, event, ui);
                },
                stop: function(event, ui) {
                  angular.element(jqyouiOptions.helper ? ui.helper : this).css('z-index', zIndex);
                  ngDragDropService.callEventCallback(scope, dragSettings.onStop, event, ui);
                },
                drag: function(event, ui) {
                  ngDragDropService.callEventCallback(scope, dragSettings.onDrag, event, ui);
                }
              });
          } else {
            element.draggable({disabled: true});
          }
        };
        scope.$watch(function() { return scope.$eval(attrs.drag); }, updateDraggable);
        updateDraggable();

        element.on('$destroy', function() {
          element.draggable('destroy');
        });
      }
    };
  }])

.directive('jqyouiDroppable', ['ngDragDropService', function(ngDragDropService) {
    return {
      restrict: 'A',
      priority: 1,
      link: function(scope, element, attrs) {
        var dropSettings;
        var updateDroppable = function(newValue, oldValue) {
          if (newValue) {
            dropSettings = scope.$eval(angular.element(element).attr('jqyoui-droppable') || angular.element(element).attr('data-jqyoui-droppable')) || {};
            element
              .droppable({disabled: false})
              .droppable(scope.$eval(attrs.jqyouiOptions) || {})
              .droppable({
                over: function(event, ui) {
                  ngDragDropService.callEventCallback(scope, dropSettings.onOver, event, ui);
                },
                out: function(event, ui) {
                  ngDragDropService.callEventCallback(scope, dropSettings.onOut, event, ui);
                },
                drop: function(event, ui) {
                  if (angular.element(ui.draggable).ngattr('ng-model') && attrs.ngModel) {
                    ngDragDropService.invokeDrop(scope, angular.element(ui.draggable), angular.element(this), event, ui);
                  } else {
                    ngDragDropService.callEventCallback(scope, dropSettings.onDrop, event, ui);
                  }
                }
              });
          } else {
            element.droppable({disabled: true});
          }
        };

        scope.$watch(function() { return scope.$eval(attrs.drop); }, updateDroppable);
        updateDroppable();

        element.on('$destroy', function() {
          element.droppable('destroy');
        });
      }
    };
  }])

.directive('uiCalendar', ['uiCalendarConfig', '$locale', function(uiCalendarConfig, $locale) {
    return {
        restrict: 'A',
        scope: {eventSources:'=ngModel',calendarWatchEvent: '&'},
        controller: 'uiCalendarCtrl',
        link: function(scope, elm, attrs, controller) {

            var sources = scope.eventSources,
                sourcesChanged = false,
                eventSourcesWatcher = controller.changeWatcher(sources, controller.sourcesFingerprint),
                eventsWatcher = controller.changeWatcher(controller.allEvents, controller.eventsFingerprint),
                options = null;

            function getOptions(){
                var calendarSettings = attrs.uiCalendar ? scope.$parent.$eval(attrs.uiCalendar) : {},
                fullCalendarConfig;
                fullCalendarConfig = controller.getFullCalendarConfig(calendarSettings, uiCalendarConfig);

                options = { eventSources: sources };
                angular.extend(options, fullCalendarConfig);

                var options2 = {};
                for(var o in options){
                    if(o !== 'eventSources'){
                      options2[o] = options[o];
                    }
                }
                return JSON.stringify(options2);
            }

            scope.destroy = function(){
              if(attrs.calendar) {
                scope.calendar = scope.$parent[attrs.calendar] =  elm.html('');
              } else {
                scope.calendar = elm.html('');
              }
            };

            scope.init = function(){
              scope.calendar.fullCalendar(options);
            };

            eventSourcesWatcher.onAdded = function(source) {
              scope.calendar.fullCalendar('addEventSource', source);
              sourcesChanged = true;
            };

            eventSourcesWatcher.onRemoved = function(source) {
              scope.calendar.fullCalendar('removeEventSource', source);
              sourcesChanged = true;
            };

            eventsWatcher.onAdded = function(event) {
              scope.calendar.fullCalendar('renderEvent', event, true);
            };

            eventsWatcher.onRemoved = function(event) {
              scope.calendar.fullCalendar('removeEvents', function(e) { return e === event; });
            };

            eventsWatcher.onChanged = function(event) {
              scope.calendar.fullCalendar('updateEvent', event);
            };

            eventSourcesWatcher.subscribe(scope);
            eventsWatcher.subscribe(scope, function(newTokens, oldTokens) {
              if (sourcesChanged === true) {
                sourcesChanged = false;
                // prevent incremental updates in this case
                return false;
              }
            });

            scope.$watch(getOptions, function(newO,oldO){
                scope.destroy();
                scope.init();
            });
      }
    };
}])

.service('ngDragDropService', ['$timeout', '$parse', function($timeout, $parse) {
    this.callEventCallback = function (scope, callbackName, event, ui) {
      if (!callbackName) return;

      var objExtract = extract(callbackName),
          callback = objExtract.callback,
          constructor = objExtract.constructor,
          args = [event, ui].concat(objExtract.args);

      // call either $scoped method i.e. $scope.dropCallback or constructor's method i.e. this.dropCallback
      scope.$apply((scope[callback] || scope[constructor][callback]).apply(scope, args));

      function extract(callbackName) {
        var atStartBracket = callbackName.indexOf('(') !== -1 ? callbackName.indexOf('(') : callbackName.length,
            atEndBracket = callbackName.lastIndexOf(')') !== -1 ? callbackName.lastIndexOf(')') : callbackName.length,
            args = callbackName.substring(atStartBracket + 1, atEndBracket), // matching function arguments inside brackets
            constructor = callbackName.match(/^[^.]+.\s*/)[0].slice(0, -1); // matching a string upto a dot to check ctrl as syntax
            constructor = scope[constructor] && typeof scope[constructor].constructor === 'function' ? constructor : null;

        return {
          callback: callbackName.substring(constructor && constructor.length + 1 || 0, atStartBracket),
          args: (args && args.split(',') || []).map(function(item) { return $parse(item)(scope); }),
          constructor: constructor
        }
      }
    };

    this.invokeDrop = function (scope, $draggable, $droppable, event, ui) {
      var dragModel = '',
        dropModel = '',
        dragSettings = {},
        dropSettings = {},
        jqyoui_pos = null,
        dragItem = {},
        dropItem = {},
        dragModelValue,
        dropModelValue,
        $droppableDraggable = null,
        droppableScope = $droppable.scope(),
        draggableScope = $draggable.scope();

      dragModel = $draggable.ngattr('ng-model');
      dropModel = $droppable.ngattr('ng-model');
      dragModelValue = draggableScope.$eval(dragModel);
      dropModelValue = droppableScope.$eval(dropModel);

      $droppableDraggable = $droppable.find('[jqyoui-draggable]:last,[data-jqyoui-draggable]:last');
      dropSettings = droppableScope.$eval($droppable.attr('jqyoui-droppable') || $droppable.attr('data-jqyoui-droppable')) || [];
      dragSettings = draggableScope.$eval($draggable.attr('jqyoui-draggable') || $draggable.attr('data-jqyoui-draggable')) || [];

      // Helps pick up the right item
      dragSettings.index = this.fixIndex(draggableScope, dragSettings, dragModelValue);
      dropSettings.index = this.fixIndex(droppableScope, dropSettings, dropModelValue);

      jqyoui_pos = angular.isArray(dragModelValue) ? dragSettings.index : null;
      dragItem = angular.isArray(dragModelValue) ? dragModelValue[jqyoui_pos] : dragModelValue;


      if (angular.isArray(dropModelValue) && dropSettings && dropSettings.index !== undefined) {
        dropItem = dropModelValue[dropSettings.index];
      } else if (!angular.isArray(dropModelValue)) {
        dropItem = dropModelValue;
      } else {
        dropItem = {};
      }

      if (dragSettings.animate === true) {
        this.move($draggable, $droppableDraggable.length > 0 ? $droppableDraggable : $droppable, null, 'fast', dropSettings, null);
        this.move($droppableDraggable.length > 0 && !dropSettings.multiple ? $droppableDraggable : [], $draggable.parent('[jqyoui-droppable],[data-jqyoui-droppable]'), angular.startXY, 'fast', dropSettings, angular.bind(this, function() {
          $timeout(angular.bind(this, function() {
            // Do not move this into move() to avoid flickering issue
            $draggable.css({'position': 'relative', 'left': '', 'top': ''});
            // Angular v1.2 uses ng-hide to hide an element not display property
            // so we've to manually remove display:none set in this.move()
            $droppableDraggable.css({'position': 'relative', 'left': '', 'top': '', 'display': ''});

            this.mutateDraggable(draggableScope, dropSettings, dragSettings, dragModel, dropModel, dropItem, $draggable);
            this.mutateDroppable(droppableScope, dropSettings, dragSettings, dropModel, dragItem, jqyoui_pos);
            this.callEventCallback(droppableScope, dropSettings.onDrop, event, ui);
          }));
        }));
      } else {
        $timeout(angular.bind(this, function() {
          this.mutateDraggable(draggableScope, dropSettings, dragSettings, dragModel, dropModel, dropItem, $draggable);
          this.mutateDroppable(droppableScope, dropSettings, dragSettings, dropModel, dragItem, jqyoui_pos);
          this.callEventCallback(droppableScope, dropSettings.onDrop, event, ui);
        }));
      }
    };

    this.move = function($fromEl, $toEl, toPos, duration, dropSettings, callback) {
      if ($fromEl.length === 0) {
        if (callback) {
          window.setTimeout(function() {
            callback();
          }, 300);
        }
        return false;
      }

      var zIndex = 9999,
        fromPos = $fromEl.offset(),
        wasVisible = $toEl && $toEl.is(':visible'),
        hadNgHideCls = $toEl.hasClass('ng-hide');

      if (toPos === null && $toEl.length > 0) {
        if (($toEl.attr('jqyoui-draggable') || $toEl.attr('data-jqyoui-draggable')) !== undefined && $toEl.ngattr('ng-model') !== undefined && $toEl.is(':visible') && dropSettings && dropSettings.multiple) {
          toPos = $toEl.offset();
          if (dropSettings.stack === false) {
            toPos.left+= $toEl.outerWidth(true);
          } else {
            toPos.top+= $toEl.outerHeight(true);
          }
        } else {
          // Angular v1.2 uses ng-hide to hide an element 
          // so we've to remove it in order to grab its position
          if (hadNgHideCls) $toEl.removeClass('ng-hide');
          toPos = $toEl.css({'visibility': 'hidden', 'display': 'block'}).offset();
          $toEl.css({'visibility': '','display': wasVisible ? 'block' : 'none'});
        }
      }

      $fromEl.css({'position': 'absolute', 'z-index': zIndex})
        .css(fromPos)
        .animate(toPos, duration, function() {
          // Angular v1.2 uses ng-hide to hide an element
          // and as we remove it above, we've to put it back to
          // hide the element (while swapping) if it was hidden already
          // because we remove the display:none in this.invokeDrop()
          if (hadNgHideCls) $toEl.addClass('ng-hide');
          if (callback) callback();
        });
    };

    this.mutateDroppable = function(scope, dropSettings, dragSettings, dropModel, dragItem, jqyoui_pos) {
      var dropModelValue = scope.$eval(dropModel);

      scope.dndDragItem = dragItem;

      if (angular.isArray(dropModelValue)) {
        if (dropSettings && dropSettings.index >= 0) {
          dropModelValue[dropSettings.index] = dragItem;
        } else {
          dropModelValue.push(dragItem);
        }
        if (dragSettings && dragSettings.placeholder === true) {
          dropModelValue[dropModelValue.length - 1]['jqyoui_pos'] = jqyoui_pos;
        }
      } else {
        $parse(dropModel + ' = dndDragItem')(scope);
        if (dragSettings && dragSettings.placeholder === true) {
          dropModelValue['jqyoui_pos'] = jqyoui_pos;
        }
      }
    };

    this.mutateDraggable = function(scope, dropSettings, dragSettings, dragModel, dropModel, dropItem, $draggable) {
      var isEmpty = angular.equals(angular.copy(dropItem), {}),
        dragModelValue = scope.$eval(dragModel);

      scope.dndDropItem = dropItem;

      if (dragSettings && dragSettings.placeholder) {
        if (dragSettings.placeholder != 'keep'){
          if (angular.isArray(dragModelValue) && dragSettings.index !== undefined) {
            dragModelValue[dragSettings.index] = dropItem;
          } else {
            $parse(dragModel + ' = dndDropItem')(scope);
          }
        }
      } else {
        if (angular.isArray(dragModelValue)) {
          if (isEmpty) {
            if (dragSettings && ( dragSettings.placeholder !== true && dragSettings.placeholder !== 'keep' )) {
              dragModelValue.splice(dragSettings.index, 1);
            }
          } else {
            dragModelValue[dragSettings.index] = dropItem;
          }
        } else {
          // Fix: LIST(object) to LIST(array) - model does not get updated using just scope[dragModel] = {...}
          // P.S.: Could not figure out why it happened
          $parse(dragModel + ' = dndDropItem')(scope);
          if (scope.$parent) {
            $parse(dragModel + ' = dndDropItem')(scope.$parent);
          }
        }
      }

      $draggable.css({'z-index': '', 'left': '', 'top': ''});
    };

    this.fixIndex = function(scope, settings, modelValue) {
      if (settings.applyFilter && angular.isArray(modelValue) && modelValue.length > 0) {
        var dragModelValueFiltered = scope[settings.applyFilter](),
            lookup = dragModelValueFiltered[settings.index],
            actualIndex = undefined;

        modelValue.forEach(function(item, i) {
           if (angular.equals(item, lookup)) {
             actualIndex = i;
           }
        });

        return actualIndex;
      }

      return settings.index;
    };
  }])
;

解决方案

Haven't used angular-dragdrop, but the documentation says that the config object should contain a onDrop property. Try replacing jqyoui-droppable="{multiple:true}" with jqyoui-droppable="{multiple:true, onDrop: 'drop'}". angular-dragdrop seem to expect onDrop to be a string with the name of a function on the scope.

这篇关于如何仅使用角度指令将元素拖放到日历上的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆