Angularjs templateUrl fails to bind attributes inside ng-repeat - angularjs

I'm using directive to display html snippets.
And templateUrl inside the directive,
to be able to include snippets as html file.
The directive does not work, if I try to call
inside a builtin ng-repeat directive
({{snip}} is passed as is, without substitute):
div ng-repeat="snip in ['snippet1.html','snippet2.html']">
<my-template snippet="{{snip}}"></my-template>
</div>
For reference, here is the directive:
app.directive("myTemplate", function() {
return {
restrict: 'EA',
replace: true,
scope: { snippet: '#'},
templateUrl: function(elem, attrs) {
console.log('We try to load the following snippet:' + attrs.snippet);
return attrs.snippet;
}
};
});
And also a plunker demo.
Any pointer is much appreciated.
(the directive is more complicated in my code,
I tried to get a minimal example, where the issue is reproducible.)

attrs param for templateUrl is not interpolated during directive execution. You may use the following way to achieve this
app.directive("myTemplate", function() {
return {
restrict: 'EA',
replace: false,
scope: { snippet: '#'},
template: '<div ng-include="snippet"></div>'
};
});
Demo: http://plnkr.co/edit/2ofO6m45Apmq7kbYWJBG?p=preview

Check out this link
http://plnkr.co/edit/TBmTXztOnYPYxV4qPyjD?p=preview
app.directive("myTemplate", function() {
return {
restrict: 'EA',
replace: true,
scope: { snippet: '=snippet'},
link: function(scope, elem, attrs) {
console.log('We try to load the following snippet:' + scope.snippet);
},
template: '<div ng-include="snippet"></div>'
};
})

You can use ng-include, watching the attrs. Like this:
app.directive("myTemplate", function() {
return {
restrict: 'E',
replace: true,
link: function(scope, elem, attrs) {
scope.content = attrs.snippet;
attrs.$observe("snippet",function(v){
scope.content = v;
});
},
template: "<div data-ng-include='content'></div>"
};
});

Just made changes in directive structure. Instead of rendering all templates using ng-repeat we will render it using directive itself, for that we will pass entire template array to directive.
HTML
<div ng-init="snippets = ['snippet1.html','snippet2.html']">
<my-template snippets="snippets"></my-template>
</div>
Directive
angular.module('myApp', [])
.controller('test',function(){})
.directive("myTemplate", function ($templateCache, $compile) {
return {
restrict: 'EA',
replace: true,
scope: {
snippets: '='
},
link: function(scope, element, attrs){
angular.forEach(scope.snippets, function(val, index){
//creating new element inside angularjs
element.append($compile($templateCache.get(val))(scope));
});
}
};
});
Working Fiddle
Hope this could help you. Thanks.

it seems you are trying to have different views based on some logic
and you used templateUrl function but Angular interpolation was not working, to fix this issue
don't use templateUrl
so how to do it without using templateUrl
simply like this
app.directive("myTemplate", function() {
return {
link: function(scope, elem, attrs) {
$scope.templateUrl = '/ActivityStream/activity-' + $scope.ativity.type + '.html'
},
template: "<div data-ng-include='templateUrl'></div>"
};
});
hope this is simple and esay to understand

Related

scope variable of the controller is not recognized in nested directives

I have created two directives and inserted the first directive into the second one. The content of template attribute works fine but the scope variable of the controller is not recognized. Please provide me solution on this
sample link: http://jsbin.com/zugeginihe/2/
You didn't provide the attribute for the second directive.
HTML
<div second-dir first-dir-scope="content">
<div first-dir first-dir-scope="content"></div>
</div>
Link demo: http://jsbin.com/jotagiwolu/2/edit
The best option would using parent directive, We could take use of require option of directive like require: '?secondDir' in firstDir
Code
var myApp = angular.module("myApp", []);
myApp.controller("myController", function($scope) {
$scope.content = "test1";
});
myApp.directive("firstDir", function() {
return {
restrict: "AE",
require: '?secondDir',
scope: {
firstDirScope: "="
},
template: "<div>first content</div>",
link: function(scope, element, attrs, secondDir) {
console.log(scope.firstDirScope, 'first');
}
};
});
myApp.directive("secondDir", function() {
return {
restrict: "AE",
scope: {
firstDirScope: "="
},
controller: function($scope) {
console.log($scope.firstDirScope, 'second');
}
};
});
Working JSBin

Calling service method from a directive template

Let's say I have a directive:
<component>
<img ng-src='{{something}}' />
</component>
defined as:
app.directive("component", function() {
return {
scope: {},
restrict: 'E',
transclude: true,
template: "<a href='' ng-click='MyService.doThings()' ng-transclude></a>"
}
});
Despite all my efforts, I fail to understand how to accomplish two tasks:
How do I access the inner image source path?
How can I pass this path to service MyService? (think of a lightbox wrapper)
Update with solution:
app.directive("component", function(LightboxService) {
return {
restrict: 'E',
transclude: true,
replace: true,
template: "<a href='' ng-click='lb()' ng-transclude></a>",
link: function (scope, element, attrs) {
scope.lb = function () {
var src = $(element).find("img").attr("src");
LightboxService.show(src);
}
}
}
});
You can access the source path either by binding it to your controller scope or from a link method using attributes.
You can not access Service from a template. You should inject your service into a controller and define a function in $scope to call from the template.
Check your directive below:
app.directive("component", function() {
return {
scope: {
ngSrc: "#", //Text Binding
},
controller: function($scope, MyService) {
$scope.doThings = function() {
MyService.doThings();
}
},
restrict: 'E',
transclude: true,
template: "<a href='{{ng-src}}' ng-click='doThings' ng-transclude></a>"
}
});
You can learn more about directives with isolated scope here:
https://umur.io/angularjs-directives-using-isolated-scope-with-attributes/

How can I pass a template to a directive in an attribute?

I want to pass a template to a directive like this:
<my-directive template="/templates/my-directive-template.html"></my-directive>
If no template is provided then the standard template is used.
How can I achieve this?
Or shouldn't I do this? I just want to reuse a directive, but want to give it different appearances each time.
Here's the directive... but I'm stuck on how to move forward.
app.directive('my-directive', function(){
return {
restrict: 'E',
scope: {
template: '=template'
},
template: 'standard-template.html'
}
})
templateUrl can be a function, that gets the element and its attributes as arguments. So you can do the following:
app.directive('my-directive', function(){
return {
restrict: 'E',
templateUrl: function(element, attrs) {
return attrs.template || 'standard-template.html';
}
You could use ng-include. So as an example
app.directive('my-directive', function(){
return {
restrict: 'E',
scope: {
template: '=?'
},
template: '<div ng-include="directiveTemplate"></div>',
link: function (scope) {
scope.directiveTemplate = scope.template || '/path/to/default.tpl.html';
}
}
})

Prevent angular from copying attributes when replace=true

The following directive:
var app = angular.module('demo', []);
app.directive('myDirective', function() {
return {
restrict: 'E',
template: '<h1>Foo bar</h1>'
};
});
With the following usage:
<my:directive foo="bar"></my:directive>
Renders the following HTML:
<my:directive foo="bar"><h1>Foo bar</h1></my:directive>
Since I want to replace my directive with the provided template I set replace:true. This produces the following HTML:
<h1 foo="bar">Foo bar</h1>
Note that Angular copies my directive's attributes to the template elements (the foo="bar"). How can I prevent this behaviour?
You can manually remove the attributes in the link function of the directive:
.directive('myDirective', function() {
return {
restrict: 'E',
replace: true,
template: '<h1>Foo bar</h1>',
link: function(scope, elm, attrs){
elm.removeAttr('foo');
}
};
});
Here's a fiddle with this directive working in your situation.
EDIT: You can extend this to remove all attributes dynamically with a simple loop:
.directive('myDirective', function() {
return {
restrict: 'E',
replace: true,
template: '<h1>Foo bar</h1>',
link: function(scope, elm, attrs){
for(var attr in attrs.$attr){
elm.removeAttr(attr);
}
}
};
});

How can I get my directive to access the controllers scope

I have a setup like this:
<controller>
<directive>
in my controller that has a function that returns an html string. How can I get my directive to render this by accessing the controllers scope?
Or maybe I should just put the controller in the directive?
app.controller('controller', ['$scope', 'DataService', function ($scope, DataService) {
$scope.parseJson = function () {
//returns the html
};
}]);
directive
app.directive('Output', function () {
return {
restrict: 'A',
replace: true,
template: '<need html from controller>',
link: function(scope, element, attr) {
//render
//scope.parseJson();
}
};
});
You should use the isolated scope: '&' option
app.directive('output', ['$sce', function ($sce) {
return {
restrict: 'A',
replace: true,
template: "<div ng-bind-html='parsed'></div>",
scope:{
output: "&"
},
link: function(scope){
scope.parsed = $sce.trustAsHtml(scope.output());
}
};
}]);
Template:
<div output="parseJson()"></div>
The directive and the controller should be sharing the scope already. Don't bother using a template for the directive, just get the HTML string in you linking function (you already have the method call in there) and modify the element directly using element.html(). Take a look at the element docs for more info.
app.directive('Output', function ($compile) {
return {
restrict: 'A',
link: function(scope, element, attr) {
var templateString = scope.parseJson();
var compiledTemplate = $compile(templateString)(scope);
compiledTemplate.appendTo("TheElementYouWishtoAppendYourDirectiveTo");
}
};
});

Resources