Trying to convert jquery plugin to Angular Directive

Within a loop, I have:

<div class="barcode" class="thumbnail"> 
  <canvas class="ean" barcode-generator barcode-value="9002236311036"> </canvas>
</div>

Which loops out a load of barcodes. I've statically added the barcode-value, but the intention is for this to be added via {{barcodeNumber}}

I've found a really nice plugin https://github.com/joushx/jQuery.EAN13 which converts a number to a barcode.

Following various tutorials, I've written the following Directive (although I don't quite get the HOW or WHY as yet). I've also included jquery above Angular, and the plugin after Angular.

app.directive('barcodeGenerator', function () {
return {
  restrict: 'A',
  scope: {
    barcodeValue: '='
  },
  link: function (scope, elem, attrs) {
    console.log("Recognized the barcode directive usage");
    $('.ean').EAN13(scope.barcodeValue);
  }
}
});

The console.log works - but then the bit where I call the plugin doesn't... Chrome debug displays the following error:

TypeError: Object 9002236311036 has no method 'split'

I'm not sure what I'm doing wrong - have read lots of forum posts, but can't quite grok it.

Thanks, Rob

Edit - following on from Francisco's post below - adding toString() has worked. Only thing is, I don't know why / how this is working.

app.directive('barcodeGenerator', function () {
return {
  restrict: 'A',
  scope: {
    barcodeValue: '='
  },
  link: function (scope, elem, attrs) {
    console.log("Recognized the barcode directive usage");
    $('.ean').EAN13(scope.barcodeValue.toString());
  }
}
});

So I've done a little refactoring:

app.directive('ean', function () {
return {
  restrict: 'C',
  scope: {
    barcodeValue: '='
  },
  link: function (scope, elem) {
    console.log("Recognized the barcode directive usage");
    $(elem).EAN13(scope.barcodeValue.toString());
  } 
}
});
  • I wanted to clean up my html, so used a class (restrict C?) - set the barcode value within the scope.

Then in my html, I added:

<div class="barcode" class="thumbnail"> 
  <canvas class="ean" barcode-value="{{barcode}}"> </canvas>
</div>

And this is where it errors... the barcode-value. Before it was hardwired and worked... now I try to put it in the loop, it doesn't.

Edit...

<div class="barcode" class="thumbnail"> 
  <canvas class="ean" barcode-value="barcode"> </canvas>
</div>

Removing the curly brackets worked.... hmm... I need to get a manual...

Answers:

Answer

Directives are a way to extend HTML. The whole purpose behind doing this is that AngularJS encourages to keep all DOM manipulation outside of controllers so they become testable.

I won't get into detail of how exactly directives work, it's possibly both the most powerful and most confusing aspect of AngularJS.

In short though, referring to what you've done:

app.directive('barcodeGenerator', function () {
    return {
        // Restrict tells AngularJS how you will be declaring your directive in the markup.
        // A = attribute, C = class, E = element and M = comment
        restrict: 'A',
        // The directive compiler actually happens before the $scope is available in AngularJS, therefore
        // You need to pass certain values into your scope. In this instance, you are passing the barcodeValue
        // attribute and telling it its equal. In other words where you use scope.barcodeValue.toString() below
        // You are able to do this because of the below declaration. There are other symbols you can use to tell
        // the compiler to do other things such as interpret the values as a method, but I'll let you investigate
        scope: {
            barcodeValue: '='
        },
        // The link function passes the element to the directive and allows you to manipulate the dom
        // You could event try to replace $(.ean) with just elem below, since you are passing the scope,
        // element and attribute to the function below, then using the jQuery plugin to do the rest.
        link: function (scope, elem, attrs) {
            console.log("Recognized the barcode directive usage");
            $('.ean').EAN13(scope.barcodeValue.toString());
        }
    };
});
Answer

The francisco.preller is absolutely right. Just one improvement is required. If you change

link: function (scope, elem, attrs) {
        console.log("Recognized the barcode directive usage");
        $('.ean').EAN13(scope.barcodeValue.toString());
    }

with

link: function (scope, elem, attrs) {
        console.log("Recognized the barcode directive usage");
        elem.EAN13(scope.barcodeValue.toString());
    }

Not only it becomes more angularized, but it also follows the role of the 'elem' parameter, which is already a jQuery object (or jQLite, which is a jQuery subset, if jQuery is not loaded). Any use of direct DOM manipulation is said to be a bad practice by Google, as it could not always be reflected in Angular's digest cycle and will cause unexpected behavior.

Answer

Trying to get something similar to work with no success..the barcode will just not display..do you have all your code on github to use?

Answer

Using this library for the barcode: https://github.com/joushx/jQuery.EAN13

app.directive('ean', function () {
return {
  restrict: 'C',
  scope: {
    barcodeValue: '='
  },
  link: function (scope, elem, attr) {
    console.log("Recognized the barcode directive usage");
    $(elem).EAN13(scope.barcodeValue.toString());
  }
}
});

and

<div class="barcode" class="thumbnail" ng-show="voucher.barcode">
<canvas class="ean" barcode-value="voucher.redemptionCode"> </canvas>
</div>

and if I recall correctly - any number you pump in gets converted to the barcode (although its been over a year since I did this... )

Hope this helps

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us Javascript

©2020 All rights reserved.