Hiding containing element for angular directive from within directive - javascript

Given the following situation with one parent directive and two child directives:
<div pane-list>
<div calc-pane></div>
<div user-pane></div>
</div>
I can use replace: true on the child directives, and then in the top level of their template <div ng-show="showPane">. This allows me to control whether or not the pane is showing from within the directives I use inside this list of panes - without replying on the parent pane-list directive having anything to do with it or needing to share scope. With replace: true I can use these panes inside any kind of parent element with no worries.
Apparently replace is being removed, so what can I do instead? I don't see any ways that aren't considerably more complicated. If I can't replace the pane element, I don't see a simple way to be able to show/hide it from within the directive.
Anybody have any ideas?

Related

AngularJS Directive - Multiple directives same name

Let's say I have multiple directives with the same name "parent-elem" (on each page I can have a different number of these directives - dynamic number)
<div ng-app="app">
<div parent-elem></div>
<div parent-elem></div>
<div parent-elem></div>
</div>
Is there a way to know (inside the link function) AngularJS finished render all the directives with the same name on the page?
Inside the directive link function - how do I know this directive is the last rendered?
Note: Not using a ng-repeat
You should have had written, same directive, multiple times :P
Now, that totally depends on your directive, how you make it.
It can keep the counter in a service or rootScope may be whenever it is initialized.
If you are using ng-repeat which you should in this case, you have a bool $last that can tell you if the element rendered is last or not, which you can pass to the directive via any attribute.

Angular.js $scope and dom element

How does angular keep track of which $scope is related to which element? I have a few theories:
angular element keeps scope object as property
angular saves each scope in cache with the relationship with element
angular searches each ng-scope, and magically find element
For example, I have an element with $scope, and I want to change dom hierarchy of this element (moving to outside of the outer controller). How is scope affected by this action?
If you have an angular app, and your HTML looks something like this:
<div ng-controller="OuterController">
...
<div ng-controller="InnerController">
<div id="wrapper">
<span>An Element</span>
</div>
</div>
</div>
And you move the <span> out of the #wrapper div, it's still within the context of both OuterController and InnerController. However, if you move it up to where the ... is, only the OuterController's context applies.
Each controller has its own context, and that context extends down into all child-elements recursively, even if a new controller is present, at which point, both controllers are in-scope.
This is true whether the element is moved dynamically with Javascript or otherwise. Angular keeps track of most context internally.

How to dynamically nest a directive element in-between existing parent and child directive elements?

Background:
I am using a custom CMS where I have limited access to the code base. So, in a few cases I plan to make some DOM manipulations using JavaScript.
Problem:
I have a container directive and the container has plain old HTML items, but am not able to mark the items as being directives from the server side. Also, the plain old HTML items contain sub-content that are directives.
Example:
Here is the before:
DIV[container-directive]
DIV.some-item-in-html
DIV[some-directive-in-the-content]
DIV.some-item-in-html
DIV[some-directive-in-the-content]
...
Here is what the DOM should look like afterwards:
DIV[container-directive]
DIV[container-item] <-- This is what needs to be inserted
DIV.some-item-in-html
DIV[some-directive-in-the-content]
DIV[container-item] <-- This is what needs to be inserted
DIV.some-item-in-html
DIV[some-directive-in-the-content]
...
Question:
Does anyone have suggestions on the best approach to injecting DOM element that are directives in-between a nesting of directives using JavaScript?
Some thoughts:
I think manipulate the DOM in advance of the compilation by angular, but I wonder if there is a way to do this within Angular's framework.
Another option is from the container directive's post-linking function, I could wrap the HTML items in directive elements called "container-item" and then $compile the items manually. So, I tried this but I get an error related to the items already having directives inside with transcluded content. Something about the "ngTransclude" being unexpected. I think this is related to the inner directives already having been processed.
I would go with your first option and manipulate the DOM ahead of angular compilation.
You can do this within a directive that contains the elements that you want to manipulate.
For example:
app.directive('body', function() {
return {
restrict: 'E',
compile: function(element, attr) {
// find the inner element and wrap it
$('.some-item-in-html', element).wrap('<div class="container"></div>');
}
}
});
Parent directives are always compiled before child directives, so you can change the DOM of the children within the compile property, and not have to worry about recompiling or re-linking directives.
[EDIT]
Thanks to Biagio for the following edit.
This method shouldn't be used with a directive with a template because the element would be assigned to the template and not the child elements.
Another alternative is doing the DOM manipulation in a function that runs at the start of the angular lifecycle.
For example:
app.run(function(){
// find the inner element and wrap it
$('.some-item-in-html').wrap('<div class="container"></div>');
});

How to manipulate DOM after ng-show in Angularjs?

I'm new to angularjs. I'm using angularjs version 1.2.13.
I've come upon a scenario where after ng-show displays my DIV, I need to manipulate the DOM in order to realign some DIV columns. I cannot realign my DIVs if they are hidden.
HTML looks like this:
<div ng-controller="MyController" ng-show="IsThisShown">
<div class="column">1</div>
<div class="column">2</div>
<div class="column">3</div>
</div>
I think the way to go would be to create a "realign" directive such as:
<div class="column" realign>1</div>
<div class="column" realign>2</div>
<div class="column" realign>3</div>
But I'm not sure how I would make the directive trigger only when the parent DIV is shown (through the ng-show directive).
Any ideas ?
Thanks appreciated!
Here's a little more code:
module.controller("MyController", function($scope, FormState){
$scope.$watch(function(){ return FormState.showGrid; }, function(newVal, oldVal){
//At this point in time, right here, the DOM has not been updated...
$scope.IsThisShown = newVal;
//At this point in time, right here the DOM has still not been updated...
//the DOM gets updated when the function exists
});
});
You have a few different options.
One option you can explore is using an isolate scope with your realign directive.
See this example here:
http://plnkr.co/edit/lO2U4GZcEm4K1qGLpsFV
You don't have to use the isolate scope as Angular scope is prototypical by nature (though with a slight gotcha with regards to primitives), but I figured I'd throw this into the example so you can see isolate scope in action. In this example I'm using an isolate scope with an execute expression.
Just a random example that builds on your description by randomly repositioning some div's after the parent is shown.
Hopefully that helps.
There are a lot of ways, but the way that immediately comes to mind is:
<div ng-controller="MyController" ng-show="IsThisShown">
<div class="column" realign="IsThisShown">1</div>
<div class="column" realign="IsThisShown">2</div>
<div class="column" realign="IsThisShown">3</div>
</div>
And have your new directive observe its argument and do the realignment when it goes true.
The other answers are good (and standard), but tie the realign directive to being shown/hidden by that variable. If, for example, there are two nested ng-show's, this would break down. In my opinion, a better solution is to create an on-show directive, with the following scope:
scope: { 'onShow' : '&' }
And within the link function, set up a $scope.$watch as follows:
$scope.$watch(
function() { return $element.hasClass('ng-hide'); },
function(newVal, oldVal) { /* execute onShow here if newVal === false */ }
);
You could also (and I don't recommend this) change ng-show to ng-if. ng-if removes and adds the elements from the DOM, instead of just hiding them. In that case, the link function fires every time the element reappears.

how to append div into one div using angularjs

<div data-ng-controller="maincontrol">
<div class="main">
</div>
<button data-ng-click="submit()">click</button>
</div>
when i click on click button i want to append one div within main div . i want to append one new div (dynamically)for each and every click .also i want to find whether children div exist or not .
i will do like this in jquery
$('main').append();
i will pass div within append();
but how to do by using angular..js ?
Using a directive could be a solution, but it's still too close to jQuery. When you play with Angular, you have to think differently.
jQuery is procedural.
1- I am finding an element in the dom
2- I am doing some stuff
3- I am adding, removing, updating elements in the dom
angular is declarative
You define your data
You define how your data should be displayed (using ng-repeat, ng-class, etc..)
then..
when you are playing with your data, the view is automatically updating.
If you want to play correctly with angular you should maybe do something like:
Template:
<div class="main">
<div ng-repeat="stuff in stuffs"><h1>{{stuff.title}}</h1> <p>{{stuff.content}}</p></div>
</div>
Controller:
function MainCtrl() {
$scope.stuffs = [];
$scope.submit = function() {
$scope.stuffs.push({title: 'Hello', content: 'world'});
}
}
It's generally best to create a directive for DOM manipulation ( many other uses for directives also).
Within a directive you have access to the angular.element . If jQuery is installed before angular.js in page, this is a jQuery object, otherwise it is a jqLite object that has many jQUery compatible methods.
Very simple example:
<button data-ng-click="submit()" my-directive>click</button>
app.directive('myDirective',function(){
return function(scope, element, attrs){
element.click(function(){
element.parent().find('.main').append('<div>Some text</div>')
})
}
})
Read up on directives and angular.element

Categories