ChevCast
ChevCast

Reputation: 59234

What is the AngularJS equivalent of a JQuery plugin?

Background

I created a node module called shotgun and another called shotgun-client which when combined provide a node-powered realtime terminal API in the browser. The client library let's the user create an instance of shotgun.ClientShell and exposes an API to talk to the server. This clientShell instance is just an API with methods on it which means the user has to do all the work of creating an interface that uses that API.

I wanted to give the user a shortcut so I created this awesome JQuery plugin that acts as a wrapper for the clientShell object and creates a simple HTML terminal interface for the user.

Demo: http://codetunnel.com/demos/shotgun

The JQuery plugin does the following...

  1. Creates a bunch of elements and inserts them within the element the plugin was invoked on which would be #console if it was invoked like this:

    $('#console').shotgunConsole();

  2. Instantiates an instance of the shotgun.ClientShell API.

    var clientShell = new shotgun.ClientShell(options);

  3. Sets up event handlers to tie user actions to clientShell API calls.

My Question

I am new to AngularJS and I'm curious how I would turn a JQuery plugin like this one into an AngularJS directive. Essentially I'd like to do this:

<div ng-shotgun-console></div>

Then I'd like that div to transform into the same HTML terminal that my JQuery plugin creates. I'm just really confused as to how I package that up so it can be included as an "Angular Adapter" alongside my "JQuery Adapter". JQuery plugins are easy and are pretty much entirely contained in a single function...

$.fn.shotgunConsole = function (options) { ... };

...but I can't figure out how to create a simple script that does the same things and could easily be dropped into someone's existing Angular application with the same ease as a JQuery plugin.

Upvotes: 3

Views: 802

Answers (3)

Greg Pike
Greg Pike

Reputation: 91

What you need is a directive.

Assuming your Angular application is assigned to "app":

app.directive('ngShotgunConsole', ['injectedDependency',
    function(injectedDependency) {
        return {
            restrict: 'A',
            templateUrl: '/path/to/filename.html',
            scope: true,
            link: function(scope, element, attrs) {
                element.shotgunConsole();
            }
        }
    }
])

Using the link function in an Angular directive gives you access to element as if you were using jQuery. So "element" is like "$('your-selector')".

Upvotes: -1

aemxdp
aemxdp

Reputation: 1339

Angular way to things like this is directives. Here's an example of the directive for wiring custom jquery-powered autocomplete control:

angular
    .module('ng-button-autocomplete', [])
    .directive('ngButtonAutocomplete', function () { return {
        restrict: 'AE',
        replace: true,
        template: '<div><input type="text"><button type="button" class="btn"><i class="icon-search"></i></button></div>',
        scope: {
            source: '&',
            value: '='
        },
        link: function ($scope, $elem, $attr) {
            var input = $($elem.children()[0]),
                button = $($elem.children()[1]);
            $scope.$watch('value', function (val) {
                input.val(val);
            });
            input.autocomplete({
                source: $scope.source(),
                select: function (event, ui) {
                    $scope.$apply(function () {
                        $scope.value = ui.item.value;
                    });
                },
                close: function () {
                    input.autocomplete('option', 'minLength', 9999);
                },
                minLength: 9999
            });
            button.click(function () {
                input.autocomplete('option', 'minLength', 0);
                input.autocomplete('search', input.val());
            });
        }
    };});

You then inject this module to your application like this:

var app = angular.module('myApp', ['ng-button-autocomplete']);

app.controller('MyCtrl', function ($scope) {
    $scope.xs = ['abc', 'acd', 'bcd'];
    $scope.x = 123;
});

And just use directive in html like this:

<div ng-button-autocomplete data-source="xs" data-value="x"></div>

Upvotes: 4

TheSharpieOne
TheSharpieOne

Reputation: 25736

Its rather simple to turn a plugin into a directive. Here is a basic example assuming that your jQuery plugin is already loaded on the page.

HTML:

<div shotgun-console="options"></div>

In Controller:

$scope.options = {
    // ... some options
}

Directive:

.directive('shotgunConsole',function(){
    return {
        scope: {
            shotgunConsole: "="
        },
        link: function(scope, elm, attrs){
            $(elm).shotgunConsole(scope.options);
            scope.$watch('options',function(newOptions){
                // something to update the options
                $(elm).shotgunConsole(newOptions);
            });
        }
    };
});

Upvotes: 1

Related Questions