Adding a dynamic directive inside another directive template in AngularJS - javascript

I want to add dynamic directive inside another directive tempalte.
As you see I want to add another directive inside a directive template
How do add those dynamic directive there
Please help
return {
restrict: 'AE',
require :'^awkGrid',
templateUrl: 'views/shutter.html',
link : function(scope, element, attr, controllerInstance){
//Set the header
scope.items = [];
angular.forEach(scope.rowData, function(value, key) {
var obj = {
key : key,
value : value
};
template = <country name="'+value.country+'" id="'+key+'"></country>;
scope.items.push(template);
});
};
//Inside shutter.html file
<div data-ng-repeat="item in items" class="ag-row action-row"
ng-class-odd="'ag-row-even'"
ng-class-even="'ag-row-odd'"
ng-class="{'ag-row-selected':$index == selectedRow}"
ng-click="setClickedRow($index,$event)">
<div class="ag-cell">
{{item}} //Not working ,Prinitng the string
<country name="india" id="-1"></country> //Working
</div>

To dynamically switch out the entire template of a directive you have to set the element's html to the desired new template and then pass the element's contents into $compile to bind it with the $scope.
element.html('<h1>Dynamic Content</h1>').show();
$compile(element.contents())($scope);
This should all be defined in the link function of the directive in question.

You must have to recompile your directive. Add folowing code at the end of link function:
$compile(element.contents())(scope);
Answer is in here.
Of course, you have to add service $compile to your directive as a dependency.

Related

Pass data to transcluded element

I want to create a directive that organizes a displays data grouped by date. I also want to be able to specify a directive that will display the individual rows. In a perfect world it would look something like this (but nice and pretty)
Friday, Oct 28
[some directive html]
[some directive html]
[some directive html]
Saturday, Oct 29
[some directive html]
Sunday, Oct 30
[some directive html]
[some directive html]
...
This obviously doesn't work, so if you have a better approach please tell me, but I was hoping to be able to do something along these lines:
app.directive('dateOrganized', [function(){
return {
template:
'<div>' +
'<div ng-repeat="organizedDate in organizedDate">' +
'<div>{{organizedDate.date | date}}</div>' +
'<div ng-repeat="item in organizedDate.items">' +
'{{rowDirectiveHtml}}' +
'</div>' +
'</div>' +
'</div>',
scope: {
organizedDates: '=',
rowDirectiveHtml: '='
}
...
};
}])
app.directive('itemRow', [function(){
return {
template: '<div>{{item.data}}</div>',
scope: {
item: '='
}
};
}]);
then use it like this:
<div data-organized organized-dates="stuff" row-directive-html="<div item-row item=\"item\" />" />
I know this is super ugly (and doesn't work, but I'm sure I could get it working with a few tweaks) so what I am really asking, is there a better way to do this?
This question is more complicated than might appear, so let's break it down.
What you are building is a directive that accepts a partial template - <div item-row item="item" /> - and that template uses (or linked against a scope with) an inner variable - item - that is not defined in the outer scope by the user; its meaning is defined by your directive and your user "discovers" it by reading the documentation of your directive. I typically name such "magic" variables with a prefixed $, e.g. $item.
Step 1
Instead of passing a template as an HTML-as-string via attribute binding, pass it as contents and transclude that content. Transcluding allows you to bind the transcluded content against an arbitrary scope:
<foo>
<div>my item is: {{$item}}</div>
</foo>
.directive("foo", function(){
return {
scope: {},
transclude: true,
template: "<h1>I am foo</h1><placeholder></placeholder>",
link: function(scope, element, attrs, ctrls, transclude){
scope.$item = "magic variable";
transclude(scope, function(clonedContent){
element.find("placeholder").replaceWith(clonedContent);
});
}
};
});
The above will place the template <div>my item is: {{$item}}</div> (could be any template you specify) where the directive foo decides, and will link against a scope that has $item defined.
Step 2
But the added complexity of your directive is that it uses ng-repeat, which by itself accepts a template, and the template your directive receives needs to be used as a template of ng-repeat.
With just the approach above, this would not work, since by the time link runs, ng-repeat will have already transcluded its own content before you had a chance to apply yours.
One way to address that is to manually $compile the template of foo instead of using the template property. Prior to compiling, we will have a chance to place the intended template where needed:
.directive("foo", function($compile){
return {
scope: {},
transclude: true,
link: function(scope, element, attrs, ctrls, transclude){
scope.items = [1, 2, 3, 4];
var template = '<h1>I am foo</h1>\
<div ng-repeat="$item in items">\
<placeholder></placeholder>\
</div>';
var templateEl = angular.element(template);
transclude(scope, function(clonedContent){
templateEl.find("placeholder").replaceWith(clonedContent);
$compile(templateEl)(scope, function(clonedTemplate){
element.append(clonedTemplate);
});
});
}
};
});
Demo

$compile in Directives

Hey guys i was planning out a directive i was making which would essentially be a popup with a timer on it. Basically the plan was to pass in an object which could configure the properties to construct the message. The directive would contain the html template and we would append the message/html based on the properties set in a service. For Example:
$rootScope.timer = 'recursive time fn goes here'
obj = {
message : '<span ng-click="connect()">Custom message goes here {{ timer }} </span>'
}
Popup.pop(obj);
etc. The point of the question is the $rootScope timer needs to tick down (which is simple to do in a controller) but the directive sets html as a string if interpolated and will not update the value if i'm correct. My question is how do i get the directive to render the timer ticking down inside the directive. would i need to use $compile in the directive? if so how? Furthermore how would i pass an ng-click function from this service if i ever needed one? Sorry if its confusing pls ask questions.
Try this
//you can add your custom messge and time function returning value to the way u want
// this is the basic way to do
var testing = angular.module('testing', [])
testing.directive('mydir', function ($compile, $rootScope) {
var template = '<span ng-click="connect()">custom message</span>'
return {
restrict: 'E',
link: function (scope, ele, attribute) {
scope.connect = function () {
alert('popup' + new Date().getTime());
}
var content = $compile(template)(scope);
ele.append(content)
}
}
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body>
<div ng-app="testing">
<mydir></mydir>
</div>
</body>

Dynamic injection of directive inside another directive template

Hello I'm new to AngularJS and I think I misunderstood something. Im trying to inject dynamically a directive inside another directive template.
For instance I have 2 directives "a-tag" and "b-tag" and I would like to add one of these 2 directives inside another directive "container".
I have something like this:
<body ng-app="myApp">
<container item="a-tag" a-color="#f00"></container>
</body>
I declared my "container" directive to get the item attribute (a-tag, b-tag, or any other directive) and inject it.
angular.module("Container", []).directive("container", function($compile){
return {
restrict: "EA",
scope: {
item: "#"
},
link: function(scope, element, attrs){
var template = '<div id="container">';
var item = '';
if(scope.item !== undefined){
item = '<' + scope.item;
item += ' ></' + scope.item + '>';
}
template += item + '</div>';
element.html(template);
$compile(element.contents())(scope);
}
};
});
It is working but i dunt know how to broadcast to my child directive (a/b,etc.) his attributes (for instance a-color="#f00" like used in the first piece of code).
My child directives look like this:
angular.module("A", []).directive("aTag", function(){
return {
restrict: "EA",
templateUrl: "template/a.html",
replace: true,
link: function(scope, element, attrs){
element.css("color", attrs.bColor);
}
};
});
It is a simple example. Actually I designed a modal popup (my container) and I would like to use it for several things such as displaying a form, a loader (my directives a-tag, b-tag, etc).
Any idea is welcome.
Ty,
RĂ©mi

Dynamically Create and Load Angular Directive

In my application i have a list of custom directive names.
$scope.data =["app-hello","app-goodby","app-goodafter"];
each name in this array is one directive that im created.
var app = angular.module('app',[]).controller('mainCtrl',function($scope){
$scope.data =["app-hello","app-goodby","app-goodafter"];
}).directive('appHello',function(){
return {
restrict:'EA',
template:'<h1>Hello Directive</h1>'
};
}).directive('appGoodbye',function(){
return {
restrict:'EA',
template:'<h1>GoodBye</h1>'
};
}).directive('appGoodafter',function(){
return{
restrict:'EA',
template:'<h1>Good Afternoon</h1>'
};
});
now i want to load directive with ng-repeat in the view for example because i used EA restrict for directive can create directive in ng-repeat like this :
<div ng-repeat="d in data" >
<div {{d}}></div>
</div>
but this way it doesn't work. so the real question is if i have list of directive how to load this directive with ng-repeat.for this scenario i create a jsbin .
thanks.
You need a "master" directive that $compiles the HTML (optionally containing directives) into an Angular-aware template and then links the compiled element to a $scope:
app.directive('master', function ($compile) {
return {
restrict: 'A',
link: function postLink(scope, elem, attrs) {
attrs.$observe('directive', function (dirName) {
if (dirName) {
var compiledAndLinkedElem =
$compile('<div ' + dirName + '></div>')(scope);
elem.html('').append(compiledAndLinkedElem);
}
});
}
};
});
<div master directive="{{dir}}" ng-repeat="dir in ['dir1', 'dir2', 'dir3']"></div>
See, also, this short demo.
You can do it in this way:
Directive:
app.directive('compile',function($compile){
return{
restrict:'A',
template: '<div></div>',
link:function(scope,elem,attrs){
scope.name = attrs.compile;
elem.children('div').attr(scope.name,'');
$compile(elem.contents())(scope);
}
};
});
HTML:
<div ng-repeat="d in data" compile="{{d}}">
</div>
Jsbin: http://jsbin.com/wofituye/4/edit
I actually prefer to create templates, that just contain the directive. Then you can use ng-include this then enables you to easily pass scope variables into the dynamically chosen directives too.
Here is my widget code fore example:
<div ng-repeat="widget in widgets track by $index" ng-include="widget.url" class="widget-container" ng-class="widget.widget_type.config.height +' ' + widget.widget_type.config.width">
</div>
Then I set the widget.url to a template containing just the right directive.
I can then in my directive do this:
<custom-widget ng-attr-widget="widget"></custom-widget>
Then I have access to the dynamic variable too, so I can access configuration specifics too, without having to dynamically generate HTML strings and compile them. Not a perfect solution, but personally I used to use the other approach mentioned, and discovered that this fit my needs much better.

AngularJs: grab compiled html and set into tooltip

I'm using angular js bootstrap tooltip to show tooltips on a set of elements.
Plunker: http://plnkr.co/edit/9xk41f3CR0wnajN71bSi
I need to inject into the tooltip html compiled by angular, but i don't really get how. The tooltip tutorial is not useful to me because it gets the html from the scope as variable, but for a set of elements this is not possible.
How can i fill tooltip-html-unsafe?
You can do something like this:
HTML:
<li ng-repeat="phone in phones">
<div phone-info index="{{$index}}">
<p tooltip-html-unsafe="{{tooltips[$index] }}">A tooltip should appear on top of this line ({{ phone.name }} - {{ phone.snippet }})</p>
<div>
</li>
Add to controller:
$scope.tooltips = [];
Directive:
app.directive('phoneInfo', function($compile, $timeout) {
/* wrap in root element so we can get final innerHTML*/
var tipTemplate = '<div><p> This will be the content of {{phone.name}} injected in the tooltip </p><div>';
return {
link: function(scope, el, attrs) {
var tipComp = $compile(tipTemplate)(scope)
$timeout(function() {
scope.tooltips[attrs.index] = tipComp.html()
});
}
}
})
Used index to avoid creating an isolated scope. Can also be done with isolated scope and create a property of phone instead of using scope.tooltips[index]
DEMO

Categories

Resources