how to get compiled element in custom directive compile function - angularjs

I have used angular JS custom directive compile function, in that I am not able to get the compiled HTML element. I am getting-
<div id="test_{{value}}" modulename="test_{{value}}"></div>
How to get the compiled html element in Post link method?
like this,
<div id="test_1" modulename="test_1"></div>
compile function code as follows,
module.directive("custom", ['$compile', function ($compile) {
return {
restrict: 'CEA',
transclude:true,
compile: function(el) {
if (settings.require && settings.require.length) {
return function(scope, el) {
$compile(el)(scope);
}
}
return {
pre: function(scope, element, attrs, ctrls) {
},
post: function(scope, element, attrs, ctrls) {
//here need to get compiled html element
}
}
}
};
}
Thanks in advance

Related

Unable to pass interpolated value during transclusion in directives

I am creating an email directive as below,
angular.module('app')
.directive('email', function () {
return {
restrict: 'EA',
transclude: true,
template: '{{email}}',
link: function (scope, element, attrs, ctrl, transclude) {
transclude(scope, function (clone) {
scope.email = clone.text();
});
}
};
});
I am using it in the HTML as below,
<email>{{emailId}}</email>
However, I am unable to pass the interpolated value of emailId inside the directive. The output of the directive ends up as,
{{emailId}}
How do we pass the actual interpolated value inside the directive?
Plnkr - http://plnkr.co/edit/AeBfp3VayKihygelKr9C?p=preview
To pass a variable to directive scope, simply use an attribute:
angular.module('app')
.directive('email', function () {
return {
restrict: 'EA',
̶t̶r̶a̶n̶s̶c̶l̶u̶d̶e̶:̶ ̶t̶r̶u̶e̶,̶
template: '{{email}}',
link: function (scope, element, attrs, ctrl, transclude) {
//transclude(scope, function (clone) {
// scope.email = clone.text();
//});
scope.email = scope.$eval(attrs.addr);
//OR
scope.$watch(attrs.addr, function(value) {
scope.email = value;
});
}
};
});
Usage:
<̶e̶m̶a̶i̶l̶>̶{̶{̶e̶m̶a̶i̶l̶I̶d̶}̶}̶<̶/̶e̶m̶a̶i̶l̶>̶
<email addr="emailId"></email>
There is no need to use transclusion to evaluate an Angular Expression.
For more information, see
AngularJS scope.$eval API Reference
AngularJS scope.$watch API Reference
You Just have to add Only on directive template ng-transclude on your element
here is the code
angular.module('app')
.directive('email', function () {
return {
restrict: 'EA',
transclude: true,
template: '<a href="{{email}}" ng-transclude>{{email}}</a>',
link: function (scope, element, attrs, ctrl, transclude) {
}
};
});
here is the link
Plunker http://next.plnkr.co/edit/SY3ih9NwAqz7ZhZg?open=lib%2Fscript.js&preview

I can pass a scope variable into a directive's link function, but not the compile function, angular

I'm using ng-repeat and I need to pass a scope variable into a directive's compile function. I know how to do it with the link function, but not the compile function.
My html looks like:
<div ng-repeat="item in chapter.main">
<block type="item.type"></block>
</div>
Let's say item.type="blah" no matter the item.
Then this link function works fine
app.directive('block', function() {
return {
restrict: 'E',
link: function(scope, element, attributes){
scope.$watch(attributes.type, function(value){
console.log(value); //will output "blah" which is correct
});
}
}
});
But I can't do the same with compile?
app.directive('block', function() {
return {
restrict: 'E',
compile: function(element, attrs, scope) {
scope.$watch(attrs.type, function(value){
console.log(value);
});
}
}
});
The error I get is "cannot read property $watch of undefined"..
This is how I'd like my directive to look like:
app.directive('block', function() {
return {
restrict: 'E',
compile: function(element, attrs) {
element.append('<div ng-include="\'{{type}}-template.html\'"></div>');
//or element.append('<div ng-include="\'{' + attrs.type + '}-template.html\'"></div>');
//except the above won't interpret attr.type as a variable, just as the literal string 'item.type'
}
}
});
The compile function doesn't have scope as one it's parameter.
function compile(tElement, tAttrs, transclude) { ... }
NOTE: transclude is deprecated in the latest version of Angular.
Is there any reason you don't want to use link?
From the DOC
The compile function deals with transforming the template DOM. Since most directives do not do template transformation, it is not used often. The compile function takes the following arguments:
tElement - template element - The element where the directive has been declared. It is safe to do template transformation on the element and child elements only.
tAttrs - template attributes - Normalized list of attributes declared on this element shared between all directive compile functions.
transclude - [DEPRECATED!] A transclude linking function: function(scope, cloneLinkingFn)
UPDATE
To access the scope from inside compile function, you need to have either a preLink or postLink function. In your case, you need only the postLink function. So this ...
compile: function compile(tElement, tAttrs, transclude) {
return function postLink(scope, element, attrs) { ... }
},
PROPOSED SOLUTION Might not be exact but should help you on your way.
html
<div ng-app="myApp" ng-controller="app">
<block type="item.type"></block>
</div>
JS (Controller + Directive)
var myApp = angular.module('myApp', []);
myApp.controller('app', function ($scope, $http) {
$scope.item = {
type: 'someTmpl'
};
}).directive('block', ['$compile', function ($compile) {
return {
restrict: 'AE',
transclude: true,
scope: {
type: '='
},
compile: function (element, attrs) {
return function (scope, element, attrs) {
var tmpl;
tmpl = scope.type + '-template.html';
console.log(tmpl);
element.append('<div ng-include=' + tmpl + '></div>');
$compile(element.contents())(scope);
};
}
};
}]);

Get HTML inside directive declaration

I have a directive that can contain some HTML inside it. How can I get it? I have tried link and compile but I am getting the HTML that is defined in the template. Here is my view:
<my-directive ng-model="ctrl.SomeField">
<p> This is the HTML I want! <p>
</my-directive>
Here is my directive:
return {
restrict: 'E',
scope: {
ngModel: "="
},
template: "<p>This is the HTML that is being returned from compile and link!</p>" +
"<p>This is not the HTML that I want!</p>"
link: {
pre: function preLink(scope, element, attrs) {
var html = element.html(); //returns the html in the directive template
},
post: function postLink(scope, element, attrs) {
var html = element.html(); //returns the html in the directive template
}
},
compile: function(element, attrs){
var html = element.html(); //returns the html in the directive template
}
}
How do I get the HTML from my view and not from my directive template?
Edit: Here is an example - http://plnkr.co/edit/z6gFOrGG01jKoKwISHcW?p=preview
Here is my solution! http://plnkr.co/edit/OlRyBN1I0jCkAREIKVeC?p=preview. Basically I just needed to use another directive to do some fancy transclusion stuff in a link step.
Here is the directive:
function returnFn() {
return {
link: {
pre: function (scope, element, attr, ctrl, transclude) {
if (transclude) {
transclude(scope, function (clone) {
element.append(clone);
});
}
}
}
}
}
return [returnFn];

get initial value of ngModel in directive

I have a directive that requires ngModel. The directive modifies the value stored in ngModel (it implements in-place editing of text). Inside my link function I need to get the value of ngModel before it has been changed.
I tried looking at ngModel.$viewValue, and ngModel.$modelValue. They both eventually get the model's contents, but in the beginning of the directive's life-cycle they get the raw unprocessed angular expression such as {{user.name}}. And I cannot find a way to determine
when the expression has been processed.
Any ideas?
directive('test', function() {
return {
restrict: 'A',
require: 'ngModel',
link: function(scope, element, attrs, ngModel) {
}
};
})
Use the $parse service:
app.directive('test', function($parse) {
return {
link: function (scope, element, attrs) {
var modelGetter = $parse(attrs.ngModel);
var initialValue = modelGetter(scope);
}
};
});
Or:
app.directive('test', function($parse) {
return {
compile: function compile(tElement, tAttrs) {
var modelGetter = $parse(tAttrs.ngModel);
return function postLink(scope, element) {
var initialValue = modelGetter(scope);
};
}
};
});
Demo: http://plnkr.co/edit/EfXbjBsbJbxmqrm0gSo0?p=preview

Directives doesn't translate attributes after element replace with jQuery

I tried to do directive, which include template on the fly, but there is one problem - after compile all attributes, including ng-model, aren't translate to new element and ng-model doesn't working.
Where I'm wrong?
Element code:
<input type-test="kendo">
Directive:
App.directive('typeTest', ['$templateCache', '$compile', '$http', 'Formatter',
function ($templateCache, $compile, $http, Formatter) {
return {
restrict: 'A',
scope: {
ngModel: '='
},
replace: true,
link: function(scope, element, attrs) {
$http.get(Formatter.getTemplateUrl(attrs.typeTest), {cache: $templateCache}).success(function(tplContent) {
var el = $compile(tplContent)(scope);
element.replaceWith(el);
});
}
}
}
]);
Formatter.getTemplateUrl() returns a url to template depend on input argument (attrs.typeTest).
Template to type-test="kendo":
<input type="text" kendo-drop-down-list k-data-source="list" k-data-text-field="'Name'" k-data-value-field="'Id'">
List is defined like [{Id: 1, Name: 'First'}, {Id: 2, Name: 'Second'}].
You shouldn't replace the element inside a linking function of a directive. The linking function should just set up event listeners to make the directive work. Place your logic inside the compile function instead of the link function. Here's a pretty good article about it: http://amitgharat.wordpress.com/2013/06/08/the-hitchhikers-guide-to-the-directive/
I find a solution:
App.directive('dynamicType', ['$compile',
function ($compile) {
return {
compile: function compile(tElement, tAttrs, transclude) {
return {
pre: function preLink(scope, iElement, iAttrs, controller) {
var tpl = "<input type-test='"+iAttrs.dynamicType+"'>";
iElement.html(tpl);
$compile(iElement.contents())(scope);
},
post: function postLink(scope, iElement, iAttrs, controller) {}
}
}
}
}
]);
This directive compile new element, then link it and after return control to typeTest directive - to compile and link other element.
Element:
<input dynamic-type="kendo">

Resources