I could able to inject almost everything in the beforeEach(inject(beforeEach(inject(function(_$controller_,_mycustomService_,_$log_) in Jasmine
etc, But I can't inject a directive ?
I would get error like http://errors.angularjs.org/1.3.13/$injector/unpr?p0=myCustomDirectiveProvider%20%3C-%20myCustomDirective
Should this not possible with AngularJS ? Is this the reason why the unit testing of directive is little different style ( by that I meant the $compile option) ?
Directives aren't injectable anywhere in angular, only providers (services, factories, values, constants, etc.).
In order to test a directive, you need to ensure the module in which the directive is defined has been loaded with the module() function, (it'll also need to be referenced in your karma config), then you can compile a piece of DOM and ensure everything behaves as you expect.
Rather than go into a full example here, I'll advise you to do your own research and google "testing angular directives".
Related
I am very new to angularjs. I have little bit confusion with link and compile usage in directives. Can anyone please tell me in which scenarios we have to use link and compile.
What is the difference between compile and link function in angularjs
Already answered on stack overflow and has an excellent explanation
The compile phase
When the DOM is loaded Angular starts the compile phase, where it traverses the markup top-down, and calls compile on all directives. Graphically, we could express it like so:
An image illustrating the compilation loop for children
It is perhaps important to mention that at this stage, the templates the compile function gets are the source templates (not instance template).
The link phase
DOM instances are often simply the result of a source template being rendered to the DOM, but they may be created by ng-repeat, or introduced on the fly.
Whenever a new instance of an element with a directive is rendered to the DOM, the link phase starts.
In this phase, Angular calls controller, pre-link, iterates children, and call post-link on all directives, like so:
Below links will give you clear idea for compile vs link.
Angular directives - when and how to use compile, controller, pre-link and post-link
http://odetocode.com/blogs/scott/archive/2014/05/28/compile-pre-and-post-linking-in-angularjs.aspx
I use ui-router to create routes with multiple HTML pages.
I have custom "target" directives within these pages that use $state.current in various ways.
But I also have other custom "lookup" directives in other states which load these HTML "templates", find these "target" directives, compile them and insert them into the DOM.
The problem I am having is that when the HTML content is compiled in these second directives, $state.current obviously refers to whatever state the application is in when it is compiled, whereas I would like the directive to compile as if it was in its "native" state.
Is there any (easy-ish!) way to get a reference to the target directive's "native" state? i.e. the state connected to the .HTML file which the directive is in? Is there a method (angular, jquery, native js or anything else) to get from the directive to the HTML template file? Then I could do a reverse lookup on the state objects. element.ownerDocument can get the URL of the current state, but not the HTML file of the template.
Alternatively, if the second directive had a reference to the "target" state, how should I modify the "target" directive so that it takes a state reference when it is compiled in both scenarios? Something in the compile function perhaps?? - but the docs don't seem to cover this kind of use case... I could do with a pointer in the right direction.
I hope that all makes sense. I have looked around for similar answers, but I guess this is an unusual use case? I'll knock up a Plunker shortly to help illustrate...
When you compile HTML using $compile, you pass in a scope object. Instead of using $state.current within the directive, could you attach the "state" you need to the scope object that you're passing in?
How and why is <body ng-app> used? How can we assign controllers, directives etc to this nameless module. Also explain how this is related to manually bootstraping the Angular App.
Fiddle
This is actually three separate questions, but I'm happy to tackle each one.
How and why is used?
Angular will not and cannot properly bootstrap the application unless there is an entrance point to that application. According to the documentation, if a parameter is not passed that names the app instance, angular will attempt to auto-bootstrap the application for you by crawling the DOM and using the first ngApp directive instance that it is encountered.
We typically want to place our entrance point on the <body> element to encompass all the potential DOM we need without cluttering it with <head> elements, such as loading scripts and css. That said, if you are auto-bootstrapping your application, the recommended placement is on the HTML element.
How can we assign controllers, directives etc to this nameless module?
Modules, controllers, etc MUST be attached to something in order for Angular to pick them up and interopt with them correctly.
Once the application is bootstrapped, Angular will begin parsing the DOM, looking for directives. If you have an application instance (and you do), your controllers will be automatically be added to that instance. If you look at the bootstrap documentation -> Automatic Initialization, you'll find the following:
Angular initializes automatically upon DOMContentLoaded event or when
the angular.js script is evaluated if at that time document.readyState
is set to 'complete'. At this point Angular looks for the ng-app
directive which designates your application root. If the ng-app
directive is found then Angular will:
load the module associated with the directive.
create the application
injector compile the DOM treating the ng-app directive as the root of
the compilation. This allows you to tell it to treat only a portion of
the DOM as an Angular application.
How the heck is the fiddle working?
This one is actually smoke and mirrors that really shouldn't count :). If you look at the network traffic for JSFiddle, you'll find that AngularJS is actually being loaded. As a result, your interpolation is actually getting automagically bound to the JSFiddle Angular instance, not one that you provide yourself (or in this case didn't), parsed, and subsequently rendered into the DOM as 2.
Per angularjs.org:
"The ngApp directive designates the root element of the application and is typically placed near the root element of the page - e.g. on the or tags."
In other words, ng-app is what makes your html become an Angular application, thus being able to use the {{ }} in your code. These brackets are able to carry out operations, which is why you're able to calcuate 1 + 1. If you were to use variables, however, you would need to attach an ng-controller to a container div and initialize a Controller.
It's the equivalent of ng-app="". However, you need a namespace to attach controllers, directives. etc too. Angular can interpolate {{ 1 + 1 }} without a namespace, but you won't be able to bind anything to the views scope. Interestingly enough ng-app=" " is a namespace you can bind to.
https://jsfiddle.net/n3hygcnd/3/
I have a directive that takes "previewHTML" as a $scope variable input. I simply want to insert this HTML into a div in my directive template.
I've been working on this problem for a week trying methods from using ng-bind-html, {{}}, $sce, $compile and everything I could think of inbetween; I'm at a loss of why this is so painfully difficult.
The closest I've gotten is to create a scope using $rootScope.$new(true), then attach the variables I need "newScope.value = 'myvalue'", then use $compile to compile the preview HTML and in the cloneAttachFn (which I assume is a callback for when it's finished compiling) I set the previewHTML scope variable, which is included as '< ... ng-bind-html="previewHTML">'
The html without the scope applied comes out fine, but the bindings aren't set. The weird thing is that in the object they are set, but in the outputted HTML they are not; meaning the element has been created, but the bindings haven't been set yet. Unfortunately, Angular won't take a jquery HTML object in ng-bind-html, even though it returns a jquery object in order to maintain the bindings in the HTML.
I'm going to have to use a timeout for now... but does anyone know how to do this very rudimentary thing of including html, that has binding, in a directive template (it has to come from a $scope variable, or at least be generated outside of the directive by the user of the directive)? [is it even async? The documentation is frustratingly unclear]
(Honestly, I'm tens of thousands of lines and a year in and the more I use Angular the more I'd rather use plain JS)
I have 2 questions relating to directives. The first question relates to injecting a provider. I have used the compile directive example listed on the AngularJS web site. In that example it states to create a module and then create a directive from that module
// declare a new module, and inject the $compileProvider
angular.module('compile', [], function($compileProvider) {
// configure new 'compile' directive by passing a directive
// factory function. The factory function injects the '$compile'
$compileProvider.directive('compile', function($compile) {...
In my application in all I do is create the directive like so
myApp.directive('compile', function($compile) {...
I haven't referred to $compileProvider anywhere in my code, however my code still works and compiles templates quiet well. Why is that?
Also, although it works well when compiling templates they all seem to work except when I compile 'switch' statement. 'switch' statements do not seem to link the scope, all the other elements compile without a problem. Is this related to the fact that I haven't injected $compileProvider or is there something about switch statements that require an extra step when compiling?
Thanks
Frank
It works and compiles templates quite well because module.directive is simply shorthand for $compileProvider.directive. The docs for module.directive refer you to $compileProvider.directive.
As for using switch inside your directives, can you provide an example of how you're doing this? Depending on what you're switching on and where you're doing it, you may be defining your directive incorrectly. For example, if you're switching inside of directive callback, it's only going to be executed once, so only one of your case statements will win and create only 1 directive.