I have used the directive scope in directive template.
I have tried to get the html from template cache which was stored earlier.
But the current directive scope is not applied to the directive. I don't what will be the reason.
I have tried to compile the template and get the value. But not applied.
contentString = $templateCache.get('template/MyTemplate')
var div = document.createElement("div");
div = angular.element(div).html(contentString);
var s = $compile(div.contents())($scope);
template/MyTemplate would be following
<div>
{{obj.value}}
</div>
Directive scope like following,
link: function ($scope, $element, $attributes) {
$scope.obj.value="This is my test"
}
I got the output like
<div class="ng-scope">
{{obj.value}}
</div>
What will be the issue?
Check this example which is using a custom directive with an isolated scope. I hope the below examples will be of help to you.
angular
.module('demo', [])
.directive('hello', hello);
hello.$inject = ['$templateCache', '$compile'];
function hello($templateCache, $compile) {
var directive = {
scope: {
},
link: linkFunc
};
return directive;
function linkFunc(scope, element, attrs, ngModelCtrl) {
scope.obj = {
value: 'Hello, World!'
};
var template = $templateCache.get('templateId.html');
element.html(template);
$compile(element.contents())(scope);
}
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>
<div ng-app="demo">
<hello></hello>
<script type="text/ng-template" id="templateId.html">
<div>
{{obj.value}}
</div>
</script>
</div>
Another example using controller aliasing syntax i.e. controller as with a directive to be consistent with using controller as with view and controller pairings
angular
.module('demo', [])
.controller('DefaultController', DefaultController)
.directive('hello', hello);
function DefaultController() {
var vm = this;
vm.message = 'Hello, World!';
}
hello.$inject = ['$templateCache', '$compile'];
function hello($templateCache, $compile) {
var directive = {
link: linkFunc,
scope: {
message: '='
},
controller: HelloController,
controllerAs: 'vm',
bindToController: true
};
return directive;
function linkFunc(scope, element, attrs, ngModelCtrl) {
var template = $templateCache.get('templateId.html');
element.html(template);
$compile(element.contents())(scope);
}
}
function HelloController() {
var vm = this;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>
<div ng-app="demo">
<div ng-controller="DefaultController as ctrl">
<hello message="ctrl.message"></hello>
<script type="text/ng-template" id="templateId.html">
<p>{{vm.message}}</p>
</script>
</div>
</div>
Related
I have the following code:
dynamicTemplateItem.js:
angular.module('mod1')
.directive('dynamicTemplateItem', ['$rootScope', '$compile', '$parse', '$http',
function ($rootScope, $compile, $parse, $http) {
var linker = function ($scope, $element, $attrs) {
var templateUrl = $rootScope.dynTemplate[$attrs.type];
// it will be something like "views/templates/template.html"
if (templateUrl) {
$http.get(templateUrl).then(function (response) {
$compile($element.html(response.data).contents())($scope);
}, function (e) {
console.error(e);
});
}
};
return {
restrict: "E",
link: linker,
scope: {
type: '='
}
};
}]);
views/main html:
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Test</title>
</head>
<body>
<div ng-cloak class="container">
<dynamic-template-item type="login"/>
</div>
</body>
</html>
views/templates/template.html:
<div ng-controller="Controller1">
<div> ctrl1 </div>
<div ng-controller="Controller2">
<div> ctrl2 </div>
<select ng-change="switch()" ng-options="test.name for test in tests.availableTests track by test.id"
ng-model="tests.selectedTest"></select>
</div>
</div>
Controller2.js:
angular.module("mod1").controller("Controller2", ['$scope', '$rootScope', '$location', "$state"
function ($scope, $rootScope, $location, $state) {
// ...
$scope.switch = function () {
// ...
};
}]);
The problem is that $scope.switch function is not accessed and also any other function in Controller2.
What am I doing wrong?
Is was used to work before introducing dynamic templating with the dynamicTemplateItem directive, so before dividing main html and template.html, when I was using templateUrl: views/main.html in directive.
My angularjs version is 1.7
Thanks
The problem here is that you are declaring the directive with an isolated scope:
scope: {
type: '='
}
Since you don't seem to require it as you are retrieving the type from the attributed, you should remove the scope from de declaration and your directive should be able to access the parent scope.
return {
restrict: "E",
link: linker
};
Suppose the following blueprint code:
<div ng-controller="myCtrl">
<div ng-repeat="...">
<div ng-repeat="...">
<div ng-repeat="...">
<div ng=if="..." my-directive>
</div>
</div>
</div>
</div>
</div>
myApp.directive('myDirective', function() {
return {
controller: function($scope){
console.log('controller scope');
console.log($scope);
},
link:function(scope,element){
console.log('link scope');
console.log(scope);
}
}
});
Both outputs in console will point to the scope created by ng-if directive. My question is how may I access myCtrl's scope from inside the directive . Of course not by using $parent.$parent....
The easiest way could be by using require in the directive, like:
<div ng-controller="MyCtrl">
<div my-directive></div>
</div>
var myApp = angular.module("app", []);
myApp.controller("MyCtrl", function($scope) {
this.text = "I am in Controller Scope";
this.getValue = function() { return this.text; };
});
myApp.directive("myDirective", function() {
return {
require: "^ngController",
link: function(scope, elem, attrs, ngCtrl) {
elem.text(ngCtrl.getValue());
}
};
});
EDIT
In your case, I think you could use the controller scope variables and methods in the directive by using scope binding with &; snippet below:
<div ng-controller="MyCtrl as vm">
<my-directive on-get-value="vm.getValue()">
</my-directive>
</div>
angular.module('app', [])
.controller('MyCtrl', function($window) {
var vm = this;
vm.getValue = function() { $window.alert("I am in Controller Scope"); };
})
.directive('myDirective', function() {
return {
scope: {
onGetValue:'&'
},
controllerAs:'vm',
controller: function($scope) {
$scope.onGetValue();
}
};
});
Use services to share data between angular components. This question might be a good start: Share data between AngularJS controllers. This approach will work for sharing data between controller and directive as well
When you are creating your directive, the returning function is called DDO (Directive Defining Object). One of its attributes is 'scope'. if you initialize it with scope : true, the directive will prototypically inherit the parent scope. If you set scope: false, the directive will use the parent scope. And finally, if you set scope : {...}, it will created an isolated scope.
var app = angular.module("test",[]);
app.controller("myCntrl",function($scope){
$scope.text = "Im in controller Scope";
});
app.directive("myDirective", function(){
return {
restrict: "EA",
scope: true,
template: "<div>Where are you, directive ? {{text}}</div>"
};
});
h2 {
cursor: pointer;
}
.directive {
border: 5px solid #F5BF6E;
padding: 10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.22/angular.min.js"></script>
<div ng-app="test">
<div ng-controller="myCntrl">
<h2 ng-click="reverseName()">Where are you ? {{text}}</h2>
<div my-directive class='directive'></div>
</div>
</div>
You can check this link for more details : Directive Scopes
I am referencing the value of the variable in a controller in an ng-class template but its not working.
here is the html directive template URl :
<div class="tooltip-anchor">
<div class=" tooltip-content ehub-body" ng-class="{ 'tooltip__content--disabled': tooltipContentValue}" ng-transclude>Tooltip content</div>
</div>
Here is where i am using the directive in the index page
<div style="text-align:center;">
<ehub-tooltip>Hello i am here, and i am her to stay</ehub-tooltip>over here
<ehub-tooltip>Be nice to people on your way up and they will be nice to you on your way down</ehub-tooltip>click me
</div>
And here is the directive:
in this directive i am creating a variable and setting it to false and also trying to use it in an ng-class attribute
(function (window) {
'use strict';
angular
.module('ehub.component.tooltip', [])
.controller('ehubTooltipCtrl', ['$scope', function ($scope) {
$scope.tooltipContentValue = false;
}])
.directive('ehubTooltip', ehubTooltip);
function ehubTooltip() {
var directive = {
controller: "ehubTooltipCtrl",
link: link,
transclude: true,
templateUrl: 'ehub-tooltip.html',
restrict: 'E'
};
return directive;
function link(scope, element, attrs) {
scope.keyupevt = function () {
if (event.keyCode === 27) {
$scope.tooltipContentValue = true;
}
}
}
}
})();
Try this working jsfiddle.
angular.module('ExampleApp', ['ngMessages'])
.controller('ExampleController', function($scope) {
})
.directive('ehubTooltip', function() {
var directive = {
link: link,
transclude: true,
template: '<div class="tooltip-anchor"><div class=" tooltip-content ehub-body" ng-class="{ \'tooltip__content--disabled\': tooltipContentValue}" ng-transclude>Tooltip content</div></div>',
restrict: 'E'
};
function link(scope, element, attrs) {
scope.tooltipContentValue = false;
scope.keyupevt = function() {
if (event.keyCode === 27) {
scope.tooltipContentValue = true;
}
}
}
return directive;
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="ExampleApp">
<div ng-controller="ExampleController">
<div style="text-align:center;">
<a href="" ng-keyup="keyupevt()">
<ehub-tooltip>Hello i am here, and i am her to stay</ehub-tooltip>over here</a>
<a href="" ng-keyup="keyupevt()">
<ehub-tooltip>Be nice to people on your way up and they will be nice to you on your way down</ehub-tooltip>click me</a>
</div>
</div>
</div>
I have been struggling for a coupe of hours trying to get fancybox to display html template from $templateCache. It all works fine except for the annoying fact the the data binding does not work and I'm not sure how to solve it.
<div ng-controller="MyCtrl">
Hello, {{ templateVariable }}!
<script type="text/ng-template" id="testTemplate.html">
<h1>{{ templateVariable }}</h1>
<p>Bla bla bla</p>
</script>
<br /><br />
<a href="#" show-template>Show template</a>
</div>
var myApp = angular.module('myApp',[]);
myApp.directive('showTemplate', function($templateCache, $compile, $parse) {
return {
restrict: 'A',
link: function (scope, element, attrs, ctrl) {
element.bind('click', function() {
var template = $templateCache.get('testTemplate.html');
var compiled = $compile(template)(scope);
$.fancybox.open(template);
});
}
};
});
myApp.controller('MyCtrl', function($scope) {
$scope.templateVariable = 'My template variable';
});
JSFiddle:
http://jsfiddle.net/oligustafsson/p4f7mh19/
Anyone have any insights to how to accomplish this feat?
To answer my own question, this is what I came up with:
<div ng-controller="MyCtrl">
Hello, {{ templateVariable }}!
<script type="text/ng-template" id="testTemplate.html">
<div>
<h1>{{ templateVariable }}</h1>
<p>Bla bla bla</p>
<div>Mooo</div>
</div>
</script>
<br /><br />
Show template
</div>
I wrapped the template html in a div.
var myApp = angular.module('myApp',[]);
myApp.directive('showTemplate', function($templateCache, $compile, $timeout) {
return {
restrict: 'A',
link: function (scope, element, attrs, ctrl) {
element.bind('click', function() {
$timeout( function(){
var template = $templateCache.get('testTemplate.html');
var linkFn = $compile(template);
var linkedContent = linkFn(scope);
$.fancybox.open(linkedContent);
}, 0)
});
}
};
});
myApp.controller('MyCtrl', function($scope) {
$scope.templateVariable = 'My template variable';
});
Finding some other suggestions like using $timeout and $compile, this seems to work just fine.
JSFiddle: http://jsfiddle.net/oligustafsson/vpbutty0/
Thanx!
What is the idiomatic way to get an elements siblings when it is clicked using AngularJS?
So far I've got this:
<div ng-controller="FooCtrl">
<div ng-click="clicked()">One</div>
<div ng-click="clicked()">Two</div>
<div ng-click="clicked()">Three</div>
</div>
<script>
function FooCtrl($scope){
$scope.clicked = function()
{
console.log("Clicked", this, arguments);
};
}
</script>
here's a jQuery implementation as a concrete example:
<div id="foo">
<div>One</div>
<div>two</div>
<div>three</div>
</div>
<script>
$(function(){
$('#foo div').on('click', function(){
$(this).siblings('div').removeClass('clicked');
$(this).addClass('clicked');
});
});
</script>
Use a directive, since you want to traverse the DOM:
app.directive('sibs', function() {
return {
link: function(scope, element, attrs) {
element.bind('click', function() {
element.parent().children().removeClass('clicked');
element.addClass('clicked');
})
},
}
});
<div sibs>One</div>
<div sibs>Two</div>
<div sibs>Three</div>
Note that jQuery is not required.
fiddle
Here is an angular version of the jQuery sample that you provided:
HTML:
<div ng-controller="FooCtrl">
<div ng-click="selected.item='One'"
ng-class="{clicked:selected.item=='One'}">One</div>
<div ng-click="selected.item='Two'"
ng-class="{clicked:selected.item=='Two'}">Two</div>
<div ng-click="selected.item='Three'"
ng-class="{clicked:selected.item=='Three'}">Three</div>
</div>
JS:
function FooCtrl($scope, $rootScope) {
$scope.selected = {
item:""
}
}
NOTE: You dont strictly need to access DOM for this. However if you still want to then you can write a simple directive. Something like below:
HTML:
<div ng-controller="FooCtrl">
<div ng-click="clicked()" get-siblings>One</div>
<div ng-click="clicked()" get-siblings>Two</div>
<div ng-click="clicked()" get-siblings>Three</div>
</div>
JS:
yourApp.directive('getSiblings', function() {
return {
scope: true,
link: function(scope,element,attrs){
scope.clicked = function () {
element.siblings('div').removeClass('clicked');
element.addClass('clicked');
}
}
}
});
fiddle
Following is a directive built exclusively with Angular grammar (borrowing from jqLite):
link: function(scope, iElement, iAttributes, controllers) {
var parentChildren,
mySiblings = [];
// add a marker to this element to distinguish it from its siblings
// this could be a lot more robust
iElement.attr('rsFindMySiblings', 'anchor');
// get my parent's children, it will include me!
parentChildren = iElement.parent().children();
// remove myself
scope.siblings = [];
for (var i=0; i < parentChildren.length; i++) {
var child = angular.element(parentChildren[i]);
var attr = child.attr('rsFindMySiblings');
if (!attr) {
scope.siblings.push({name: child[0].textContent});
}
}
}
Note that it uses a controller to store the results. See this plunker for a detailed example