I'm new to angular and i'm wondering where to put some code. I know that dom manipulation should not happen in a controller but in a directive.
Do i realy have to create a directive for this small bit of javascript code (a click on a button adds a class to the <body> tag?)
Yes, create a directive. Multiplying directives in your code base is not a bad thing at all. Look at the angular source code for directives like ngBind, and you'll realise that small doesn't matter at all, it is quite the opposite (directives are meant to be specialised).
Related
Sometimes when I build an Angular custom directive, I will hear a comment as to, if it is an Angular directive, it should not use jQuery code in it, because it should be built in an AngularJS way.
And I thought it might be true, but is it possible? For example, what if the directive template has 2 sections, one is the words and one is the tiny images (such as review stars), and so you need 2 sections in your template, labeled as .description and .star-images -- so then you should need to use $.find(".description") to find that section inside your template if you need to do something to it or inside it. jqLite won't work as jqLite's find() is limited to tags only.
Another example is, what if you have a directive that doesn't have a template, but just limit the keypress to digits only, say, for an input box. So you don't want your directive to have a template as <input type="text"> but just want the user of the directive to say <input type="text" digits-input-only> and your directive is called digitsInputOnly. So in that case, don't you need to use jQuery's elem.on() or elem.bind() to listen on keypress or keydown events, and when the key down code is not a digit, then do a event.preventDefault()? So in that case, it has to use jQuery?
Or other there other ways to do it so that you really shouldn't need to use jQuery?
As a long time user of jQuery it is easy while learning angular to lean on jQuery however none of the cases mentioned are difficult to work around not having it...and in most cases are actually easier
Try removing jQuery completely from your project to avoid temptation and you will quickly realize how little you really need it
The core directives provide the majority of the event handlers needed and angular.element (jQlite) also has bind() which will accept virtually any event name. $document.bind('contextmenu', function(event) for example.
The core dom event directives all let you pass in $event for things like event.preventDefault()
<input ng-keydown="somefunc($event)">
For traverses you can always use a native method to query DOM to find an element and wrap that element (or collection) in angular.element() the same way you would with $(). The more you focus on data models and core directives first however, the less you find need to actually do dom traverses
As for plugins ... it's not a sin to use jQuery plugins in directives. There are some very commonly used angular modules that are wrappers for well known jQuery plugins ... fullcalendar and Datatables are a couple that quickly come to mind along with numerous datepickers. However often you will find situations where you may have previously leaned on a plugin to do simple tasks that angular makes easy itself and you no longer would use such plugins
The sin with using jQuery plugins is using ones that are actually easier to achieve (and test) using angular itself
In conclusion, the biggest adjustment is learning how to focus on data models first, before thinking about the DOM. Also being intimately familiar with the left side menu of the API reference where all the core directives and services are listed is a huge help
Let us say I have a custom directive implemented like this:
<div my-custom-component></div>
This directive transforms the div into something with a whole lot of child elements. It's using a jQuery Widget internally. Is there a way to ask Angular to completely ignore this part of the visual-tree while dirty checking?
You might look into Bind Once (v1.3+):
<my-custom-component name="::item"></my-custom-component>
I've been trying to get my head around ng-template and where and when I may need it. After looking at a few tutorials I am still none the wiser.
If I have defined a template eg.
<script type="text/ng-template" id="my-template-id">
... html here
</script>
I have seen that sometimes this is used with ng-include and sometimes as a templateUrl in a directive.
Also once I read that it goes in to the $templateCache, what benefit do I get from using this? I am using Angular to dynamically list products, no great shakes there but if I can get more performance from using something like ng-template I would like to have a go at it.
Script types ng-template are used to embed html fragments inline. These fragments can then be used by ng-include or directives to load the html fragment and construct the view.
Advantage of inline template fragments is that there is one less call to make to server to load the html template which is required in standard scenario. Not a huge advantage considering the template is cached for future use.
The disadvantage could be that you may never use the inline template at all and it just gets loaded as part of parent view content.
I do not quite understand when to use a directive and when it would be more appropriate to use nginclude. Take this example: I have a partial, password-and-confirm-input-fields.html, that is the html for entering and confirming a password. I use this both under signup-page and under change-password-page. Those two pages has a controller each, the partial html has no dedicated controller.
Should I use directive or ngInclude for this?
It all depends on what you want from your code fragment. Personally, if the code doesn't have any logic, or doesn't even need a controller, then I go with ngInclude. I typically put large more "static" html fragments that I don't want cluttering up the view here. (ie: Let's say a large table whose data comes from the parent Controller anyway. It's cleaner to have <div ng-include="bigtable.html" /> than all those lines cluttering up the View)
If there is logic, DOM manipulation, or you need it to be customizable (aka render differently) in different instances it's used, then directives are the better choice (they're daunting at first, but they're very powerful, give it time).
ngInclude
Sometimes you will see ngInclude's that are affected by their exterior $scope / interface. Such as a large/complicated repeater lets say. These 2 interfaces are tied together because of this. If something in the main $scope changes, you must alter / change your logic within your included partial.
Directives
On the other hand, directives can have explicit scopes / controllers / etc. So if you're thinking of a scenario where you'd have to reuse something multiple times, you can see how having its own scope connected would make life easier & less confusing.
Also, anytime you are going to be interacting with the DOM at all, you should use a directive. This makes it better for testing, and decouples these actions away from a controller / service / etc, which is something you want!
Tip: Make sure not to use restrict: 'E' if you care about IE8! There are ways around this, but they are annoying. Just make life easier and stick with attribute/etc. <div my-directive />
Components [Update 3/1/2016]
Added in Angular 1.5, it's essentially a wrapper around .directve(). Component should be used most of the time. It removes a lot of boilerplate directive code, by defaulting to things like restrict: 'E', scope : {}, bindToController: true. I highly recommend using these for almost everything in your app, in order to be able to transition to Angular2 more easily.
In conclusion:
You should be creating Components & Directives a majority of the time.
More extensible
You can template and have your file externally (like ngInclude)
You can choose to use the parent scope, or it's own isolate scope within the directive.
Better re-use throughout your application
Update 3/1/2016
Now that Angular 2 is slowly wrapping up, and we know the general format (of course there will still be some changes here and there) just wanted to add how important it is to do components (sometimes directives if you need them to be restrict: 'E' for example).
Components are very similar to Angular 2's #Component. In this way we are encapsulating logic & html in the same area.
Make sure you encapsulate as many things as you can in components, it will make the transition to Angular 2 that much easier! (If you choose to make the transition)
Here's a nice article describing this migration process using directives (very similar if you were going to use components of course) : http://angular-tips.com/blog/2015/09/migrating-directives-to-angular-2/
I am developing a mobile application with left and right drawer, using mmenu (http://mmenu.frebsite.nl/) it is working fine till I've decided to populate items of the right menu on the fly. My app is based on angularjs and all directives of angularjs in body are working fine except all directives inside <nav id="menu-right">somehow, angularjs directives inside the menu definitions are not executed. I am not sure if it is something related with the order of executing javascript. Any help will be really appreciated. Thank you !!
UPDATED (07-April)
An example in jsfiddle http://jsfiddle.net/jmhostalet/wcK8L/
"My controller says" is working in the body but not in the mmenu, in body prints "Hello" but in mmenu prints nothing
The problems you were running into were:
First off the was not included in the declaration
You are changing the DOM without angular knowing about it therefor it does not have a chance to compile the braces {{myCtrlVar}}
It seems like extra work to create a directive but in the long run will allow you to reuse your code more. Also if you are like me and have bad javascript habits; it is nicer to use a framework to keep things straight.
My solution the in the plunker below shows "one way" to do what you are asking. It would be interesting to port the entire MMenu code over to an angular module in order to have more parameters and control.
(Never heard of MMenu, but seems like a cool project -- I will look more into it).
Plunker
(sorry I am inept at using fiddler)
Your fiddle doesn't have controller initialization on #menu-right but on his sibling element and therefore {{myCtrlVar}} expression can't access controllers scope objects.