2015-08-21 87 views
2

我使用的是Angular和JSPlumb,我想绑定从jsplumb到我的元素在指令中的可拖动行为(在链接函数中使用element)。角度绑定可拖动行为元素在角度方向的指令

现在我做这样的事情(http://jsfiddle.net/r8epahbt/):

// In the controller I define a method to get the elements 
// via jquery and then make them draggable 
function MyCtrl($scope, $http, $log, $timeout) { 
    $scope.makeWidgetsDraggable = function() { 
     // ISSUE: I have to use jQuery here, how can I do it the Angular way? 
     // I only want to make the "current" element draggable (it's wasteful to do ALL .widgets) 
     // How can I make only THIS element (could be passed from directive below) draggable 
     jsPlumb.draggable($('#canvas .widget'), { // Do this $('#canvas .widget') - the Angular Way 
      containment: "parent" 
     }); 
    }; 
} 

// When the value of $scope.items changes, we call scope.makeWidgetDraggable 
// which will get ALL widgets and make them draggable. 
// I only want to make the newly created widget draggable 
myApp.directive("widgetTemplate", function($parse, $timeout) { 
    //... 
    link: function (scope, element, attrs) { 
     // Watch the `items` for change, if so (item added) 
     // make the new element(s) draggable 
     scope.$watch('items', function() { 
      $timeout(function() { 
       // [ISSUE] - This method uses jQuery to get `this` element (and all other elements) 
       // How can I do this the `angular way` - I want to make `this` element draggable 
       // (the one that is being rendered by this directive) 
       scope.makeWidgetsDraggable(); 

       // I want to do something like this: 
       // But it Gives error: TypeError: Cannot read property 'offsetLeft' of undefined 
       /*jsPlumb.draggable(element, { 
        containment: "parent" 
       });*/ 
      }); // $timeout 
     }); // $watch 
    },// link 
    //... 
} 

我觉得这样的事情应该工作(在指令中的链接功能):

// Gives me error (through JSPlumb Library): 
// TypeError: Cannot read property 'offsetLeft' of undefined 
jsPlumb.draggable(element, { 
    containment: "parent" 
}); 

我做了一个工作JSFiddle,如果任何人都可以看看我真的很感激它。

http://jsfiddle.net/r8epahbt/


所以基本上,我想找到做线11(在小提琴)

// I want to remove this jquery selector 
jsPlumb.draggable($('#canvas .widget'),...) 

// and do it the `Angular Way` 
jsPlumb.draggable(element, ...) 
// Doesn't work, gives me error: 
// TypeError: Cannot read property 'offsetLeft' of undefined 

回答

2

一个更好的方式,您可以移动$scope.makeWidgetsDraggable功能是指令的一部分link,并将控制器从耦合到指令,因为您已通过指令的范围=传递项目:

指令

myApp.directive("widgetTemplate", function ($parse, $timeout) { 
    return { 
     restrict: "E", 
     templateUrl: "widgetTemplate", 
     replace: true, 
     scope: { 
      items: "=" 
     }, 
     link: function (scope, element, attrs) { 

      scope.makeWidgetsDraggable = function() { 
       // ISSUE: I have to use jQuery here, how can I do it the Angular way? 
       // I only want to make the "current" element draggable (it's wasteful to do ALL .widgets) 
       // How can I make only THIS element (could be passed from directive line 46) draggable 
       jsPlumb.draggable(element, { // Do this $('#canvas .widget') - the Angular Way 
        containment: "parent" 
       }); 
      }; 


      // Watch the `items` for change, if so (item added), make the new element(s) draggable 
      scope.$watch('items', function() { 
       $timeout(function() { 
        // [ISSUE] - This method uses jQuery to get `this` element 
        // How can I do this the `angular way` - I want to make `this` element draggable 
        // (the one that is being rendered by this directive) 
        scope.makeWidgetsDraggable(); 

        // I want to do something like this: 
        // But it Gives error: TypeError: Cannot read property 'offsetLeft' of undefined 
        /*jsPlumb.draggable(element, { 
         containment: "parent" 
        });*/ 
       }); // $timeout 
      }); // $watch 
     }, // link 
    } 
}); 

这是你的工作拨弄着变化:http://jsfiddle.net/r8epahbt/1/

编辑

好像我刚才前张贴了一下,该解决方案是行不通的100%,但是我会离开这个答案,以防它可能帮助其他人处理类似的情况。

我看到element指向DOM comment后,第二条建议是将单个项目传递给指令,并为每个项目指定1个指令实例。这样,您就不必看任何变更的项目,你不需要任何超时:

变化鉴于

<div id="canvas" class="canvas"> 
    <div class="absolute widget" ng-repeat="item in items" id="widget{{$index}}" data-wId="{{$index}}"> 
     <widget-template item="item"></widget-template> 
    </div> 
</div>  

通知我删除了<span ng-init="fakeAjaxCall"></span>和移动它交给控制器。

指令

myApp.directive("widgetTemplate", function ($parse, $timeout) { 
    return { 
     restrict: "E", 
     templateUrl: "widgetTemplate", 
     replace: true, 
     scope: { 
      item: "=" 
     }, 
     link: function (scope, element, attrs) { 
      jsPlumb.draggable(element.parent(), { 
       containment: "parent" 
      }); 

      //no need to watch for items added since an instance of the directive is used for each element. 

     }, // link 
    } 
}); 

最后这里的更新的jsfiddle,这个时候我做了双重肯定它的工作原理。 http://jsfiddle.net/r8epahbt/10/

+0

我喜欢这个想法,它可以帮助我进一步理解角度,但'jsPlumb.draggable(element..'仍然返回错误:'不能读取undefined'的属性'offsetLeft',我怎样才能得到如果你检查jsfiddle,它会在控制台中抛出相同的错误:http://jsfiddle.net/r8epahbt/2/(**注意**箱子不像原来的小提琴那样可以拖动) 。 – Anil

+0

奇怪的是,当我发布的答案是工作,但现在我回来了,它不再工作。让我检查一下,我会更新我的答案。 – yvesmancera

+0

这很奇怪,在指令中,元素指向DOM('ngRepeat')中的注释,我认为我有更好的解决方案,但需要做一些更改,准备就绪时会进行更新。 – yvesmancera