I'm trying to write a little dsl around the grid elements outlined here: http://foundation.zurb.com/docs/grid.php
basically what I wish to do is to
<row>
<column two mobile-one>{{myText}}</col>
<column four centered mobile-three><input type="text" ng-model="myText"></input></col>
</row>
transform into:
<div class="row">
<div class="columns two mobile-one">{{myText}}</div>
<div class= "columns four centered mobile-three"><input type="text" ng-model="myText"></input></div>
</div>
Ideally, I wish to write something that can take arbitrary nesting: row -> col -> row -> col -> row.....
I am having trouble getting the first step right - nesting the elements because I can't quite figure how how to get the child elements into another template without seriously compromising the compilation process.
var app = angular.module('lapis', []);
app.directive('row', function(){
return {
restrict: 'E',
compile: function(tElement, attrs) {
var content = tElement.children();
tElement.replaceWith(
$('', {class: 'row',}).append(content));
}
}
});
just does not do anything. The failed attempt is shown here - http://jsfiddle.net/ZVuRQ/
Please help!
I was hoping not to use ng-transclude because I found that it added an additional scope.
Here is a directive that does not use ng-transclude:
app.directive('row', function() {
return {
restrict: 'E',
compile: function(tElement, attrs) {
var content = angular.element('<div class="row"></div>')
content.append(tElement.children());
tElement.replaceWith(content);
}
}
});
You may want to use tElement.contents() instead of tElement.children().
You don't need jquery at all in your example (but you need to include it on your page/jsFiddle):
var app = angular.module('lapis', []);
app.directive('row', function(){
return {
restrict: 'E',
template: '<div class="row" ng-transclude></div>',
transclude: true,
replace: true
};
});
Related
This question already has answers here:
AngularJS - html under my directive is not showing
(2 answers)
Closed 6 years ago.
I have a parent directive which includes two children directives, first and second. I noticed that only the first child is rendered. Also, if I put some arbitrary HTML markup before the first one, it's all rendered but if I put them after that then they will not show up. Why is this?
See the jsfiddle:
<!-- index.html -->
<div ng-app="myApp">
<my-parent-dir />
</div>
<!-- main.js -->
var app = angular.module("myApp", []);
app.directive("myParentDir", function() {
return {
restrict: 'E',
template: '<my-first-child /> <my-second-child />'
};
});
app.directive("myFirstChild", function() {
return {
restrict: 'E',
template: '<input type="text" placeholder="first">',
};
});
app.directive("mySecondChild", function() {
return {
restrict: 'E',
template: '<input type="text" placeholder="second">',
};
});
Try to use it like this:
var app = angular.module("myApp", []);
app.directive("myParentDir", function() {
return {
restrict: 'E',
template: '<my-first-child></my-first-child> <my-second-child></my-second-child>'
};
});
From the angular issues in github:
self-closing or void elements as the html spec defines them are very
special to the browser parser. you can't make your own, so for your
custom elements you have to stick to non-void elements ().
this can't be changed in angular.
Self defined tags are no leaf tags so you will have to use:
template:'<my-first-child></my-first-child> <my-second-child></my-second-child>'
Since you're using custom tags, you need to close the tag, because HTML spec does not allow self closing tags.
template: '<my-first-child></my-first-child> <my-second-child></my-second-child>'
JSFiddle
I have the following html:
<div ng-controller="collapseController">
<div><breadcrumb-visualiser breadcrumbs="breadcrumbs" /></div>
<div id="partialViewContainer">
<div id="personContainer" partial-view-loader view="person" parent="" breadcrumbs="breadcrumbs"></div>
</div>
</div>
Template breadcrumb-visualiser
<div style="width: 100%; background-color: #eee">
<div ng-repeat="breadcrumb in breadcrumbs">
<span class="customBreadcrumb"><a ng-href="" ng-click="">{{breadcrumb}}</a></span>
</div>
</div>
partial-view-loader
Loads an MVC partial view into the containing div. The loading partial view will be able to add yet another (new) view to the screen, while hiding the previous screen.
As you may see by the above html, this directive shares the breadcrumbs binding, provided by the collapseController.
The directive adds the latest breadcrumb (associated to the just loaded partial view) to the existing breadcrumb list like so:
$scope.AddBreadCrumb = function (breadcrumb) {
$scope.breadcrumbs.push(breadcrumb);
}
That's a function in the directive controller.
The issue
The collapseController initialises breadcrumbs with this value ['A', 'B'].
So breadcrumbs A and B are displayed right away.
The first load of partial-view-loader will add breadcrumb C, resulting in:
['A', 'B', 'C'].
As I click the button that causes a new view to be added, I will once again trigger partial-view-loader, but now for breadcrumb D.
The problem is that it does not seem to update the breadcrumb. There's no visual change. Internally though, changes have been done but incorrectly.
If I add logging to AddBreadCrumb like so:
$scope.AddBreadCrumb = function (breadcrumb) {
console.log($scope.breadcrumbs);
$scope.breadcrumbs.push(breadcrumb);
console.log($scope.breadcrumbs);
}
I get the following output:
before: ['A', 'B']
- push -
after: ['A', 'B', 'D']
Question
How come the added breadcrumb 'C' isn't preserved, and why is the new breadcrumb list not displayed (even if it's incorrect)?
In response to Divya:
self.AddChildByDirective = function (viewIdentifier, parentViewIdentifier) {
var html = '<div id="' + viewIdentifier + 'Container" fvl-partial-view-loader view="' + viewIdentifier + '" parent="' + parentViewIdentifier + '" breadcrumbs="breadcrumbs" /></div>';
var target = $('#partialViewContainer');
var linkFunc = $compile(html);
var content = linkFunc($scope);
target.append(content);
chainedScreensService.CollapsePartialByIdentifier(parentViewIdentifier);
}
That builds, compiles and appends the directive code for the new screen (view and parent are different).
Extra info:
I've changed the scope of both directives to scope: false. The idea is to make sure I'm using the variables declared by the controller, not something in an isolated scope. Zero difference.
This is the current code of the directives:
breadcrumbVisualiser
angular.module('directives.api').directive("breadcrumbVisualiser", [
function () {
return {
restrict: 'E',
scope: false,
templateUrl: 'Templates/Directives/BreadcrumbVisualiser.html',
controller: function () {
},
link: function (scope, element, attrs) {
}
}
}
]);
partialViewLoader
angular.module('directives.api').directive("partialViewLoader", [
'$compile',
'chainedScreensService',
function (
$compile,
chainedScreensService) {
return {
restrict: 'A',
scope: false,
controller: ['$scope', function ($scope) {
}],
link: function (scope, element, attrs) {
chainedScreensService.GetPartialView(scope.activeView).then(function (viewData) {
$.post(viewData.Url, function(view) {
var linkFunc = $compile(view);
var content = linkFunc(scope);
element.append(content);
scope.AddBreadCrumb(viewData.Subject);
});
});
}
}
}
]);
scope.AddBreadCrumb(viewData.Subject) is a function defined in the controller.
Hello I'm new to AngularJS and I think I misunderstood something. Im trying to inject dynamically a directive inside another directive template.
For instance I have 2 directives "a-tag" and "b-tag" and I would like to add one of these 2 directives inside another directive "container".
I have something like this:
<body ng-app="myApp">
<container item="a-tag" a-color="#f00"></container>
</body>
I declared my "container" directive to get the item attribute (a-tag, b-tag, or any other directive) and inject it.
angular.module("Container", []).directive("container", function($compile){
return {
restrict: "EA",
scope: {
item: "#"
},
link: function(scope, element, attrs){
var template = '<div id="container">';
var item = '';
if(scope.item !== undefined){
item = '<' + scope.item;
item += ' ></' + scope.item + '>';
}
template += item + '</div>';
element.html(template);
$compile(element.contents())(scope);
}
};
});
It is working but i dunt know how to broadcast to my child directive (a/b,etc.) his attributes (for instance a-color="#f00" like used in the first piece of code).
My child directives look like this:
angular.module("A", []).directive("aTag", function(){
return {
restrict: "EA",
templateUrl: "template/a.html",
replace: true,
link: function(scope, element, attrs){
element.css("color", attrs.bColor);
}
};
});
It is a simple example. Actually I designed a modal popup (my container) and I would like to use it for several things such as displaying a form, a loader (my directives a-tag, b-tag, etc).
Any idea is welcome.
Ty,
RĂ©mi
In my application i have a list of custom directive names.
$scope.data =["app-hello","app-goodby","app-goodafter"];
each name in this array is one directive that im created.
var app = angular.module('app',[]).controller('mainCtrl',function($scope){
$scope.data =["app-hello","app-goodby","app-goodafter"];
}).directive('appHello',function(){
return {
restrict:'EA',
template:'<h1>Hello Directive</h1>'
};
}).directive('appGoodbye',function(){
return {
restrict:'EA',
template:'<h1>GoodBye</h1>'
};
}).directive('appGoodafter',function(){
return{
restrict:'EA',
template:'<h1>Good Afternoon</h1>'
};
});
now i want to load directive with ng-repeat in the view for example because i used EA restrict for directive can create directive in ng-repeat like this :
<div ng-repeat="d in data" >
<div {{d}}></div>
</div>
but this way it doesn't work. so the real question is if i have list of directive how to load this directive with ng-repeat.for this scenario i create a jsbin .
thanks.
You need a "master" directive that $compiles the HTML (optionally containing directives) into an Angular-aware template and then links the compiled element to a $scope:
app.directive('master', function ($compile) {
return {
restrict: 'A',
link: function postLink(scope, elem, attrs) {
attrs.$observe('directive', function (dirName) {
if (dirName) {
var compiledAndLinkedElem =
$compile('<div ' + dirName + '></div>')(scope);
elem.html('').append(compiledAndLinkedElem);
}
});
}
};
});
<div master directive="{{dir}}" ng-repeat="dir in ['dir1', 'dir2', 'dir3']"></div>
See, also, this short demo.
You can do it in this way:
Directive:
app.directive('compile',function($compile){
return{
restrict:'A',
template: '<div></div>',
link:function(scope,elem,attrs){
scope.name = attrs.compile;
elem.children('div').attr(scope.name,'');
$compile(elem.contents())(scope);
}
};
});
HTML:
<div ng-repeat="d in data" compile="{{d}}">
</div>
Jsbin: http://jsbin.com/wofituye/4/edit
I actually prefer to create templates, that just contain the directive. Then you can use ng-include this then enables you to easily pass scope variables into the dynamically chosen directives too.
Here is my widget code fore example:
<div ng-repeat="widget in widgets track by $index" ng-include="widget.url" class="widget-container" ng-class="widget.widget_type.config.height +' ' + widget.widget_type.config.width">
</div>
Then I set the widget.url to a template containing just the right directive.
I can then in my directive do this:
<custom-widget ng-attr-widget="widget"></custom-widget>
Then I have access to the dynamic variable too, so I can access configuration specifics too, without having to dynamically generate HTML strings and compile them. Not a perfect solution, but personally I used to use the other approach mentioned, and discovered that this fit my needs much better.
I'm trying to learn AngularJS and have one question/concept I'm struggling to understand.
Take the following demo code I created:
js
var app = angular.module('customerPortalApp', ["ui.router"]);
app.config( function($stateProvider, $urlRouterProvider){
// For any unmatched url, send to /route1
$urlRouterProvider.otherwise("/route1");
$stateProvider
.state('route1', {
url: "/route1",
templateUrl: "/static/html/partials/_campaign_title.html",
controller: "CampaignCtrl"
})
});
app.controller("CampaignCtrl", function($scope){
$scope.loadCampaign = function(){
alert("loaded campaign!")
}
});
app.directive("campaign", function() {
var MessageBox = angular.element('<div class="alert alert-success">hello</div>');
var link = function (scope, element){
scope.loadCampaign();
}
return {
restrict: "E",
compile: function (template){
template.append(MessageBox)
return link
}
}
});
html
<div class="container" ng-app="customerPortalApp">
<div class="row">
<div class="span12">
<div class="well" ui-view></div>
</div>
</div>
<div ng-controller="CampaignCtrl">
<campaign>
test
</campaign>
</div>
</div>
Looking at this code I call the controller in my config and the new $stateProvider I added now takes care of the template loading, so why do I now need directive? In my example I don't now know why I would need one, can ui-view be used to house more controllers?
For your example, you can to use a ui-view. In general, I used directives for a reusable and specified behavior.
What are Directives?
At a high level, directives are markers on a DOM element (such as an attribute, element name, or CSS class) that tell AngularJS's HTML compiler ($compile) to attach a specified behavior to that DOM element or even transform the DOM element and its children.
Angular comes with a set of these directives built-in, like ngBind, ngModel, and ngView. Much like you create controllers and services, you can create your own directives for Angular to use. When Angular bootstraps your application, the HTML compiler traverses the DOM matching directives against the DOM elements.
See the documentation: Angular JS Documentation
A example below as I used the directives:
/* Get the boolean data and switch true or false for respective images. This Example use the bootstrap to show images */
App.directive('bool2image', function() {
return {
restrict: 'C',
replace: true,
transclude: true,
scope: { boolean: '#boolean' },
template: '<div ng-switch on="boolean">' +
'<div ng-switch-when="false"><span><i class=icon-remove></i></span></div>' +
'<div ng-switch-when="true"><span><i class=icon-ok></i></span></div>' +
'</div>'
}
});
So, to used the directive called into the code:
<div class="bool2image" boolean="{{booleanData}}"></div>
I hope to help you.