Transclude:'element' demystified

Transclusion is no doubt a very confusing topic in AngularJS. It has two ways of implmentation :

1) transclude: 'true'
2) transclude: 'element'

as far as transclude: 'true' goes, one can grasp it with little effort but transclude: 'element' seems like a lot of work .

So, what thus transclude:'element' do ?

It transcludes the whole element ,i.e, it copies the content inside the directive as well as the directive tag  itself and places one or more copies of it with the correct scope .

The transclusion is achieved via transclusion function unlike the more simpler ng-transclude in case of transclude: 'true' .
For a quick review of transclude:'true' , to achieve transclusion , we included <ng-transclude> wherever we wanted our element to appear inside the 'template' property like :

transclude: 'true',
template: '<some tags here><div ng-transclude><some tags here>',


but when we do  transclude: 'element', we cannot use a template , so we can't  ng-transclude it , so instead, as i just mentioned , we will use transclusion function . Transclusion function is simply a link function , which is returned after compiling the transcluded elements .
To give you an overview of how transclusion is achieved by the browser, the flow is as follows :

var elementsToTransclude = directiveElement.contents();
directiveElement.html(' ');
var transcludeFn= $compile(elementsToTransclude);


So, basically , we are getting the contents of the element containing the directive which has transclusion enabled in the first line and storing them in a variable . Then we are removing the contents  of the element from the DOM . In the third line , we are compiling the variable which has the contents of the element and producing the transclusion function (transcludeFn) .

This function is given as the fifth parameter of 'link' function . It was earlier used in 'compile' function as well but has become obsolete now .

link : function(scope, element, attributes, controller, transcludeFn){}

This Transclude function can accept a scope and a call back function , and this function returns a  clone of the transcluded element instead of the original element  like :

transcludeFn(scope,function(clone){});

This callback function is synchronous not asynchronous . 
Now, its important to understand that this transcludeFn places the transcluded element and the location where you want to place can be achieved by Jquery style DOM traversal and modification . Like if i want to put the transcluded element after the 'element' , which is the second parameter of the link function , i can simply do :

element.after(transcludeFn());


Or i can attach a clone of the transcluded element to the DOM  :

transcludeFn(function(clone){
element.after(clone);
})


In the above two examples of transclusion, the transcluded elements get an inherited scope from the parent scope . Now there is an element of confusion here . The parent scope i am referring to is the original scope not the scope of the directive which has transclusion enabled.
  Let me give an example :
suppose i  have done transclude :element for my custom directive

note that i have isolated the scope of the directive , so in normal sense , anything inside this directive should not inherit from the parent controller scope

app.js :

var app=angular.module('mainModule',[]);
app.controller('mainController',function($scope){
 $scope.Var='Hello I am you father';
});
app.directive('customDirective',function(){
return {
        restrict: 'A',
        scope: {},
        transclude: 'element',
        link: function(scope,element,attrs,controller,transcludeFn){
        transcludeFn(function(clone){
        element.after(clone);
      });
}
}
});


and in my html

index.html:

    <body ng-app="mainModule">
     <div ng-controller="mainController">
       Fathers scope is : {{$id}} 
      <div custom-directive>Hello People Socpe id is : {{$id}} and i am inherited from:                                 {{$parent.$id}} {{Var}}</div>
     </div>
     </body>

{{$id}} is a very neat way to get  the scope id .
{{$parent.$id}} gives the scope id of the parent scope .
i have used {{Var }} in the transcluded element , which is defined only in the parent controller .

So , now in my browser,  i can see :

Fathers scope is : 2
Hello People scope id is: 4 and i am inherited from : 2 Hello i am your father .

Did you see that , did you see that ? That guy is inheriting . 'Var' is being fetched from the parent controller 'mainController' , even though the directive has isolate scope . This behaviour of transclude element is desirable to avoid conflicts between scopes,scope leaking .

Now getting back to the features of transcludeFn , though the default scope of transcluded elements is like the one i mentioned above, you can also provide your own custom scope to it like :

transcludeFn(scope,function(clone){
});


so in the above case, i gave the first parameter as scope, which is also the first parameter of the link function , so you guessed it right , we are assigning it the scope of the custom directive . And since the directive has isolate scope, it will not read any properties from the parent scope and that {{Var}} should not evaluate , since it is not visible now to the transcluded element scope . Right?  Yes ofcourse .

Our view is now :


Fathers scope is : 2
Hello People scope id is: 3 and i am inherited from : 2


Dont get confused by that line 'and i am inherited from : 2', since i used $parent in that and you can access the immediate parent in isolate scopes through $parent , which may sound confusing to some .

Now, lets talk something about the compiling and linking of transcludeFn .

when you do something like :

transcludeFn(scope, function(clone){
element.after(clone) // this is compiled but not linked yet 
}) 


and when you do something like :

var transcluded=transcludeFn();
element.after(transluded) // this is compiled and linked .


So, what is its importance . One is that, if you want to clone the transcluded element several times , like in the case of ng-repeat , you hve to insert the clones into html before linking . They will have individual scopes of their own , again like in ng-repeat ..

Lets further extend our app.js above

var app=angular.module('mainModule',[]);
app.controller('mainController',function($scope){
  $scope.Var='Hello I am you father';
});
app.directive('customDirective',function(){
  return {
    restrict:'A',
    scope:{},     
    transclude: 'element',
    link: function(scope,element,attrs,controller,transcludeFn){
      for (var i = 5; i >= 0; i--) {
      trscluded=transcludeFn(function(clone){
         element.after(clone);
      });
    }
}
}
});

Here you can see we are doing five iterations of the for loop and embedding a clone in our html for each iteration . every clone has its own scope id.

Our view now :

Fathers scope is :2
Hello People Socpe id is : 8 and i am inherited from: 2 Hello I am you father
Hello People Socpe id is : 7 and i am inherited from: 2 Hello I am you father
Hello People Socpe id is : 6 and i am inherited from: 2 Hello I am you father
Hello People Socpe id is : 5 and i am inherited from: 2 Hello I am you father
Hello People Socpe id is : 4 and i am inherited from: 2 Hello I am you father

This happens because we are inserting the html before linking, we wont be able to add clones, if we have already  linked the element, like , if we do

var app=angular.module('mainModule',[]);
app.controller('mainController',function($scope){
  $scope.Var='Hello I am you father';
});
app.directive('customDirective',function(){
  return {
    restrict:'A',
    scope:{},     
    transclude: 'element',
    link: function(scope,element,attrs,controller,transcludeFn){
      for (var i = 5; i >= 0; i--) {
         element.after(transcludeFn());
      }
}
}
});

we will only get a single element in our html :

Our view now :

Fathers scope is :2
Hello People Socpe id is : 8 and i am inherited from: 2 Hello I am you father 

There are many complex implementations of transclde: 'element'  , but as an introduction and understanding to transclude: 'element' , this can get you going .
Cheers .

What is a prototype based language in terms of javascript

Today i was going through the basics and since switching from a class based language to a prototype based language can be a a little tricky , i will leave this post here.

Now. What the wiki says :

Prototype-based programming is a style of object-oriented programming in which behaviour reuse (known as inheritance) is performed via a process of cloning existing objects that serve as prototypes. This model can also be known as prototypalprototype-oriented, classless, or instance-based programming. Delegation is the language feature that supports prototype-based programming.


So , what we can understand that in a prototype based language , objects are created by cloning existing objects(prototypes)  and adding your own properties to it .Actually, in javascript, when  we are creating an object, we are always creating a clone of an existing object .
var o= {a:1,b:2};

Now, this object inherits from a base object in javascript called Object.prototype which has its own methods and properties . Infact , this object  also inherits from the topmost base  object - 'null' , yes , null ( i am not sure if i should call this an object or not , but i like to think it this way for consistency in the model ) .

So, if you give console.log(o.hasOwnProperty) , you will see a function definition in the console :
function hasOwnProperty() { [native code] }


which means that you have inherited properties from Object.prototype and hasOwnProperty is one of its methods .

 So , basically :
0---> Object.prototype -----> null 


Similarly Arrays inherit from Array.prototype and functions inherit from function.prototype which have their own methods and proprties  and both of these inherit from null . 

So , what if we want to create an object from scratch without inheriting from anything. 
Yes, you guessed it right we will inherit from null and give our own properties to it . 

var cleanObject=Object.create(null);

cleanObject.pi=3.14;

So you can see cloning(inheritance) is going on everywhere . And unlike class based language , there is no separate object definition and instance ,i.e, usually in class based languages, object definition does not occupy memory but in javascript they too occupy memory . 
Suppose you  create a function , and it is both an object definition and instance . like :
function hello(){
console.log('Hello World');
}
hello() // working as an instance 
var hi = new hello() // working as an object definition


Which means that there is no explicit class , objects inherit directly from other objects through properties, called prototypes in javascript . So if you define and attach anything to the prototype property of an object , then it will be visible to all the objects inheriting from that object . And if you change that definition later in any object , then it will be visible to all objects . like in this example :

var Person = function() {

  this.canTalk = true;

};

Person.prototype.greet = function() {

  if (this.canTalk) {

    console.log('Hi, I am ' + this.name);

  }

};

var Employee = function(name, title) {

  Person.call(this);

  this.name = name;

  this.title = title;

};

Employee.prototype = Object.create(Person.prototype);

Employee.prototype.constructor = Person;

var bob = new Employee('Bob', 'Builder');

var rg = new Employee('Red Green', 'Handyman');

bob.greet();

rg.greet();

Person.prototype.greet=function(){

  console.log('Just for testing');

}

bob.greet();

rg.greet();

So in the above example, we change the greet function, and the change is reflected across all instaces .

And yaa about that last line 'Delegation is the language feature that supports prototype-based programming.' , if you guys are wondering what delegation is , then to sum it up , it is similar to classical inheritance but with much lighter memory footprint invloved and entangles the overly complex hierarchies . Means, you can call any function in context of an instance of another function without considering the hierarchies involved . It simplies inheritance actually . Delegation is primarily achieved in javascript by 'call' and 'apply' .You can use 'call' and 'apply' to call any function inside an instance of a function . 
If you want to learn more about delegation , then you can follow this article . 
So thats all you need to get the feel of a prototype based language . 
Cheers