Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Injecting $attrs in AngularJS

I have some JavaScript written in the context of AngularJS. My relevant JavaScript looks like the following:

.factory('$myFactory', function ($myLibrary, $interpolate) {
 return {
   myFunction: function ($scope, $attrs, p) {
     if (p !== null) {
       $attrs.set('myProperty', p);
     }
   }
 };

I am trying to unit test this code. In an attempt to unit test the code, I'm using Jasmine.

it('should set myProperty', inject(function ($scope, $myFactory) {
//  $myFactory.myFunction($scope
}));

I can't figure out how to inject some $attrs from my unit test. How do I do that? I can successfully get my $scope setup. However, I don't understand how to inject $attrs. Is there something special about it that I'm not aware of? I'm having a similar issue with $element, though that one is out of the context of this specific test.

Thank you!

like image 250
user3111277 Avatar asked Jan 23 '14 15:01

user3111277


People also ask

What is injector in AngularJS?

Overview. $injector is used to retrieve object instances as defined by provider, instantiate types, invoke methods, and load modules. The following always holds true: var $injector = angular.

Which component can be injected as a dependency in AngularJS?

The "Application Module" can be injected as a dependency in AngularJS.

What is Attrs in AngularJS?

Using attrs you are able to access the attributes defined in your html tag like <fm-rating ng-model="$parent.restaurant.price" symbol="$" readonly="true"> So in this case you will have access to the symbol and readonly attributes.

What does $compile do in AngularJS?

Compiles an HTML string or DOM into a template and produces a template function, which can then be used to link scope and the template together.


3 Answers

Here is a plunker: http://plnkr.co/edit/k1cxSjpAXhhJUEOcx9PG

Maybe there is a better solution but That's what I got.

  • $scope is easy to get, you can inject $rootScope everywhere
  • $attrs on the other hand is only available through the $compile variable (it lives in compile.js)

My solution is to create a fake controller , to compile it and to hijack it's $attrs.

So that's how it looks like:

var injected = null

function fakeController($scope, $attrs, $element){
  injected = {}
  injected.$scope = $scope;
  injected.$attrs = $attrs;
  injected.$element = $element;
}

describe('Testing a Hello World controller', function() {
  var $scope = null;
  var $attrs = null;
  var $element = null;

  var ctrl = null;

  //you need to indicate your module in a test
  beforeEach(module('plunker'));

  beforeEach(inject(function($compile, $rootScope, $controller) {

    $compile('<span ng-controller="fakeController"></span>')($rootScope);

    $scope = injected.$scope;
    $attrs = injected.$attrs;
    $element = injected.$element;

    ctrl = $controller('MainCtrl', {
      $scope: $scope,
      $attrs: $attrs,
      $element: $element
    });

  }));

  it('should say hallo to the World', function() {
    expect($scope.name).toEqual('World');
  });
});
like image 196
Ilan Frumer Avatar answered Oct 22 '22 22:10

Ilan Frumer


seems that you can just instantiate the controller with empty object, as well...

ctrl = $controller('MyCtrl', {
  $scope: $scope,
  $attrs: {}
});
like image 32
jaf0 Avatar answered Oct 22 '22 21:10

jaf0


In latest versions of AngularJS a controller needs to be provided to get full $attrs.

See $controllerProvider documentation.

Here's a snippet

describe('angular-component-controller', function() {

  // save injected parameters of controller
  var injected = {};
  var controller;

  // @see $https://docs.angularjs.org/api/ngMock/service/$componentController
  // we need to extract those from $compile instead of use as locals
  angular.module('locals', []).controller('controller',
    ['$attrs', function($attrs) {
      injected.$attrs = $attrs;
    }]
  );

  beforeEach(module('locals'));

  beforeEach(inject(function($rootScope, $compile, $componentController) {
    // invoke dummy component to get $attrs
    $compile('<span ng-controller="controller">')($rootScope);

    var locals = {};
    locals.$scope = $rootScope.$new();
    locals.$attrs = injected.$attrs;

    var bindings = {};

    controller = $componentController('component', locals, bindings);
  }));    
});

See this gist AngularJS $componentController unit test

like image 32
Ricardo Veloso Avatar answered Oct 22 '22 22:10

Ricardo Veloso