AngularJs transclude not working in Directive template or templateURL - angularjs

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

Related

Ng-Transclude not working for ng-include

I have created a ng-transclude sample which is not working when I use ng-include inside directive template property.Below are the code I have tried
angular.module("app",[]);
angular.module("app").controller('appController', function ($scope) {
$scope.message="Message from controller";
});
angular.module("app").directive('myFrame', function () {
return {
restrict: 'E',
template : '<div ng-include=\"getTemplateUrl()\"></div>',
controller:function($scope){
$scope.hidden=false;
$scope.close=function(){
$scope.hidden=true;
}
$scope.getTemplateUrl=function(){
//dynamic url
return "frame.html";
}
$scope.message="message from directive";
},
transclude:true,
}
});
angular.module("app").directive('mychildFrame', function () {
return {
restrict: 'E',
templateUrl:"childframe.html",
controller:function($scope){
},
}
});
childFrame.html
<h2>I am from Child</h2>
<div></div>
frame.html
<div class="well" style="width:350px;" ng-hide="hidden">
<div style="float:right;margin-top:-15px">
<i class="glyphicon glyphicon-remove" ng-click="close()" style="cursor:pointer"></i>
</div>
<div ng-transclude>
/*frame content goes here*/
</div>
</div>
index.html
<my-frame>
<mychild-frame></mychild-frame>
</my-frame>
https://plnkr.co/edit/O58voI?p=preview
When I change to the property template to templateUrl="frame.html" it's working fine. But the problem is, this HTML page inside the template is dynamic. So I end up with ng-include.
Could you please provide any possible workaround?
When using the templateUrl property you can also pass it a function to dynamically load a template.
There's no need to put the function in a controller, especially since it doesn't really belong there anyway: the controller is supposed to contain view logic, not a function to load the view itself.
I added the function in the templateUrl instead in your plunkr:
templateUrl : function() {
return 'frame.html';
}
https://plnkr.co/edit/HQHI9hkTojkZFK2Gjxfw?p=preview
As you can see this gives you the desired behavior

Concat Template With Custom Directive Template

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>

Directive with isolated scope unexpectedly accessing parent scopes

I have created a directive my-directive with isolated scope, but it looks like it is able to access property div1 of $rootScope and property div2 of its parent scope $scope of controller1.
What am I missing?
Javascript:
angular.module('app', [])
.controller('controller1', ['$scope',
function ($scope) {
}])
.directive('myDirective', [
function () {
return{
restrict: 'A',
replace: true,
scope: {
myDirective:'='
}
};
}]);
HTML:
<body>
<div id="1" ng-app="app" ng-init="div1='div1'">
<div id="2" ng-controller="controller1" ng-init="div2='div2'">
<div id="4" my-directive="value" ng-init="div4='div4'">
{{div4}}<br/>
{{div1}}<br/>
{{div2}}<br/>
</div>
</div>
</div>
</body>
Output:
div4
div1
div2
You should use transclude function inside the directive, otherwise that values will be bound to parent scope. Check this: http://pucksart.com/transclude-big-mistery/
The scope is isolated within the directive's template. Give your directive a template or write a link function and you will see that the scope is isolated. When you are access the directive scope's ancestors, this is happening outside the directive and then the parsed html is being 'transcluded' into your directive template, which is otherwise empty.
It is an interesting question though. I had not until now realized that omitting the template of a directive is effectively the same as including transclude: true, template: '<div ng-transclude></div>' in the directive definition.
Though you didn't include two of these properties, you actually did this:
.directive('myDirective', [
function () {
return{
restrict: 'A',
replace: true,
transclude: true,
template: '<div ng-transclude></div>',
scope: {
myDirective:'='
}
};
}]);
Also note myDirective: '=' should be myDirective: '#' because it is just a string.

angularjs bootstrap popover data-binding not working

Currently, i am trying to make the angularjs popover data binding work.
Here is the html part:
<div id="sortable" ng-repeat="object in arrayForShow">
<div ng-class="classGenerate(object)" class="well nomargin" id="resizable" pop-over-width-offset argument='object'>
{{object.default}}
</div>
</div>
Now: ng-repeat item: object is passed into directive pop-over-width-offset.
In the popOverWidthOffset directive: I am trying the make the template html be able to access the **argument (which I set in the scope in the directive).**
app.directive "popOverWidthOffset", ($templateCache)->
restrict: 'A',
controller: 'CustomiseFormCtrl'
scope: {
argument: '='
}
link: (scope, element, attrs)->
popOverContent = $templateCache.get('angular/templates/popOverCustomisationChangeWidthOffset.html')
options = {
content: popOverContent,
placement: "top",
html: true,
}
$(element).popover(options)
popOverCustomisationChangeWidthOffset.html:
<form>
{{argument}}
</form>
Compile the content of the pop-over:
compiledPopOverContent = $compile(popOverContent)(scope);

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.

Resources