I'm using a directive to provide a basic template for many of the pages in my Angular app. It looks like this:
angular.module('app.basicLayout', [])
.directive('basicLayout', function () {
return {
restrict: 'E',
transclude: true,
templateUrl: '/assets/views/templates/basicLayout.html'
}
});
And HTML:
<basic-layout>
<h1>My layout goes here</h1>
</basic-layout>
On some of these pages I would like to add a sidebar and still be able to use the layout from my <basic-layout> directive. Is it possible to make something like the following?
<basic-layout>
<h1>My content goes here</h1>
<the-sidebar>
<h2>Sidebar content here</h2>
</the-sidebar>
</basic-layout>
Update
My template file of the directive currently look like this:
<div class="container basic-layout">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<div ng-transclude></div>
</div>
</div>
</div>
If <the-sidebar> is set, I would like to change the template file to something like this:
<div class="container basic-layout">
<div class="row">
<div class="col-md-8">
<!-- The content here -->
<div ng-transclude></div>
</div>
<div class="col-md-4">
<!-- The sidebar here -->
<div ng-transclude></div>
</div>
</div>
</div>
That's the exact case for transclusion. You can parametrize your directive layout with some variable layout (sidebar in this case). To do this your have to set the transclude property in the directive config object to true and also specify where in your directive's layout the changing content should be injected by using the ng-transclude directive. Like this:
return {
...
transluce: true,
...
}
and now in the directive template:
//other layout here
<div ng-transclude></div>
This way all the content you put inside the <basic-layout> directive will be transfered into the element on which you use ng-transclude.
For this to work, you need to manually transclude using the transclude function passed as a 5th parameter to the link function. To make it easier, I would change the template to have placeholders:
<div>
<content-placeholder></content-placeholder>
<div>
<sidebar-placeholder></sidebar-placeholder>
</div>
</div>
Then, place each content where it belongs:
transclude: true,
link: function(scope, element, attrs, ctrls, transclude){
transclude(function(clone){
var sidebar = clone.find("the-sidebar").remove();
element.find("content-placeholder").replaceWith(clone);
element.find("sidebar-placeholder").replaceWith(sidebar);
});
}
This should work for you, but it's not clear to me why you want to build a directive for a general layout.
If you have many pages in the Web app (in a classical non-SPA sense), then it's probably better to create the scaffolding in a "master page" on the server.
Otherwise, if you mean that you have many "views" of the same app, the I suggest looking into ui-router - specifically into a section of Nested States and Nested Views.
Related
I have a list and on each item in list I am calling a modal window (custom directive) which should have details about that item being clicked , but the data does not change and remains same across each item. Please find the code below.
angular
.module('Testapp')
.directive('testDirective', function () {
return {
restrict: "AE",
templateUrl: "/Apps/templates/mytem/testdir.html",
translucent: true,
scope: {item:'=data'},
link: function (scope, element, attribute) {
console.log(scope.sequence);
}
};
});
Directive
<div class="modal fade" id="modalAddFilters">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-body tree">
{{item}}
</div>
</div>
</div>
</div>
Calling Template
<div>
<div ng-repeat="items in TestList>
<test-Directive id="directive_modalAddFilters" data="items"></test-Directive>
</div>
I am able to see the data correctly loaded in DOM but directive template doesnt change the data.
You code works fine, except that you forget to close you ng-repeat with a quotation mark.
I think you just didn't properly resolved you data into the modal view.
I have made a plunk based on your (partial) code, I added a modal and everything works fine. I've used ui-bootstrap to show the modal with the repeated data injected.
Use case:
In my index.html. I have two ng-include directives and two custom directives.
Each directive has its src attribute defined the address to load some html snippet from another server (the custom directives have its template attribute loading the html)
I need to make sure that all directives (see the code 1,2,3) have fully loaded the html snippets before I call the fifth ng-include directive (4) to load the java-script from another server.
Right now all directives are running asynchronously and I can't be sure that the directive which loads the Javascript should always be the last one to load. I need this because if Javascript is loaded and executed before the html it wouldn't go through the html and linking it to javascript/jQuery.
I have solved this issue using a very classic way. I update a global variable whenever the html snipts are loaded and define the an ng-include directive to load the Javascript conditionally when the global variable is true indicating all other directives have loaded their html. But this is not the Angular way. I need the Angular way and btw I'm new starter on Angular.
Index.html
<div ng-controller="navigationController" >
**(1)**<agilesites-navbar></agilesites-navbar>
<div class="container-fluid">
<div class="row row-offcanvas row-offcanvas-right">
<div id="offcanvas-curtain" class="hidden-lg"></div>
<div id="contentContainer" class="col-sm-12 col-md-12 col-lg-12">
<div ui-view="content" id="content"></div>
</div>
**(2)**<agilesites-sidebar></agilesites-sidebar>
</div>
</div>
**(3)**<ng-include src="''+API_HOST+'api/cms/footer'" onload="cmsResourceLoadingStatus(true)"></ng-include>
**(4)**<ng-include src="''+API_HOST+'api/cms/javascript'" ng-if="cmsResourceLoadingCompleted"></ng-include>
</div>
Custom directive (agilesites-sidebar):
angular.module('newhorizonsApp')
.directive('agilesitesSidebar', ['ProductTypes','$compile', function (ProductTypes,$compile) {
return {
restrict: 'E',
scope: true,
template: '<ng-include src="\'\'+API_HOST+\'api/cms/sidebar\'" onload="executeOnLoad();"></ng-include>',
link: function (scope,elem){
scope.executeOnLoad = function() {
scope.cmsResourceLoadingStatus(true);
};
}
};
}]);
I am creating an angular.js application.
I have written a html page and wants to put it under div using directive
<div data-(<directive-name)>
</div>
DxPDictionary.directive('import', [function () {
return {
restrict: 'A',
templateUrl: 'template/Import.html',
scope: false,
}
It's not working, is this approch is right or should use another way to achieve this
<body ng-controller="userCtrl">
<div class="container">
<div ng-include="'myUsersList.html'"></div>
<div ng-include="'myUsersForm.html'"></div>
</div>
</body>
use like this.
<div data-directive-name>
</div>
DxPDictionary.directive('dataDirectiveName', [function () {
return {
restrict: 'A',
templateUrl: 'template/Import.html',
scope: false,
}
your directive name dataDirectiveName in directive definition in camel case format and directive name data-directive-name on DOM should match.
You can use ng-include if you are not creating reusable components using directive and want use is as only html of the page.
There is already a directive for this purpose. You do not need to create your own.
https://docs.angularjs.org/api/ng/directive/ngBindHtml
Ashley's answer is good if you keep your html in a file. If you dynamically generate your html, you can use ng-bind-html directive.
I have some DIVs that appear on the bottom of each of my pages:
<div id="message" ng-show="test.stateService.displayMessage">
<div>
<div>
<div>
{{ test.stateService.message }}
</div>
</div>
</div>
</div>
Is there a way that I can use Angular to simplify this code so that I do not need to add the same code block to every page?
Yes, you could use a directive like so:
app.directive('codeblock', function() {
return {
scope: true, // use a child scope that inherits from parent
restrict: 'A',
replace: 'false',
template: '<div>\
<div>\
<div>\
{{ test.stateService.message }}\
</div>\
</div>\
</div>'
};
});
You'd call it like this:
<div codeblock id="message" ng-show="test.stateService.displayMessage">
Check https://docs.angularjs.org/api/ng/directive/ngInclude
You can save this div as a file, say footer.htm and add the below code to the bottom of all pages.
<div ng-include="footer.htm"></div>
But this code also needs to be given at the bottom of all pages. So I am not sure how it can save your time.
I don't think you can get rid of adding at least some code on each of the pages. Using an html template with ng-include would be one of the approaches.
I have a directive by name cngView
controller.js
//directive to include view panel
angular.module('cngFoundation', [])
.directive('cngView', function() {
return {
restrict : 'CAME',
templateUrl: 'templates/view.html'
};
});
to access directive
<div ng-app="cngFoundation">
<div id="mainbody" class="container">
<cng-view>
[AAA]
</cng-view>
</div>
</div>
The templates/view.html is as follows
<!-- View Panel-->
<div class="panel panel-primary " id="view" >
<div class="panel-heading">
<h3 class="panel-title" ><b>View</b></h3>
</div>
<div class="panel-body">
[BBB]
</div>
</div>
I have made the cng-view tag work but I don't know how to give contents inside the tag.
How to make contents I give at place "[AAA]" appear at "[BBB]" .
In short how to make contents I give within cng-view tag(a custom tag) go into the specific place inside the template content of the cng-view .
Please give guidance . At least please direct me to some online tutorial .
Thanks
You need to use ng-transclude which tells template where to place existing content
<div class="panel-body" ng-transclude></div>
Also need to set transclude:true in directive
See section Creating a Directive that Wraps Other Elements in directive docs
You can use the built in ng-transclude directive. In your view.html replace [BBB] with
<span ng-transclude></span>
also be sure to define transclude on your directive
transclude: true,
For a working example see this plunkr