I am a bit confused regarding ngSwitch directive -- whether it is 'attribute directive' or 'structural directive'.
Attribute directives are written with 'square brackets' like [ngStyle], [ngClass], etc. (and we write it as [ngSwitch] which refers it as 'Attribute Directives').
Structural directives are written with 'aestrick' like *ngFor, *ngIf, etc. (and we write the cases as *ngSwitchCase="..." which means it is a structural directive).
<div [ngSwitch]="colorValue">
<p *ngSwitchCase="red">Red</p>
<p *ngSwitchCase="blue">Blue</p>
<p *ngSwitchCase="green">Green</p>
</div>
As per the code above, it is getting very confusing to categorize ngSwtich to either of the Directive Categories! Can someone help me out in understanding the directive-type of ngSwitch ?
[ngSwitch] is an attribute directive used in combination with *ngSwitchCase and *ngSwitchDefault that are both structural directives.
This is clearly explained in Angular's documentation...
NgSwitch — an attribute directive that changes the behavior of its companion directives.
NgSwitchCase — structural directive that adds its element to the DOM when its bound value equals the switch value and removes its bound value when it doesn't equal the switch value.
NgSwitchDefault — structural directive that adds its element to the DOM when there is no selected NgSwitchCase.
https://angular.io/guide/built-in-directives#switching-cases-with-ngswitch
As I understand it , 'structural directive' change the dom's struct. attribute directive change the dom's attribute,such as color,background and so on
ngSwitch change it's children's length , so its a structural directive,
It is a structural directive
Structural directives updates the DOM layout by adding or removing elements.
Structural Directive:
What are structural directives?
Structural directives are responsible for HTML layout. They shape or reshape the DOM's structure, typically by adding, removing, or manipulating elements.
As with other directives, you apply a structural directive to a host element. The directive then does whatever it's supposed to do with that host element and its descendants.
Structural directives are easy to recognize. An asterisk (*) precedes the directive attribute name as in this example.
Refer: https://angular.io/guide/structural-directives
ngSwitch is a built-in structural directive.
[https://angular.io/guide/structural-directives]
#j3ff: The (*) star on *ngSwitchCase is merely sugar syntax,
it does not indicate the type of directive.
It could be written the long way like this...
<div class="course-category" [ngSwitch]="colorValue">
<ng-template [ngSwitchCase]="'RED'">
<div>
<p>Red</p>
</div>
</ng-template>
Related
In angular we could do:
template: `<ng-container #c></ng-container>`
or:
template: `<template #c></template>`
To create a view container that is hidden when the template is rendered.
Is there a difference between using ng-container over the html template alternative? I'm guessing Angular has to have it's own template containers like ng-template or ng-container since use of the raw html template element could break non browser based runtimes, like mobile clients, etc.
The <ng-container> is always rendered, but does not represent a DOM element. It is still attached to the component's view.
The <ng-template> will only be rendered if it is explicitly requested.
Here's a good reference on the subject:
http://nataliesmith.ca/blog/2018-05-01-ngtemplate-ngcontainer-ngcontent/
To create a view container that is hidden when the template is rendered.
Always use <ng-template> when possible. The <ng-container> is for grouping DOM elements together. For example; when you need to apply a *ngIf to many <td> elements, because you can not use a <span> around <td>.
As I've recently found out, ngSwitch acts a bit like ngIf, in that it outright removes elements from the DOM rather than just hide them. Now in my application this strikes me as both needlessly expensive and potentially problematic down the line (if I need to access properties of my hidden DOM elements). At the same time I like the cleanliness of the ngSwitch syntax as opposed to a bunch of different ngShow directives (which would not allow me to include a 'default' behaviour either). Is there any way I can modify the way this directive works to have it merely hide elements, not remove them altogether? Thanks.
OK, I understood better your need and I have the same need before.
I advice you to use ngSwitch with custom directives like this :
<div ng-switch="mode">
<directive-a ng-switch-when="a"></directive-a>
<directive-b ng-switch-when="b">...</directive-b>
<directive-c ng-switch-default>...</directive-c>
</div>
and in the definitions of your directives directiveA, directiveB and directiveC you use the templateUrl wich will use the cache from the second call of the directive.
The second approach is to use ng-show on every directive but I prefer the ng-switch because it let the dom lighter.
I know this is a bit old but I faced the same issue today and I managed to cache segments views by not using ngSwitch but directly the [hidden] attributes with the segment condition this way :
<ion-segment [(ngModel)]="segmentName">
<ion-segment-button value="profile">
Profile
</ion-segment-button>
<ion-segment-button value="friends">
Friends
</ion-segment-button>
</ion-segment>
<page-profile [hidden]="segmentName != 'profile'" ></page-profile>
<page-friends [hidden]="segmentName != 'friends'" ></page-friends>
Just replace ngSwitchCase by the [hidden] conditional
No, there isn't any way to keep nodes hidden as ngShow and ngHide do if you use ngSwitch. Only the ngSwitchWhen node will be created if its condition is true, all others are commented.
The advantage of ngSwitch is that the dom will be lighter.
Hi please explain reason for following three scenarios as I am unable to know why is this happening -
1)
<div ng-controller="myctrl">
<p>something for DOM manipulation</p>
</div>
2)in route I write
('someroute',{
templateUrl : "mytemplate",
controller : "myctrl"
});
mytemplate:
<div>
<p>something for dom manipulation</p>
</div>
3)
<div ng-include="mytemplate" ng-controller="myctrl"></div>
with template being same as above
The controllers in all the above scenarios are same, and in all of them I am just trying to select p tag of DOM by writing angular.element('p'). But this seems inconsistent. It works very well in 2nd scenario, it never works in 3rd scenario and I am not sure about 1st sccenario. Can someone explain which method is best for dom selection/manipulation, as I have to add a class to this 'p' tag on hover.
I am not understanding which gets initialized first- controller or partial?
Manipulating DOM inside controllers is discouraged. Quote from Best Practice - Dom Manipulations:
Dom Manipulations should not exist in controllers, services or anywhere else but in directives.
If you only need to style elements on hover, using the p:hover CSS selector would be enough without touching the DOM. ng-class and ng-mouseover can help you if you really want the class.
For more complex scenarios, you may want to write your own directive. You can check the article above for a guide to do that.
Load order from the first case: HTML first. Directives like ngController are loaded after parsing the HTML. Therefore the HTML already exists when the controller is loaded.
Load order for the second case: I'm not sure about it. You may check documentation for ngRoute or uiRouter depending on the router you are using.
Execution order for the third case: Controller first. The directive ngController have higher priority than the ngInclude directive. Therefore, the controller is loaded first.
Quote from ngController documentation :
This directive executes at priority level 500.
Quote from ngInclude documentation :
This directive executes at priority level 400.
I am using a third party lib with the following custom attribute directive:
angular.directive('snapDrawer', function () {
'use strict';
return {
restrict: 'AE',
...
So if the attribute "snap-drawer" is found in an HTML element the directive implementation has a match and fires, for example:
<div snap-drawer></div>
I am using Angular 1.3 which has an "AllOrNothing" approach to ng-attr where if the value conditional is undefined then the attribute does not render like so:
<div ng-attr-snap-drawer="{{data.addSnapDrawer}}"></div>
100% fact this works, the value of data.addSnapDrawer in my controller is undefined and the snap-drawer attr does not render in the DOM
I have verified that Angular 1.3 does this AllOrNothing approach with ng-attr here: What is the best way to conditionally apply attributes in Angular? (take a look at Mathew Foscarini's answer)
BUT what does render in the DOM is:
<div ng-attr-snap-drawer="{{data.addSnapDrawer}}" class="snap-drawer snap-drawer-left" style=""></div>
So, unbelievably, the angular.directive('snapDrawer') is matching to "ng-attr-snap-drawer". How can this be, I am really shocked that AngularJS, in all its glory, has a bug like this.
I cannot find anything online. I cannot set snap-drawer="false" I need it to not appear in the DOM, which I achieved by upgrading from Angular 1.2 to 1.3.
This is old, but I stumbled upon something very similar. https://github.com/angular/angular.js/issues/16441 - angular authors made it this way.
You need to devise a different way (depending on your usecase) to conditionally apply directives (e.g. use ng-switch and have two versions of the HTML; one with the directive and one without, or have a terminal directive with high priority that evaluates the expression during the linking phase, applies the necessary directive(s) and compiles the element).
I wrote an attribute restricted Angular directive (restrict:'a') that adds features to textarea. It makes no sense to apply it to any other type of element.
Adding a if (element.nodeName == 'TEXTAREA') { is really dirty and unreliable.
I tried to add require: textarea to it but it does not work and I get this error: Error: No controller: textarea
Question: Is there any cleaner way to properly apply this restriction?
EDIT: Additional constraint following the first answer.
I want to avoid using a template in this directive as I want to be able to use several directive of this type. Here is an example of what I'd like:
<textarea splittable shared mergeable></textarea>
When using your own directive (eg my-textarea) with restrict: 'E', replace: true, any additional attributes will get carried over to the root-element of the directive, even other attribute directives. So:
<my-textarea splittable class="foobar"></my-textarea>
could be rendered as:
<textarea splittable="" class="foobar"></textarea>
with splittable being executed.
demo: http://jsfiddle.net/LMq3M/
So I think using your own directive is realy the cleanest way to handle this.
In my opinion there is no need to add such controls as they just tend to add complex code when the real issue is human error.
Just document what the purpose and usage is for the directive.
The idea is you give your directive a unique name, like myDirective and you can use it in HTML as such.
<body>
<my-directive></my-directive>
</body>
The directive will replace the tag with the template you provided in the directive controller. Which could be in your case a simple textarea element with added properties.
I recommend watching this video to clearly grasp the concept of directives.
http://www.youtube.com/watch?v=xoIHkM4KpHM