【问题标题】:Angular bind draggable behaviour to element in directive the angular way角度以角度方式将可拖动行为绑定到指令中的元素
【发布时间】:2015-08-21 16:19:10
【问题描述】:

我正在使用 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

【问题讨论】:

    标签: angularjs jsplumb


    【解决方案1】:

    您可以将$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>       
    

    请注意,我删除了 &lt;span ng-init="fakeAjaxCall"&gt;&lt;/span&gt; 并将其移至控制器。

    指令

    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/

    【讨论】:

    • 我喜欢这个想法,它可以帮助我更深入地理解 Angular,但 jsPlumb.draggable(element.. 仍然返回错误:Cannot read property 'offsetLeft' of undefined, How can I get around using jQuery for angular? - 如果您检查 jsfiddle,它会在控制台中引发相同的错误:jsfiddle.net/r8epahbt/2注意这些框不像原来的 fiddle 那样可拖动)。
    • 奇怪,当我发布答案时它正在工作,但现在我回到它,它不再工作了。让我检查一下,我会更新我的答案。
    • 这太奇怪了,在指令中,元素指向 DOM 中的注释(ngRepeat),我想我有更好的解决方案,但需要更多更改,我会更新当它准备好时。
    • 请看看我更新的答案,这次我确保它有效。
    • 谢谢!我是 Angular 的新手,这(以及你之前给出的例子)实际上帮助我更好地理解它,正是我想要的。谢谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-04-21
    • 2017-03-10
    • 2016-07-01
    • 2020-09-22
    • 2015-12-22
    • 1970-01-01
    • 2014-03-20
    相关资源
    最近更新 更多