【问题标题】:Accessing AngularJS elements from a jQuery plugin从 jQuery 插件访问 AngularJS 元素
【发布时间】:2015-03-06 06:38:17
【问题描述】:

我对 AngularJS 很陌生,所以我试着理解它。 因此,当您阅读最初的问题时,不要向我开枪。

我正在使用 AngularJS 开发一个应用程序。 HTML 看起来像这样:

<div id="OfficeUI" ng-controller="Office as Office">

    <div class="absolute">
        <div class="container application-icons icon">
            <img id="{{icon.Id}}" ng-repeat-start="icon in Office.Icons" ng-repeat-end ng-src="{{icon.Icon}}" alt="{{icon.Alt}}" />
        </div>
    </div>

</div>

我的应用程序的控制器如下所示:

var OfficeUI = angular.module('Office');

// Defines the Office controller for the application.
OfficeUI.controller('Office', ['$http', function($http) {
    // Defines required variables.
    var application = this;

    // Get the Json file 'application.json' that defines the application data.
    $http.get('/OfficeUI.Beta/Resources/JSon/application.json')
        .success(function(data) {
            application.Title = data.Title;
            application.Icons = data.Icons;
        })
        .error(function(data) {
            console.error('An error occured while loading the \'application.json\' file.');
        });
}]);

正如您在 HTML 中看到的,我正在根据特定 JSon 文件中的数据绑定图像元素。

现在,我希望用户能够将事件添加到给定元素(在本例中为图像)。 因此,我开发了一个 jQuery 插件,如下所示:

(function ( $ ) {
    $.fn.OfficeUI = function(options) {

        var settings = $.extend({
        }, $.fn.OfficeUI.Defaults, options);

        return this;
    }

    $.fn.OfficeUI.Defaults = { };

    $.fn.OfficeUI.bind = function(elementSelector, bound, action) {
        $(elementSelector).on(bound, function() { action(); });

        return this;
    };
}(jQuery));

这个插件允许我调用添加事件如下:

$(this).OfficeUI.bind("icoApplication", "click", function() {
    console.log('The following element is bound.');
});

但是,该函数的第一个参数采用选择器来查找要将事件附加到的元素。但在 AngularJS 中,这不起作用,因为尚未创建元素。

谁知道如何解决这个问题? 我确实想为用户提供一种干净、简约的方式来将事件绑定到应用程序,而无需修改现有的控制器、指令、过滤器……

提前致谢。

【问题讨论】:

  • 我建议查看angular.element() 的文档(如果加载 jquery,则为 jquery - 如果不加载,则为 jQLite)并建议如果您在控制器范围内进行绑定,则可以控制它在 $digest 循环see this 中发生,这允许 Angular 在绑定之前知道您在做什么并创建 - 通常,如果您要使用 Angular,请避免在 jQuery 中构建东西并使用指令或服务用角度代替。

标签: javascript jquery angularjs


【解决方案1】:

我不确定我是否正确理解了您的问题。为什么不对图片使用 ng-click?

<div id="OfficeUI" ng-controller="Office as Office">

<div class="absolute">
    <div class="container application-icons icon">
        <img ng-click="myFunction() id="{{icon.Id}}" ng-repeat-start="icon in Office.Icons" ng-repeat-end ng-src="{{icon.Icon}}" alt="{{icon.Alt}}" />
    </div>
</div>

在你编写的控制器中:

// Defines the Office controller for the application.
OfficeUI.controller('Office', ['$scope','$http', function($scope, $http) {
    // Get the Json file 'application.json' that defines the application data.
    $http.get('/OfficeUI.Beta/Resources/JSon/application.json')
        .success(function(data) {
            $scope.Title = data.Title;
            $scope.Icons = data.Icons;
        })
        .error(function(data) {
            console.error('An error occured while loading the \'application.json\' file.');
        });

    $scope.myFunction = function () {
        console.log('The following element is bound.');
    }
}]);

然后将视图绑定到控制器:

<div id="OfficeUI" ng-controller="Office">

<div class="absolute">
    <div class="container application-icons icon">
        <img id="{{icon.Id}}" ng-repeat-start="icon in Icons" ng-repeat-end ng-src="{{icon.Icon}}" alt="{{icon.Alt}}" />
    </div>
</div>

【讨论】:

  • 因为这是我想要避免的。那么我怎么会说第一个图像应该在点击时响应,第二个应该在悬停时响应,第三个在滚动事件时响应,...
  • 如果在 ng-repeat 中,您可以添加 Angular? stackoverflow.com/questions/21751676/…。或者向 myFunction() 添加参数?
  • 我不知道这将如何解决我的问题。我希望用户能够在不修改控制器、指令或任何其他项目的情况下向 angularJS 渲染元素添加事件。
  • 我的项目是使用另一种方法构建的。我让用户能够在 JSON 文件中指定操作的数量及其 ID。使用您的方法,我的客户需要修改 HTML(模板)以实现自定义功能,这是我一直希望避免的。我不希望客户弄乱这些文件。它应该在其他地方。
【解决方案2】:

正确的方法是使用angular directives 看看这个SO question

this example

示例

App.directive('directiveName', function() {
    return {
        restrict: 'A',
        link: function(scope, element, attrs) {
            $(element).'pluginActivationFunction'(scope.$eval(attrs.directiveName));
        }
    };
}); 

【讨论】:

  • 我知道指令的方面,但是当您在循环中的 img 元素上添加指令时,该指令会添加到所有元素中。如果我想点击第一个元素并将鼠标悬停在第一个元素上怎么办?
【解决方案3】:

经过几个小时的搜索,我找到了一个我非常满意的解决方案。

所以,让我们总结一下我目前所拥有的:

我确实有用于呈现网站的 JSon 文件,如下所示:

{
  "Title": "Inbox - user@github.com - Outlook",
  "Icons": [
    {
      "Id": "icoApplication",
      "Icon": "Resources/Images/Application/Application.png",
      "Alt": "Outlook"
    },
    {
      "Id": "icoSendReceive",
      "Icon": "Resources/Images/Application/Send-Receive.png",
      "Alt": "Send / Receive"
    },
    {
      "Id": "icoUndo",
      "Icon": "Resources/Images/Application/Undo.png",
      "Alt": "Undo"
    }
  ]
}

然后,我确实有使用 AngularJS 呈现的 HTML:

<div class="absolute">
    <div class="container application-icons icon">
        <img id="{{icon.Id}}" ng-repeat-start="icon in Office.Icons" ng-repeat-end ng-src="{{icon.Icon}}" alt="{{icon.Alt}}" />
    </div>
</div>

现在,我确实有客户可以使用这个 AngularJS 应用程序。我想让用户能够在任何img 元素上附加任何事件(单击、滚动、鼠标输入...)。

客户可以在 JSon 文件中添加元素,但我想避免我的客户需要修改 AngularJS 模板才能附加事件,因为这意味着客户需要在模板中编写条件和其他内容.我会坚持使用普通的 jQuery / JavaScript 来附加事件。

所以,我所做的是创建了一个自定义 AngularJS 指令,它允许我附加事件。该指令如下所示:

OfficeUI.directive('ngcDynamicEventHandling', function() {
    return {
        restrict: 'A',
        replace: 'true', 
        link: function(scope, element, attributes) {
            var parameter = scope.$eval(attributes['ngcDynamicEventHandling']); // Get the     parameters passed to this directive.

            // Check if an event is attached to this object.
            var registeredEvent = $(this).OfficeUI.searchEvent(parameter);

            // An attached event has been found, so let's register it.
            if (registeredEvent != null) {
                element.on(registeredEvent.handler, function() { 
                    registeredEvent.action();
                });
            }
        }
    };
});

上述指令接受我在此指令中检索的参数。然后,我调用一个 jQuery 插件来附加我的事件。

添加指令时的 HTML 如下所示:

<div class="absolute">
    <div class="container application-icons icon">
        <img ngc-dynamic-event-handling="icon.Id" id="{{icon.Id}}" ng-repeat-start="icon in Office.Icons" ng-repeat-end ng-src="{{icon.Icon}}" alt="{{icon.Alt}}" />
    </div>
</div>

现在,让我们继续我的 jQuery 插件,它允许我注册事件。

(function ( $ ) {
    $.fn.OfficeUI = function(options) {

        var settings = $.extend({
        }, $.fn.OfficeUI.Defaults, options);

        return this;
    }

    $.fn.OfficeUI.Defaults = { };

    var eventCollection = []; // Defines a private collection of registered events.

    $.fn.OfficeUI.bind = function(element, handler, action) {
        eventCollection.push({
            element: element,
            handler: handler,
            action: action
        });
    };

    $.fn.OfficeUI.searchEvent = function(element) {
        var foundElement = $.grep(eventCollection, function(item) {
            return item.element == '#' + element
        });

        if (foundElement.length != 0) {        
            return foundElement[0];
        } 

        return null;
    };
}(jQuery));

所以,第一个重要的函数是bind 函数。 这个函数可以这样调用:

$(this).OfficeUI.bind("#icoApplication", "click", function() {
    console.log('This method is executed when you click on the application icon.');
});

通过调用上述函数,我将具有某些属性的对象添加到数组中。

$.fn.OfficeUI.bind = function(element, handler, action) {
    eventCollection.push({
        element: element,
        handler: handler,
        action: action
    });
};

现在,让我们再次检查一下我们的指令:

var parameter = scope.$eval(attributes['ngcDynamicEventHandling']); // Get the parameters passed to this directive.

// Check if an event is attached to this object.
var registeredEvent = $(this).OfficeUI.searchEvent(parameter);

// An attached event has been found, so let's register it.
if (registeredEvent != null) {
    element.on(registeredEvent.handler, function() { 
        registeredEvent.action();
    });
}

我在这里做的是执行我的插件的函数searchEvent,它将检查我是否已经向放置指令的元素注册了一个事件。

如果是这种情况,则将该事件注册到元素。

所以,这是一篇相当长的帖子,但我希望我已经说清楚了。 现在,我确实能够将事件附加到 AngularJS 呈现的 HTML,并且我不需要修改 AngularJS 模板。更重要的是,我可以附加各种元素,不仅仅是点击或其他。

这为最终用户提供了很大的灵活性。

如果有人对此有想法,请不要犹豫回复。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多