I've <start-login></start-login> and the directive
app.directive('startLogin', function(){
return {
restrict: 'E',
templateUrl: 'startlogin.html',
controller: 'LoginController'
}
});
I need to execute the directive ONLY after a check, like this:
var checkLogin = false //variable
if(checkLogin){
//do something and DON'T EXECUTE DIRECTIVE
}else{
//EXECUTE DIRECTIVE
How can I do this?
I've also jQuery in my project..
You could use the ng-if directive, like so:
<start-login ng-if="expression">
ng-if will not render the content of the tag if the expression is false.
Then in your controller you simply set expression to true when you want the tag to be visible. In your example you could use the variable checkLogin instead of expression of course.
There's also a big difference between using ng-if and ng-show. The user might not experience it, since the actual difference is that ng-show hides the content and ng-if doesn't render it at all. If we inspect the DOM between the two you will see that they look similar to the code below in the different states:
When expression is true:
<start-login ng-show="expression"></start-login>
<start-login ng-if="expression"></start-login>
When expression is false:
<start-login ng-show="expression" class="ng-hide"></start-login>
<!-- ngIf: start-login -->
This is the big difference. ng-if completely removes the element and only appends a comment to the DOM. If you use ng-show (or ng-hide), angular appends a class to the element. The class is declared as
.ng-hide { display: none; }
which only instructs the web browser to not display the element in the layout. The element is still "rendered" though, or executed might be a better word, which is the main difference here. This can have a real impact when loading the page, specifically if the content in the ng-if element loads data from the server for instance. It also means that if your directive modifies the DOM and adds sensitive information, then you should use ng-if!
I'd probably go with ng-if:
<start-login ng-if="checkLogin"> ... </start-login>
The ngIf directive removes or recreates a portion of the DOM tree based on an {expression}. If the expression assigned to ngIf evaluates to a false value then the element is removed from the DOM, otherwise a clone of the element is reinserted into the DOM.
https://docs.angularjs.org/api/ng/directive/ngIf
Of course you can use ngIf or ngShow/ngHide directives,but there is another way to do that.You can use angular.value(...).As you define a global value of that module,inject it in you directive,then before creating directive,you can check your value,then do whatever you want.
Related
I am developing a custom directive and now I need to handle ng-if. This is easy enough when ng-if is on the directive it self. However when ng-if is on an enclosing container element my compile function fails with run time errors.
Question is: what is the best and most efficient way to know, inside the compile function of a directive, that the directive is enclosed within a container with ng-if is false OR an expression that evaluates to false.
For example:
<div ng-if="false">
<my-directive></my-directive>
</div>
And another example:
<div ng-if="somescopeValue > 300">
<my-directive></my-directive>
</div>
Maybe the answer is using jquery to traverse the dom and find a parent with
an ng-if attribute but I was wondering if there is another more "angular" way of doing this.
Your directive shouldn't rely on knowing whether it is encapsulated in a ng-if expression. That breaks the principle of 'Separation of Concerns' and deteriorates code re-use. Consider redesigning your custom directive in such a way that it needs not be aware of its host elements, in the same fashion that all components (should) work.
If you are using same scope as parent controller or directive then you are able to access same variable in your directive(here my-directive) also. If this is not a case then you need to write code to access parent element in link function of my-directive. You will get directive element in link function as a parameter.
I'm not sure how the error happens, because when your directive is inside ng-if="false", your directive won't get called at all - all compile, link and controller function in the directive will only run as soon as your directive gets added in DOM.
Perhaps your error can be solved by initializing something in case your directive is not added.
I need to conditionally apply ng-disabled to an element that is enclosed by a controller but does not exists at time of original compile. It is created later on by an AJAX callback and needs to be enabled/disabled based on certain conditions. I guess it needs a directive, but how do I go about it?
I need to use ng-disabled and no other solution as it is well handled by IE<11, which do not support pointer-events.
The real code is too complicated to be quoted here, but let me rephrase the problem.
A jQuery lib does something like:
$.get(url, function(){
$('<a class="btn"/>').appendTo(myDiv)
});
myDiv is within an angular controller. The <a/> element does not exist at time of compilation/directive linkage. Right after it gets appended, I should call some code to test and apply ng-disabled condition. Should it be a directive or a watch?
You could create a directive with an ngIf (so that it's created just when ngIf condition equals true. You can enable this condition after the response returns). Then in the link function you could:
link: function( scope, element, attrs ){
element.removeAttr("name-of-the-directive");
element.attrs("ng-disabled", "{{myExpression}}");
$compile( element)(scope);
}
The line element.removeAttr("name-of-the-directive"); is necessary to avoid infinite compiling loop.
When you're inserting code into the DOM manually, you need to compile it and link it to your scope first.
If your use-case allows it, you could try using ng-bind-html in your template and then just put the loaded code into a $scope property without needing to $compile it yourself.
It's probably the best to illustrate my question with an example.
Here is a template snippet:
<div class="title">{{action}} Location</div>
Double curly markup tells AngularJS to evaluate action against the current scope AND to create a data-binding to action.
Is there a way to tell AngularJS to evaluate action once and be done (ie. I don't need the data-binding/watch)?
I cannot find the direct support of interporate once feature in Angular.
But you can easily work around it by using separate variable which gets
copied from action once and never changes afterwards.
In your controller:
$scope.action0 = action;
in your template:
<div class="title">{{action0}} Location</div>
EDIT : Another way is to define a directive which interpolates once
and leave it alone.
http://plnkr.co/edit/6Ul1QgqhNH0bqK2af2Jo?p=preview
js:
app.directive('staticBind', function(){
return function(scope, elem, attrs) {
elem.text( scope[ attrs.staticBind ]);
};
});
template:
<span static-bind="variable"></span>
I have found Pasvaz's bindonce module, another solution that suits better for my need, from the Angular mailing list.
UPDATE 10/27/2014: Starting from v1.3, AngularJS core supports one-time binding
I faced the same problem. I want to evaluate the expression but i dont want to display it. so i found one solution, just put your expression that you want to evaluate in ng-hide div and set ng-hide to false like
<div ng-hide="true">{{your expression here}}</div>
it will execute the expression without displaying the content
Use angular.copy when you set the scope to be used in that template. Angular wont watch a var set to a copy. angular.copy is used to store the value of the current value of a watchExpression for later comparison.
I know that even if ngShow evaluates to false, it still performs dirty checking inside the directive.
So does ngShow (like ng-show=false):
compose the DOM inside ngShow (since it has to do $compile) and then hides/removes the contents, or
only performs dirty checking without the cost of creating DOM elements?
ng-show will only set the elements to display: none. So they will still be in the DOM and still be dirty checked by angular.
Try using something like ng-switch for actually removing elements from the DOM. http://docs.angularjs.org/api/ng.directive:ngSwitch
Angular.js doesn't create any DOM nodes during the compilation. It lets the browser build the DOM then simply goes through it and collect the directives.
So if the nodes are in your templates, they will indeed be created, but by the browser, not Angular.
I have a control that should display breadcrumb navigation. It needs data (route & title) to display the navigation correctly. Data is taken from scope and used inside a directive.
What causes my problems is that I use a localization directive in the control that should translate the title. And this localization directive is called even when expression in ng-show is evaluated to false. Then the translation in localization directive ends with exception because it tries to translate incorrect string (see 'localize' directive in http://jsfiddle.net/F97wn/7/).
That seems quite weird. I would expect that if something sets whether the inner content should be visible or hidden, then it is evaluated first and then the inner content..
Ok, then I found that ng-show only sets some css attribute, so it's quite useless for me.
The question is: How should I solve the problem - what to use instead of the ng-show?
An example is at http://jsfiddle.net/F97wn/7/
You could use ngSwitch instead with the on part set to "toshow()" and the inner ng-switch-when="true" part to have your custom directive inside that area. This will then not execute the custom directive if the value of toshow is not true.
If the directive is throwing an exception, more information should probably be passed to the directive, in one of the following ways, so that the directive can decide if it has the required information to do what it needs to do:
attribute data -- e.g., localize="..." show-me="..."
something defined on the scope associated with ctrl -- e.g., $scope.showMe. The directive scope will have access to this property as scope.showMe, based on the way you currently have the directive defined.
or inject a service (that has the data) into the directive -- e.g., directive('localize', function(myShowMeService) { ... }
You might also want to look into <ng-if>. The ngIf directive removes and recreates a portion of the DOM tree (HTML) conditionally based on "falsy" and "truthy" values evaluated within an expression. It might be more intuitive than <ng-show> for your needs.
However, it is currently only available in the unstable version of AngularJS. If you can use that version of AngularJS you can find more information about it here.