How to dynamically generate a component withing a component/directive? - angularjs

I want to create a wrapper for different angularjs components. That wrapper have some have html code and some common functions.
<div class="wrapper">
<h1>{{header}}</h1>
<!--place for a component that has been passed through bindings-->
</div>
So ideally, I want to pass a name of a child component to this one and have it render it. How can I achieve this?

Not sure you can achieve that by passing names of components, but you could definitely use the AngularJS transclude directive
For example:
JS
var app = angular.module('AppModule', []);
app.directive('wrapperDir', function () {
return {
restrict: 'E',
template: '<div class="wrapper">' +
'<h1>Example transclude</h1>' +
'<div ng-transclude></div>' +
'</div>',
transclude: true,
scope: {}
};
});
HTML
<div ng-app='AppModule'>
<wrapper-dir>
<h2>Content to transclude</h2>
<div>Other stuff, including other directives</div>
</wrapper-dir>
</div>
JSFiddle example here

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

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

AngularJS: ngInclude with custom scope

I have an existing directive that creates a generic wizard that will be used across my current organization. This wizard will have steps, and each step has an HTML template to be loaded as the "body" of the wizard. Currently, I'm adding the template using ng-include. I don't know which attributes the wizard will have, as it will come from the wizard consumer.
Question: Is there a way to bind the template models (attributes) to a directive scope variable instead to the scope itself?
Currently I have:
Directive HTML
<div ng-include="/step1.html"></div>
Note: This step1.html is just an example. The actual HTML template will come as a configuration parameter from the wizard directive.
Step 1 HTML
<input type="text" ng-model="data.email"/>
This is "forcing" the wizard consumer to include "data" for each of his attributes.
As a result, I was looking for something like this:
Directive HTML
<div ng-include="/step1.html" ng-scope="scope.data"></div>
Step 1 HTML
<input type="text" ng-model="email"/>
I was able to solve the problem using ng-transclude. Now, the consumer does not need to send me the HTML code (step1.html). Right now, this goes directly into the wizard directive body, as follows:
Sample Controller
angular.module('sampleApp').controller('SampleCtrl', function ($scope) {
$scope.email;
});
Sample HTML
<div wizard>
<div step title="Step 1">
<input type="text" ng-model="email"/>
</div>
</div>
Directives with transclude option
angular.module('sampleApp').directive('wizard', function () {
return {
restrict: 'A',
transclude: true,
scope: {
},
template: '<div> Wizard <div class="stepsContainer" ng-transclude /></div>'
};
});
angular.module('sampleApp').directive('step', function () {
return {
require: "^wizard",
restrict: 'A',
transclude: true,
scope: {
title: '#'
},
template: '<div ng-show="current"> {{ title }} <div ng-transclude></div></div>'
};
});
I believe what you need is a directive, with which you can have isolate scope, just like taking parameter from outer scope.
Directive
yourModule.directive('step1', function() {
return {
scope: {
data: '=anyname'
},
templateUrl: "/step1.html"
};
})
Step1 HTML
<input type="text" ng-model="data.email"/>
Then when the consumer uses it:
<div step1 anyname="scope.consumerData"></div>
Then anyname can be named anything meaningful to the consumer, without knowing the template is actually using data.

How to move DOM to rootElement in directive (angularjs)

I have a directive which has its template but part of it should always be appended to $rootElement. So wherever user put this directive in app's html part of it must reside as the last child of $rootElement.
This is a special case for transclusion I guess but I wonder if someone has already been done anything like this.
Example - let's say I have my-modal-dialog directive and user wants to use two or more dialogs inside each other. So I'd have this html:
<my-modal-dialog id="dlg1">
<div>...</div>
<my-modal-dialog id="dlg1-1">
...
</my-modal-dialog>
</my-modal-dialog>
But the resulting html should be like this:
<div ng-app>
...
<div id="dlg1" class="modal">
...
</div>
<div id="dlg2" class="modal">
...
</div>
</div>
Any idea of how this could be done?
You could probably use compile method for this. Here is an example in fiddler - http://jsfiddle.net/EyDPh/
myApp.directive("myModelDialog", function () {
return {
replace: true,
restrict: 'E',
scope: {
'value': '='
},
compile:function(element, attrs){
var newElement = angular.element('<div id=' + attrs.id + '> Your content is - ' + element.html() + '</div>');
element.replaceWith(newElement);
}
};
});

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