Concat Template With Custom Directive Template - angularjs

I'm not sure if its possible to achieve what I want. I'll try to explain it with an example:
a custom directive:
appDirectives.directive("myTestDirective",
function() {
return {
restrict: "E",
templateUrl: "<div> Some template here... {{ testObject }} <div>",
scope: {
'testObject' = '#testObject'
}
};
}]);
Use directive in a tempalte:
<my-test-directive testObject="And some more here...">
<div>
I also want to be in the template!
</di>
</my-test-directive>
And I want to achieve this template:
<div> Some template here... And some more here... <div>
<div>
I also want to be in the template!
</di>

You can do this with transclusion. Just add a param to the directive, and use ng-transclude on the element you want to have the contents be inserted.
You might have to remove some the original since the transclusion needs an element to operate on, but this is the basic idea.
angular.module('test', [])
.directive('myTestDirective', function() {
return {
restrict: "E",
template: "<div> Some template here... {{testObject}} <div><div ng-transclude></div>",
scope: {
testObject: '#'
},
transclude: true
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="test">
<my-test-directive test-object="And some more here...">
<div>
I also want to be in the template!
</div>
</my-test-directive>
</div>

Related

AngularJs transclude not working in Directive template or templateURL

I have written a custom directive like so, notice I have commented out the template URL that contains the same HTML structure and the template property:
.directive('sillyDirective', function ( ) {
'use strict';
return {
restrict: 'A',
replace: false,
transclude: true,
template: '<h2>Welcome to my site</h2>',
//templateUrl: '/views/hello.html' ,
link: function (scope, element, attrs) {
element.bind('click', function (){
alert('you click me! I am clicked');
});
};
});
In my HTML view I have the following...
<div data-silly-directive>
<div><img src="logo.jpg></div>
<div><h1>My First Website</h1></div>
</div>
The problem is the content of the directive, e.g.:
<div><img src="logo.jpg></div>
<div><h1>My First Website</h1></div>
is being overwritten with the template content even thought I have set transclude to true and replace to false? What am I doing wrong here?
you need to specify ng-transclude in the template of your directive, this will let angular know where to insert the content of the markup.
app.directive("foo", function() {
return {
transclude: true,
template: "<div>the template</div><div ng-transclude></div>"
};
})
html:
<div foo>
Some Content Here
</div>
result:
<div foo>
<div>the template</div>
<div ng-transclude>Some Content Here</div>
</div>
here's a plnkr
source: https://www.accelebrate.com/blog/angularjs-transclusion-part-1/
Your template must contain an element with an ng-transclude attribute. That's where the body will be "pasted" by angular.
See
https://docs.angularjs.org/api/ng/directive/ngTransclude

Put directive template as a content of container the directive is attached to

Normally, when i'm creating a directive, i have two possible ways to deal with directive templates. I can create a html file somewhere on my server and use it's URL in directive settings:
#directives.directive "someDirective", [
'$rootScope'
($rootScope) ->
controller: ($scope) ->
link: (scope, element, attrs) ->
return
restrict: 'A'
templateUrl: 'path/to/template.html'
scope: {
eventId: '#'
}
]
or i can put the script tag somewhere in the markup and use it's ID as a templateUrl:
<script type="text/ng-template" id="template.html">
<p>Hello {{ name }}</p>
</script>
However, i was wondering - is that possible to put that template to directive container tag as a body of it? That's how i want it to look:
<div my-ng-directive>
<p>Hello {{ name }}</p>
</div>
I think what you're looking for is ng-transclude,
basically ng-transclude allows your to "create" a slot in your original template that will contain the content of the original html element, so in your example a basic directive that does what you want will look like:
angular.module('myModule', [])
.directive('myNgDirective', function() {
return {
controller: function($scope) {
$scope.name = "Test";
},
transclude: true,
restrict: 'A',
template: '<div><h1>The directive</h1><div ng-transclude></div></div>'
}
});
This code:
<div my-ng-directive>
<p>Hello {{ name }}</p>
</div>
Will return:
<div>
<h1>The directive</h1>
<div>
<p>Hello {{ name }}</p>
</div>
</div>

How to write an angularjs directive that makes use of both scope and attributes and refer it thru compiled partial?

I want to write a directive which takes advantage of custom attributes, as follows:
<plant-stages
title="Exploration<br/>du cycle de<br/>développement<br/>de la plante"
></plant-stages>
The controller is currently as follows:
app.directive('plantStages', function () {
return {
restrict: 'AE',
templateUrl: 'corn.figure.plant.stages.html',
link: function (scope, element, attrs) {
scope.title = attrs.title;
}
};
});
The partial is as follows:
<figure class="cornStages">
<div>
<p>{{title}}</p>
</div>
<div ng-repeat="stage in stages">
<div class="stage{{stage.stage}}"></div>
<div>
BBCH : {{stage.bbch}}<br/>
{{stage.displayName}}
</div>
</div>
</figure>
The partial makes use of some scope model variables.
And {{title}} should support plain HTML injection out of the view which embeds it, hence should be compiled. I tried to support this but without success.
What modification should I make to have the HTML compiled?
A bonus question: when I pass the attribute in, I create a dummy title variable in the scope that persists where it should only be local. How would one make changes to handle this?
If you want to wrap HTML in your custom directive take a look at the transclude option (see docs):
module.directive('myDirective', function() {
return {
restrict: 'E',
transclude: true,
template: '<div ng-transclude></div>'
};
});
This enables you to place HTML within the directive tag which can be used in the template:
<div ng-controller="Controller">
<my-directive>
<h1>Test</h1>
</my-directive>
</div>
In case you really want to pass HTML via an attribute use ng-bind-html. This requires the ngSanitize module:
module.directive('myDirective', function () {
return {
restrict: 'E',
template: '<div ng-bind-html="title"></div>',
scope: {
title:'#'
}
};
});
I added this to your fiddle.

Using ng-switch in directive with transclude

I am trying to create a template that shows some transcluded content. When I use ng-show everything works fine, but using ng-if or ng-switch gives me problems. I get this error message: Illegal use of ngTransclude directive in the template! No parent directive that requires a transclusion found
I understand that ng-switch creates a new scope. But the transclude should still go up to the parent chain. Is this a defect in angularjs? See http://jsfiddle.net/HgvP7/
Here is my html, modified from the documentation example:
<div ng-app="docsTransclusionExample">
<div ng-controller="Ctrl">
<my-dialog>Check out the contents, {{name}}!</my-dialog>
</div>
<!-- my-dialog.html -->
<script type="text/ng-template" id="my-dialog.html">
<div ng-switch="1+1">
<div ng-switch-when="2">
<div ng-transclude></div>
</div>
</div>
</script>
</div>
And the code:
angular.module('docsTransclusionExample', [])
.controller('Ctrl', function($scope) {
$scope.name = 'Tobias';
})
.directive('myDialog', function() {
return {
restrict: 'E',
transclude: true,
scope: {},
templateUrl: 'my-dialog.html',
link: function (scope, element) {
scope.name = 'Jeff';
}
};
});

Replace ng-include node with template?

Kinda new to angular. Is it possible to replace the ng-include node with the contents of the included template? For example, with:
<div ng-app>
<script type="text/ng-template" id="test.html">
<p>Test</p>
</script>
<div ng-include src="'test.html'"></div>
</div>
The generated html is:
<div ng-app>
<script type="text/ng-template" id="test.html">
<p>Test</p>
</script>
<div ng-include src="'test.html'">
<span class="ng-scope"> </span>
<p>Test</p>
<span class="ng-scope"> </span>
</div>
</div>
But what I want is:
<div ng-app>
<script type="text/ng-template" id="test.html">
<p>Test</p>
</script>
<p>Test</p>
</div>
I had this same issue and still wanted the features of ng-include to include a dynamic template. I was building a dynamic Bootstrap toolbar and I needed the cleaner markup for the CSS styles to be applied properly.
Here is the solution that I came up with for those who are interested:
HTML:
<div ng-include src="dynamicTemplatePath" include-replace></div>
Custom Directive:
app.directive('includeReplace', function () {
return {
require: 'ngInclude',
restrict: 'A', /* optional */
link: function (scope, el, attrs) {
el.replaceWith(el.children());
}
};
});
If this solution were used in the example above, setting scope.dynamicTemplatePath to 'test.html' would result in the desired markup.
So thanks to #user1737909, I've realized that ng-include is not the way to go. Directives are the better approach and more explicit.
var App = angular.module('app', []);
App.directive('blah', function() {
return {
replace: true,
restrict: 'E',
templateUrl: "test.html"
};
});
In html:
<blah></blah>
I had the same problem, my 3rd party css stylesheet didn't like the extra DOM-element.
My solution was super-simple. Just move the ng-include 1 up. So instead of
<md-sidenav flex class="md-whiteframe-z3" md-component-id="left" md-is-locked-open="$media('gt-md')">
<div ng-include="myService.template"></span>
</md-sidenav>
I simply did:
<md-sidenav flex class="md-whiteframe-z3" md-component-id="left" md-is-locked-open="$media('gt-md')" ng-include="myService.template">
</md-sidenav>
I bet this will work in most situations, even tho it technically isn't what the question is asking.
Another alternative is to write your own simple replace/include directive e.g.
.directive('myReplace', function () {
return {
replace: true,
restrict: 'A',
templateUrl: function (iElement, iAttrs) {
if (!iAttrs.myReplace) throw new Error("my-replace: template url must be provided");
return iAttrs.myReplace;
}
};
});
This would then be used as follows:
<div my-replace="test.html"></div>
This is the correct way of replacing the children
angular.module('common').directive('includeReplace', function () {
return {
require: 'ngInclude',
restrict: 'A',
compile: function (tElement, tAttrs) {
tElement.replaceWith(tElement.children());
return {
post : angular.noop
};
}
};
});
Following directive extends ng-include native directive functionality.
It adds an event listener to replace the original element when content is ready and loaded.
Use it in the original way, just add "replace" attribute:
<ng-include src="'src.html'" replace></ng-include>
or with attribute notation:
<div ng-include="'src.html'" replace></div>
Here is the directive (remember to include 'include-replace' module as dependency):
angular.module('include-replace', []).directive('ngInclude', function () {
return {
priority: 1000,
link: function($scope, $element, $attrs){
if($attrs.replace !== undefined){
var src = $scope.$eval($attrs.ngInclude || $attrs.src);
var unbind = $scope.$on('$includeContentLoaded', function($event, loaded_src){
if(src === loaded_src){
$element.next().replaceWith($element.next().children());
unbind();
};
});
}
}
};
});
I would go with a safer solution than the one provided by #Brady Isom.
I prefer to rely on the onload option given by ng-include to make sure the template is loaded before trying to remove it.
.directive('foo', [function () {
return {
restrict: 'E', //Or whatever you need
scope: true,
template: '<ng-include src="someTemplate.html" onload="replace()"></ng-include>',
link: function (scope, elem) {
scope.replace = function () {
elem.replaceWith(elem.children());
};
}
};
}])
No need for a second directive since everything is handled within the first one.

Resources