Passing HTML into TemplateURL using directive - angularjs

I am trying to get the HTML inside the directive tag into the template file and render it on the screen
HTML
<insert-test-tab><b>Put this text in the template test.html</b></insert-test-tab>
script.js
directive('insertTestTab', function() {
return {
replace: true,
link: function (scope, element, attr) {
},
templateUrl: function (elem, attr) {
return 'test.html'
},
}
}
test.html
<div>
<p>bla bla bla</p>
<p>[[I want to get that HTML inside <insert-test-tab> here]]</p>
</div>
Desired output
<div>
<p>bla bla bla</p>
<b>Put this text in the template test.html</b>
</div>
Thank you.

Directive definition:
directive('insertTestTab', function() {
return {
replace: true,
transclude: true,
link: function (scope, element, attr) {
}, templateUrl: function (elem, attr) {
return 'test.html'
},
}
}
test.html:
<div>
<p>bla bla bla</p>
<p><ng-transclude></ng-transclude></p>
</div>

You can achieve this using directive tranclude feature.
So your directive definition should be as follows :
directive('insertTestTab', function() { return {
replace: true,
transclude: true,
link: function (scope, element, attr) {
}, templateUrl: function (elem, attr) {
return 'test.html'
},
}
}
And test.html should::
<div>
<p>bla bla bla</p>
<p><ng-transclude></ng-transclude></p>
</div>
Hope this will work for you(Ref:: https://codepen.io/pankajbadukale/pen/aVbGaM)

Related

Parent directive controller undefined when passing to child directive

I asked general question here in this post. I've got answer with working example; however when I try to use this example to modify existing code, I get error.
See my code below and in this Plunker page.
Html
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.3/angular.min.js"></script>
<div ng-app="myApp">
<tmp-menu ng-disabled="true">
<tmp-menu-link></tmp-menu-link>
<tmp-menu-link></tmp-menu-link>
</tmp-menu>
</div>
JavaScript(AngularJS):
angular.module('myApp', [])
.controller('MyDirectiveController', MyDirectiveController)
.directive('tmpMenu', function() {
return {
restrict: 'AE',
replace:true,
transclude:true,
scope:{
disabled: '=?ngDisabled'
},
controller: 'MyDirectiveController',
template: '<div>myDirective Disabled: {{ disabled }}<ng-transclude></ng-transclude></div>',
link: function(scope, element, attrs) {
}
};
})
.directive('tmpMenuLink', function() {
return {
restrict: 'AE',
replace:true,
transclude:true,
scope:{
},
required:'^^tmpMenu',
template: '<div>childDirective disabled: {{ disabled }}</div>',
link: function(scope, element, attrs, MyDirectiveCtrl) {
console.log(MyDirectiveCtrl);
scope.disabled = MyDirectiveCtrl.isDisabled();
}
};
})
function MyDirectiveController($scope) {
this.isDisabled = function() {
return $scope.disabled;
};
}
Inside directive tmpMenuLink, MyDirectiveCtrl is undefined.
Why is that?
You have a typo in your code:
required:'^^tmpMenu',
change it to
require:'^^tmpMenu',
Check this plunkr
https://plnkr.co/edit/DgyW3OFgr1GyAR8fuATi?p=preview
Because it's require not required.
angular.module('myApp', [])
.controller('MyDirectiveController', MyDirectiveController)
.directive('tmpMenu', function() {
return {
restrict: 'AE',
replace: true,
transclude: true,
scope: {
disabled: '=?ngDisabled'
},
controller: 'MyDirectiveController',
template: '<div>myDirective Disabled: {{ disabled }}<ng-transclude></ng-transclude></div>',
link: function(scope, element, attrs) {}
};
})
.directive('tmpMenuLink', function() {
return {
restrict: 'AE',
replace: true,
transclude: true,
require: '^^tmpMenu',
template: '<div>childDirective disabled: {{ disabled }}</div>',
link: function(scope, element, attrs, MyDirectiveController) {
scope.disabled = MyDirectiveController.isDisabled();
}
};
})
function MyDirectiveController($scope) {
this.isDisabled = function() {
return $scope.disabled;
};
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.3/angular.min.js"></script>
<div ng-app="myApp">
<tmp-menu ng-disabled="true">
<tmp-menu-link></tmp-menu-link>
<tmp-menu-link></tmp-menu-link>
</tmp-menu>
</div>

Call a callback function after rendering the anchor in angularjs

I've the following HTML in my layout:
<div class="icon-grid">
<a ng-if="udtTable.config.moreActionIcons" ng-repeat="mai in udtTable.config.moreActionIcons"
ng-attr-data-toggle="{{(mai.modal) ? \'modal\' : undefined}}"
ng-attr-data-target="{{(mai.modalName && mai.modal) ? mai.modalName : undefined}}"
after-render="{{mai.callback}}"
href="{{mai.action}}/{{value.data.id}}"
title="{{mai.tooltip}}">
<span class="{{mai.icon}}"></span>
</a>
</div>
Here is my after-render directive:
angular.module('neogetDataTableServices').directive('afterRender', ['$timeout', function ($timeout) {
var def = {
restrict: 'A',
terminal: true,
transclude: false,
link: function (scope, element, attrs) {
console.log(attrs.afterRender);
}
};
return def;
}]);
Here is my object to repeat
var udtTable = {
config: {
"moreActionIcons" : [
{
"action": 'myaction.php',
"icon": "icomoon-lock-open",
"modal": true,
"modalName": "#mkjax-modal",
"tooltip":"Authorize",
"callback": function() {
alert('hey rendered');
}
},
]
}
}
Now the problem is if I write this line
after-render="helloworld"
Then my directive after-render logs it properly through console.log(attrs.afterRender);
But if I write this like below:
after-render="{{mai.callback}}"
Then the directive doesn't logs function() { alert('hey rendered'); } It says that it is an empty string.
Anybody has the solution?
Try like this:
angular.module('neogetDataTableServices').directive('afterRender', ['$timeout', function ($timeout) {
var def = {
restrict: 'A',
terminal: true,
transclude: false,
link: function (scope, element, attrs) {
scope.$eval(attrs.afterRender);
}
};
return def;
}]);
In html:
after-render="mai.callback()"
It would be better to use an isolated scope.
angular.module('neogetDataTableServices').directive('afterRender', ['$timeout', function ($timeout) {
var def = {
restrict: 'A',
terminal: true,
transclude: false,
scope:{
afterRender:"&"
},
link: function (scope, element, attrs) {
console.log(scope.afterRender);
}
};
return def;}]);
In this case, angular will interpret attribute as a function.
in html
after-render="mai.callback()"

Get image src within directive

I have a directive with an img tag inside it.
angular.module('example')
.directive('customDirective', function() {
return {
restrict: 'E',
replace: true,
transclude: true,
scope: {}, //isolate scope
templateUrl: 'directives/customDirective.html'
link: function(scope, element, attrs) {
// returns undefined
console.log(element.find('img').src);
}
};
});
the directive template:
<div class="customDirective">
<img src="image.jpg" />
</div>
I'm trying to get a hold of the src attribute on the image tag.
var src = element.find('img').attr('src');
This is assuming there is only a single img tag.
It would probably be easier to set the source in your directive.
Directive
angular.module('example')
.directive('customDirective', function() {
return {
restrict: 'E',
replace: true,
transclude: true,
templateUrl: 'directives/customDirective.html'
link: function(scope, element, attrs) {
scope.imgSrc = 'image.jpg';
}
};
});
Template
<div class="customDirective">
<img ng-src="{{imgSrc}}" />
</div>
Then your code drives the template instead of you needing to read data out of the template.

Add html content after directive template

Having this HTML :
<div messages>
Some content...
</div>
This directive :
myAppDirectives.directive("messages", function () {
return {
restrict: 'A',
templateUrl: '/directives/messages/messages.html',
link: function (scope, elem, attrs) {
//...
}
};
});
And messages.html :
<p>message1</p>
<p>message2</p>
The content of my html gets replaced by the directive template but i'd like it to just be appended.
Html becomes this :
<div messages>
<p>message1</p>
<p>message2</p>
</div>
But I'd like this :
<div messages>
<p>message1</p>
<p>message2</p>
Some content...
</div>
Is this possible without using ng-include?
This looks like a perfect situation to use ngTransclude.
Try:
myAppDirectives.directive("messages", function () {
return {
restrict: 'A',
transclude: true,
templateUrl: '/directives/messages/messages.html',
link: function (scope, elem, attrs) {
//...
}
};
});
messages.html:
<p>message1</p>
<p>message2</p>
<ng-transclude></ng-transclude>
If you really want this behaviour, use transclusion:
myAppDirectives.directive("messages", function () {
return {
restrict: 'A',
transclude: true,
templateUrl: '/directives/messages/messages.html',
link: function (scope, elem, attrs) {
//...
}
};
});
And the template becomes:
<p>message1</p>
<p>message2</p>
<span ng-transclude></span>
The original content of the <div messages> element will be wrapped in the <span ng-transclude>, but this should not harm.

AngularJS - accessing parent directive properties from child directives

This should not be too hard a thing to do but I cannot figure out how best to do it.
I have a parent directive, like so:
directive('editableFieldset', function () {
return {
restrict: 'E',
scope: {
model: '='
},
replace: true,
transclude: true,
template: '
<div class="editable-fieldset" ng-click="edit()">
<div ng-transclude></div>
...
</div>',
controller: ['$scope', function ($scope) {
$scope.edit = ->
$scope.editing = true
// ...
]
};
});
And a child directive:
.directive('editableString', function () {
return {
restrict: 'E',
replace: true,
template: function (element, attrs) {
'<div>
<label>' + attrs.label + '</label>
<p>{{ model.' + attrs.field + ' }}</p>
...
</div>'
},
require: '^editableFieldset'
};
});
How can I easily access the model and editing properties of the parent directive from the child directive? In my link function I have access to the parent scope - should I use $watch to watch these properties?
Put together, what I'd like to have is:
<editable-fieldset model="myModel">
<editable-string label="Some Property" field="property"></editable-string>
<editable-string label="Some Property" field="property"></editable-string>
</editable-fieldset>
The idea is to have a set of fields displayed by default. If clicked on, they become inputs and can be edited.
Taking inspiration from this SO post, I've got a working solution here in this plunker.
I had to change quite a bit. I opted to have an isolated scope on the editableString as well because it was easier to bind in the correct values to the template. Otherwise, you are going to have to use compile or another method (like $transclude service).
Here is the result:
JS:
var myApp = angular.module('myApp', []);
myApp.controller('Ctrl', function($scope) {
$scope.myModel = { property1: 'hello1', property2: 'hello2' }
});
myApp.directive('editableFieldset', function () {
return {
restrict: 'E',
scope: {
model: '='
},
transclude: true,
replace: true,
template: '<div class="editable-fieldset" ng-click="edit()"><div ng-transclude></div></div>',
link: function(scope, element) {
scope.edit = function() {
scope.editing = true;
}
},
controller: ['$scope', function($scope) {
this.getModel = function() {
return $scope.model;
}
}]
};
});
myApp.directive('editableString', function () {
return {
restrict: 'E',
replace: true,
scope: {
label: '#',
field: '#'
},
template: '<div><label>{{ label }}</label><p>{{ model[field] }}</p></div>',
require: '^editableFieldset',
link: function(scope, element, attrs, ctrl) {
scope.model = ctrl.getModel();
}
};
});
HTML:
<body ng-controller="Ctrl">
<h1>Hello Plunker!</h1>
<editable-fieldset model="myModel">
<editable-string label="Some Property1:" field="property1"></editable-string>
<editable-string label="Some Property2:" field="property2"></editable-string>
</editable-fieldset>
</body>
You can get access to parent controller by passing attribute in child directive link function
link: function (scope, element, attrs, parentCtrl) {
parentCtrl.$scope.editing = true;
}

Resources