AngularJS - Transcluding multiple directives - angularjs

I have a situation where I need to transclude multiple child directives inside of my outer directive. I've got it working, but I'm wondering if there is a better, more "angular" way to do it?
The working example is here: http://plnkr.co/edit/pmukXJPxUGd2gnMvEN1a?p=preview
Plunker code:
<!DOCTYPE html>
<html>
<head>
<script src="//code.jquery.com/jquery-2.1.1.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
</head>
<body ng-app="myApp">
<outer-directive>
<inner-directive1>Some Html I want placed elsewhere</inner-directive1>
<inner-directive2>Yet more Html that should be somewhere else</inner-directive2>
</outer-directive>
<script>
var app = angular.module("myApp", []);
app.directive("outerDirective", function($compile) {
return {
restrict: 'E',
transclude: true,
scope: {},
template: '<div>' +
' <h1>This is a title</h1>' +
' <div class="inner1"></div><br />' +
' Some other code that is in the directive<br /><br />' +
' <div class="inner2"></div><br />' +
'</div>',
link: function(scope, element, attrs, emptyCtrl, transclude) {
transclude(scope, function(clone) {
clone.each(function (i, ele) {
if (ele.nodeName === "INNER-DIRECTIVE1") {
$(element).find(".inner1").replaceWith($compile(ele)(scope));
}
if (ele.nodeName === "INNER-DIRECTIVE2") {
$(element).find(".inner2").replaceWith($compile(ele)(scope));
}
});
});
}
}
});
</script>
</body>
</html>

Related

I am facing problem in this code of custom directive

I am written this code for angularjs custom directive, but not geeting the output. Please help me.strong text
<html>
<head>
<title>Directives</title>
<script src="https://code.angularjs.org/1.6.9/angular.js"></script>
<script src="angular-1.7.6\angular.js"></script>
<script src="angular-1.7.6\angular.min.js"></script>
<script>
var app=angular.module("arrayApp", [])
app.controller("arrayCtrl", function ($scope) {
$scope.colors = ["RED","GREEN","BLUE","YELLOW" ];
});
app.directive('mycolor', function() {
return {
restrict: 'E',
transclude: 'true',
template: '<span ng-transclude></span>',
link: function(scope, element, attr){
element.append("<strong>"+attr.title+"</strong>");
}
};
});
</script>
</head>
<body ng-app="arrayApp">
<div ng-controller="arrayCtrl">
<div ng-repeat="c in colors">
<my-c title="{{c}}">
BASIC COLOR:
</my-c>
</div>
</div>
</body>
</html>
Iam not getting where I am wrong.
I am getting the output as
Output
The code is as below :
<html>
<head>
<title>Directives</title>
<script src="https://code.angularjs.org/1.6.9/angular.js"></script>
<script>
var app=angular.module("arrayApp", [])
app.controller("arrayCtrl", function ($scope) {
$scope.colors = ["RED","GREEN","BLUE","YELLOW" ];
});
app.directive('mycolor', function() {
return {
restrict: 'E',
transclude: 'true',
template: '<span ng-transclude></span>',
link: function(scope, element, attr){
element.append("<strong>"+attr.title+"</strong>");
}
};
});
</script>
</head>
<body ng-app="arrayApp">
<div ng-controller="arrayCtrl">
<div ng-repeat="c in colors">
<mycolor title="{{c}}">
BASIC COLOR:
</mycolor>
</div>
</div>
</body>
</html>
Firstly change the name of the directive into camelCase, it's a good convention for naming directives. So your directive name should be myColor.
Then use the directive like - my-color. Below is the whole code -
<html>
<head>
<title>Directives</title>
<script src="https://code.angularjs.org/1.6.9/angular.js"></script>
<script>
var app=angular.module("arrayApp", [])
app.controller("arrayCtrl", function ($scope) {
$scope.colors = ["RED","GREEN","BLUE","YELLOW" ];
});
app.directive('myColor', function() {
return {
restrict: 'E',
transclude: 'true',
template: '<span ng-transclude></span>',
link: function(scope, element, attr){
element.append("<strong>"+attr.title+"</strong>");
}
};
});
</script>
</head>
<body ng-app="arrayApp">
<div ng-controller="arrayCtrl">
<div ng-repeat="c in colors">
<my-color title="{{c}}">
BASIC COLOR:
</my-color>
</div>
</div>
</body>
</html>
This is the output -

Pass a server side parameter to AngularJS directive

I need to pass a variable from the server side to AngularJS.
I have the following HTML on the server side
<div ng-app="tablesApp" ng-controller="tablesCtrl" ng-init="lang='#lang';...go();" ...>
<st-date-range ?lang="#lang"? ...> </st-date-range>
...
</div>
I should put somewhere in the HTML code (actually in ng-init, but if there are other options I'm OK with that) my server side #lang value, then Angular should use that value...
I use a directive and I would like to pass the #lang(a server side ASP.NET razor variable) param to angular in order to use it in the template path:
app.directive('stDateRange', [function () {
return {
restrict: 'E',
require: '^stTable',
templateUrl: '/templates/stDateRange.en.html',
scope: false,
link: function (scope, element, attr, ctrl) {
var tableState = ctrl.tableState();
scope.$watchGroup(["minDate", "maxDate"],
function (newValues, oldValues) {
so, my server side #lang param I would like to pass to the directive in order to use it in the template URL, like this:
templateUrl: '/templates/stDateRange.#(lang).html'
P.S.:
I'll take this codepen example to show my need:
var app = angular.module('app', []);
app.directive('testDirective', function(){
var lang = 'en'; // <<< Set the variable HERE << !!!
return {
restrict: 'E',
template: '<p>my lang is "<strong>'+lang+'</strong>" </p>'
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<section ng-app="app" ng-init="lang='fr'">
<h3>Test directive for 'fr' lang</h3>
<test-directive></test-directive>
</section>
If I understand you right, you want to create dynamic templateUrl based on attr.lang.
So I would write your directive as:
app.directive('stDateRange', [function () {
return {
restrict: 'E',
require: '^stTable',
template: '<ng-include src="getTemplateUrl()"/>',
scope: false,
link: function (scope, element, attr, ctrl) {
scope.getTemplateUrl = function () {
var url = '/templates/stDateRange.' + attrs.lang + '.html'
return url;
};
var tableState = ctrl.tableState();
scope.$watchGroup(["minDate", "maxDate"],
function (newValues, oldValues) {
And HTML call:
<test-directive lang="{{lang}}"></test-directive>
Demo Plunker
[Edit 1]
If you don't want to use link, you can load constant:
app.directive('testDirective', function(Constants){
var lang = Constants.val;
return {
restrict: 'E',
template: '<p>my lang is "<strong>'+lang+'</strong>" </p>'
};
});
app.constant('Constants', {
val: 'Fess'
});
Demo Codepen
You cannot use $scope on your application directive ng-app but you can use $rootScope. I would achieve this by parsing $root.language into your directive and finally load the template dynamically. You could also access $rootScope.language inside your directive directly without parsing $root.language into it. You can do as you wish - demo punkr.
AngularJS application:
var app = angular.module('plunker', []);
app.controller('ApplicationController', function($scope) {});
app.directive('test', function ($http, $compile) {
return {
scope: {
lang: '='
},
restrict: 'E',
link: function(scope, element) {
$http.get('./template.'+ scope.lang +'.html').then(function (result) {
scope.test = 'some test';
element.html(result.data);
$compile(element.contents())(scope);
});
}
};
});
View:
<!doctype html>
<html ng-app="plunker" ng-init="language = 'en'">
<head>
<meta charset="utf-8">
<title>AngularJS Plunker</title>
<link rel="stylesheet" href="style.css">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.js"></script>
<script src="app.js"></script>
</head>
<body>
<div class="container">
<div class="row">
<test lang="$root.language"></test>
</div>
</div>
</body>
</html>
Template which includes your server side param:
<!doctype html>
<html ng-app="plunker" ng-init="language = '#lang'">
<head>
<meta charset="utf-8">
<title>AngularJS Plunker</title>
<link rel="stylesheet" href="style.css">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.js"></script>
<script src="app.js"></script>
</head>
<body>
<div class="container">
<div class="row">
<test lang="$root.language"></test>
</div>
</div>
</body>
</html>

ng-hide breaking my directive in angular 1.3.16

I'm trying to migrate from angular 1.2.28 to angular 1.3.16, however my code broke.
Angular 1.2.28 working: http://plnkr.co/edit/XfVakwA3Upm7Z2wosHCQ?p=preview
Angular 1.3.16 not working: http://plnkr.co/edit/4VxcHL0MHddobkmu9DMG?p=preview
JS
var app = angular.module('app', []);
app.run(function($rootScope, $timeout){
$rootScope.loading = true;
$timeout(function(){
$rootScope.items = ['Angular', '1.3.16', 'doesnt work'];
$rootScope.loading = false;
}, 3000);
});
app.directive('refresh', function(){
return {
restrict: 'A',
require: '^myDirective',
link: function(scope, element, attrs, ctrl){
if(scope.$last)
ctrl.init();
}
};
});
app.directive('myDirective', function(){
return {
restrict: 'E',
replace: true,
transclude: true,
template: '<div class="my-directive"><p>Height: {{myHeight}}</p> <div ng-transclude></div></div>',
controller: function($scope, $element){
this.init = init;
function init(){
$scope.myHeight = $('.my-directive').height();
}
}
};
});
HTML
<!DOCTYPE html>
<html ng-app="app">
<head>
<script data-require="angular.js#1.3.16" data-semver="1.3.16" src="https://code.angularjs.org/1.3.16/angular.js"></script>
<script data-require="jquery#1.11.0" data-semver="1.11.0" src="//cdnjs.cloudflare.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body>
<h1>Angular 1.3.16</h1>
<div ng-show="loading">Loading...</div>
<my-directive ng-hide="loading">
<div ng-repeat="item in items" refresh>
<p>{{item}}</p>
</div>
</my-directive>
</body>
</html>
The idea is to only run certain code when the inner html is outputted.
Height is 0 in angular 1.3.16.
However, if I remove ng-hide="loading" from <my-directive ng-hide="loading"> in angular 1.3.16, height gets the appropriated value.
Any ideas how can I solve this?
Inject $timeout into your directive and put the init code block in $timeout(function(){ ... }) like this:
app.directive('myDirective', function($timeout){
return {
restrict: 'E',
replace: true,
transclude: true,
template: '<div class="my-directive"><p><b>Height: {{myHeight}}</b></p> <div ng-transclude></div></div>',
controller: function($scope, $element){
this.init = init;
function init(){
$timeout(function(){
$scope.myHeight = $('.my-directive').height();
});
}
}
};
});
var app = angular.module('app', []);
app.run(function($rootScope, $timeout) {
$rootScope.loading = true;
$timeout(function() {
$rootScope.items = ['Angular', '1.3.16', ' work'];
$rootScope.loading = false;
}, 1000);
});
app.directive('myDirective', function($timeout) {
return {
restrict: 'E',
replace: true,
transclude: true,
template: '<div class="my-directive"><p>Height: {{myHeight}}</p> <div ng-transclude></div></div>',
link: function($scope, $element) {
$element.on('DOMAttrModified DOMSubtreeModified', init);
function init() {
$scope.$apply(function() {
$scope.myHeight = $element.height();
});
}
}
};
});
<!DOCTYPE html>
<html ng-app="app">
<head>
<script data-require="jquery#1.11.0" data-semver="1.11.0" src="//cdnjs.cloudflare.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<script data-require="angular.js#1.3.16" data-semver="1.3.16" src="https://code.angularjs.org/1.3.16/angular.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body>
<h1>Angular 1.3.16</h1>
<div ng-show="loading">Loading...</div>
<my-directive ng-hide="loading">
<div ng-repeat="item in items" refresh>
<p>{{item}}</p>
</div>
</my-directive>
</body>
</html>
You have to set the height in the correct angular directive phase/lifecycle. You should set the hight in the link or even postlink phase. Usually the two phases are the same if you don't use prelink This is when all the content has already been rendered. See angular $compile or google for angular post link
The controller is for the logic and the link is for html/dom manipulations.
EDIT:
You can bind 'DOMAttrModified DOMSubtreeModified` events to trigger changes.

How to access a controller function in directives with isolated scope?

I have a function in my controller name as enableEditor it is working if i call the function from direct HTML i.e(add). But, if I call the function for a element which is created through the directives i.e(edit) is not working. Please look at my code and advice me if any ideas.
<!doctype html>
<html lang="en" ng-app="myApp">
<head>
<meta charset="UTF-8">
<title>Example - example-example53-production</title>
<script src="js/angular.min.js"></script>
</head>
<body ng-controller="MainCtrl">
<div user-name=""></div>
<div>
add
</div>
<script>
var myApp = angular.module('myApp', []);
myApp.controller('MainCtrl', ['$scope','$filter', function ($scope,$filter) {
$scope.enableEditor = function() {
alert("123");
};
}]);
myApp.directive("userName", function() {
return {
restrict: "A",
scope: {
value: "=userName"
},
template: '<div class="click-to-edit">' +
'Edit' +
'</div>'
};
});
</script>
</body>
</html>
Since you have an isolated scope the function belongs to the scope of the directive not your controller. Try using & in your directives scope like this:
<body ng-controller="MainCtrl">
<div user-name="" callme="enableEditor()"></div>
<div>
add
</div>
<script>
var myApp = angular.module('myApp', []);
myApp.controller('MainCtrl', ['$scope','$filter', function ($scope,$filter) {
$scope.enableEditor = function() {
alert("123");
};
}]);
myApp.directive("userName", function() {
return {
restrict: "A",
scope: {
value: "=userName",
callme:"&"
},
template: '<div class="click-to-edit">' +
'Edit' +
'</div>'
};
});
The attribute callme="enableEditor()" is used to pass the method to the scope directive, the directive scope uses & to indicate it is method callme:"&". Another example:
method2="someMethod()" like
scope: {
value: "=userName",
callme:"&",
method2:"&"
},template: '<div class="click-to-edit">' + 'Edit' + 'Save' + '</div>'

Angularjs: modal window to be with the size of the window - the angular way

I am learning angular. I have done this before with jquery. I wonder what is the angular way to to this. Also is it possible this functionality to be wrapped in service or directive so it can be reused with other widgets.
html:
<!doctype html>
<html ng-app="plunker">
<head>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.8/angular.js"></script>
<script src="http://angular-ui.github.io/bootstrap/ui-bootstrap-tpls-0.10.0.js"></script>
<script src="example.js"></script>
<link href="//netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div my-modal="{ data: 'test2'}">test2</div>
</body>
</html>
javascript
angular.module('plunker', ['ui.bootstrap', 'myModal']);
angular.module("myModal", []).directive("myModal", function ($modal) {
"use strict";
return {
template: '<div ng-click="clickMe(rowData)" ng-transclude></div>',
replace: true,
transclude: true,
scope: {
rowData: '&myModal'
},
link: function (scope, element, attrs) {
scope.clickMe = function () {
$modal.open({
template: "<div style=\"overflow:auto\">Created By:" + scope.rowData().data + "</div>"
+ "<div class=\"modal-footer\">"
+ "<button class=\"btn btn-primary\" ng-click=\"ok()\">OK</button>"
+ "<button class=\"btn btn-warning\" ng-click=\"cancel()\">Cancel</button>"
+ "</div>",
controller: function ($scope, $modalInstance) {
$scope.ok = function () {
$modalInstance.close({ test: "test"});
};
$scope.cancel = function () {
$modalInstance.dismiss('cancel');
};
}
});
}
}
};
});
Working plunker:
http://plnkr.co/edit/yzxtWwZQdq94Tagdiswa?p=preview
I am very new to angular. Any working example will be greatly appreciated.
$modal uses Bootstrap modals and those have #media-queries set on .modal-dialog CSS class - you have to override that to make modal stretch to window width

Resources