How to embed an html page using angular directive - angularjs

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.

Related

AngularJS: Using directives as templating

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.

Can an angular directive contain a controller?

Or perhaps a better question is, should a directive contain a controller?
For reasons of separation, my index.html is a simple file. Everything is rendered into it via templates. So my index.html is real simple:
<body ng-app="myapp"><mainmenu></mainmenu><div ng-view></div></body>
I don't really need a directive for mainmenu, but it allows me to put the menu in a separate template file. The main menu itself contains user info, login/logout, and a search box.
<div class="leftmenu" ng-show="isLogin()">
<ul class="menu">
<li>Part1</li>
<li>Part2</li>
<li>Part3</li>
</ul>
<div ng-controller="Search" class="Search><input type="text" ui-select2="s2opts" style="width:250px;" ng-model="search" data-placeholder="search"></input></div>
</div>
<div class="rightmenu">
<ul ng-show="isLogin()" class="menu">
<li>My Account</li>
<li>Logout</li>
</ul>
<ul ng-show="!isLogin()" class="menu">
<li>Login</li>
<li>Register</li>
</ul>
</div>
So there is the menu part, with its own controller, and the search, with its own, embedded between the two parts.
Of course, my mainmenu directive unit tests fail because SearchController isn't defined. But this leaves me wondering if I am going about this wrong. Should I even have it like this, a section of html with an explicit ng-controller defined inside it? Doesn't this create all sorts of weird dependencies?
How should I better structure this? A search directive that is included so I can unit test it separately? Something feels wrong here structurally...
UPDATE:
As requested, a basic fiddle: http://jsfiddle.net/nj4n44zx/1/
As specified by the Angular documentation, the best practice is to define a controller inside a directive only to expose an API to another directive. Otherwise the link function is sufficient.
See at the bottom of :
Angular directives
By experience using controllers inside a directives shadow what you are doing in your scope. It does not help to have a easy readable code.
I do prefer using the main controller where the directive is included. With a non isolated scope you have access to everything from the link function.
I usually deal with it like that:
app.directive('topMenu', function() {
return {
restrict: 'E', // or whatever You need
templateUrl: '/partials/topmenu', //url to Your template file
controller: function($scope) {
$scope.foo = "bar";
}
};
});
Then, in that template You don't have to add ng-controller.
sure your directive can contain a controller because you declare a directive like this
myApp.directive('mainMenu', function() {
return {
restrict: 'E',
replace: true,
scope: true,
templateUrl: 'menu.html',
controller:['$scope', function($scope) {
//define your controller here
}]
};
});

Exposing AngularJS directive property value to parent controller

I am working on an AngularJS app. I am trying to write a reusable component to use throughout my app. For the sake of demonstration, we'll just use a text box. I've created a fiddle of my attempt here. Basically, I'm trying to use a control like this:
<div ng-app="myApp">
<div ng-controller="myController">
<my-control textValue="{{controlValue}}"></my-control>
<br />
You entered: {{controlValue}}
</div>
</div>
Unfortunately, I cannot figure out how to bind a property between the scope of the controller and the scope of the directive. I'm not sure what I'm doing wrong in my fiddle. Can someone please tell me what I'm doing wrong?
Thank you!
You have created directive with isolated scope and you are trying to print value from isolate scope. It isn't right, you can write your directive like this, without isolated scope:
return {
restrict: 'EAC',
template: '<input type="text" ng-model="controlValue"></input>'
};
if you want to setup directive with isolated scope, you should isolate your scope then use $watch for do changes
You were not so far, but you need to be carefull when using {{}}
Remove braces and don't use camelNotation for text-value attribute :
<div ng-app="myApp">
<div ng-controller="myController">
<my-control text-value="controlValue"></my-control>
<br />
You entered: {{controlValue}}
</div>
</div>
Use ng-model attribute :
angular.module('ui.directives', []).directive('myControl',
function() {
return {
restrict: 'EAC',
scope: {
textValue: '='
},
template: '<input type="text" ng-model="textValue"></input>'
};
}
);

Angular Directive not replacing Element

I'm trying to create a directive that will work against xml that i am injecting into the dom via a service.
Here is my a relatively reduced example, having removed the async service call for data and also the template: jsBin - transforming elements using directive
Everything works well with regard getting my post elements' header attribute into an h2 tag but it is leaving a element within my page which will fail for some browsers.
to clarify, this is what i get:
<post class="ng-isolate-scope ng-scope" heading="test heading">
<div class="ng-scope">
<h2 class="ng-binding">test heading</h2>
<div>test</div>
</div>
</post>
and this is what i would expect:
<div class="ng-scope">
<h2 class="ng-binding">test heading</h2>
<div>test</div>
</div>
I think Adam's answer is the better route, but alternatively and easier if you include jquery you can do this in your link function:
var e =$compile(template)(scope);
element.replaceWith(e);
You aren't using template correctly in your directive. Your link function should not applying your template as you are in the example code.
var linker = function(scope, element, attrs) {
var template = getTemplate();
element.html(template);
$compile(element.contents())(scope);
};
Instead of that, just do this:
return {
restrict: 'E',
replace: true,
scope: {
heading: '#'
},
template: '<div><h2>{{heading}}</h2><div>test</div></div>'
};
In your post directive. 'replace: true' will not impact anything if you are compiling and manipulating the DOM yourself.
At the same time, though, I have no idea what your compile directive is for and why you have a factory that returns an HTML string. All of that code looks like it could be reduced to a single directive. I can't really comment on what you're trying to do, but once you start using $compile all over the place, odds are you aren't doing things the 'Angular way'.

Howto set template variables in Angular UI Bootstrap? (accordion)

I try to build a accordion with Angular UI Bootstrap (http://angular-ui.github.io/bootstrap/#/accordion). On How do I set model according to chosen accordion group. UI Bootstrap i found a working solution to use a template.
In my code i add the template with <script type="text/ng-template" id="template/accordion/accordion-group.html">
In this template a can use {{heading}} set by <accordion-group heading="{{group.title}}" content="{{group.content}}" ng-repeat="group in groups"></accordion-group>.
But how do i set other custom template variables?
I tried to set content="{{group.content}}" in the accordion tag too. Even if set, i don't know how to use it, tried {{content.group}} {{content}} and {% content %}.
Complete code on: http://plnkr.co/dSIVGg64vYSTAv5vFSof
See the edited plunker: http://plnkr.co/edit/8YCUemqILQy3knXqwomJ
You were trying to the nest a controller within the template of a directive. I might be mistaken, but that doesn't work or at least not in a very nice manner.
Instead of nesting controllers I would recommend converting CollapseDemoCtrl into a directive too. You can then pass the {{group.content}} or any other content to this directive.
EDIT: Example of how to pass data to directive scope
The HTML will be something like this:
<span ng-repeat="group in groups">
<div testDirective content="group.content" title="group.title"> </div>
</span>
The directive will look something like this:
angular.module('testModule', [])
.directive('testDirective', function(){
return {
restrict: 'A',
scope: {
content:'=content',
title: '=title'
},
template: '<h1>{{title}}<h1> <div>{{content}}</div>',
link: function(scope, element, attrs) {
}
}
});

Resources