AngularJS - How do I insert compiled HTML into my directive template? - angularjs

I'm pretty sure I'm doing this the wrong way, so any help would be appreciated...
Given the following plunker: http://plnkr.co/edit/hCjTdt8XmlVPKGgzvgFu?p=preview
I'm trying to compile some Html and insert it in a specific location in my template. However, I'm getting an error:
Can't interpolate: My Value: {{innerHtml}}
TypeError: Converting circular structure to JSON
I'm pretty sure this is because I'm attempting to insert the entire element as Html, but I'm not sure how to accomplish what I'm trying to do.
Plunker code:
<!DOCTYPE html>
<html>
<head>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
</head>
<body ng-app='myApp'>
<div ng-controller='TestCtrl'>
<test-directive></test-directive>
</div>
<script>
var app = angular.module('myApp', []);
app.controller("TestCtrl", ['$scope', function($scope) {
$scope.myValue = "Hello, World!";
}]);
app.directive('testDirective', ['$compile', function($compile) {
return {
restrict: 'E',
template: "<h1>Title</h1>My Value: {{innerHtml}}",
link: function (scope, element, attr) {
scope.innerHtml = $compile("<input type='text' ng-model='myValue' />")(scope);
}
}
}]);
</script>
</body>
</html>

I think you may be confused by trying to access innerHtml on your scope? I think you need to be accessing your element to insert DOM. The element will be basically whatever's in your template, but already compiled (link happens after compile). So you can compile and add it to your element.
Try this:
element.append($compile("<input type='text' ng-model='myValue' />")(scope));
instead of scope.innerHtml line. Working in plnkr: http://plnkr.co/edit/z3k6BPVNcNxi6d4XBfXX?p=preview

Related

angularjs - access transclude html scope from hosting directive

I have a simple directive with transcluded html.
I want to be able to inject directive scope params to the transclude.
I wrote a simple example in plunker :
https://plnkr.co/edit/jqyiQdgQxbeTrzyidZYF?p=preview
I know in angular 4 it can be done, but I can't find a good way to do it in angularjs.
// Code goes here
var app = angular.module("app", []);
app.controller("mainCtrl", function($scope) {
$scope.users = ["tal", "oren", "orel", "shluki"];
$scope.deleteUser = (user) => {alert("trying to delete", user);}
});
app.directive('myList', function myList() {
return {
restrict: 'E',
transclude: true,
template: "<div><table><tr ng-repeat='item in collection'><td> This is inside myList - user name: {{item}} <ng-transclude></ng-transclude></td></tr></table></div>",
scope: {
collection: "="
},
replace: true
};
});
<!DOCTYPE html>
<html>
<head>
<script data-require="angularjs#1.6.2" data-semver="1.6.2" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.2/angular.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body ng-app="app" ng-controller="mainCtrl">
<h1>Hello Plunker!</h1>
<my-list collection="users">
<h2>This is transclude</h2>
<button ng-click="deleteUser(user)">Delete user: {{user ? user : "User name should be here"}}</button>
</my-list>
</body>
</html>
Will really appreicate some help.
plunker: https://plnkr.co/edit/jqyiQdgQxbeTrzyidZYF?p=preview
Here's a working plunker with your example.
http://plnkr.co/edit/BjSowyQdLXd0xoCZFqZ6?p=preview
The idea is to pass it as contents and not html as string. $compile is here because the link is done after ng-repeats already has transcluded its own template.
var template = '<h1>I am foo</h1>\
<div ng-repeat="item in users">\
<placeholder></placeholder>\
<hr>\
</div>';
var templateEl = angular.element(template);
transclude(scope, function(clonedContent) {
templateEl.find("placeholder").replaceWith(clonedContent);
$compile(templateEl)(scope, function(clonedTemplate) {
element.append(clonedTemplate);
});
});
If you want a proper explanation of what the problem was you should check the detailed answer here : Pass data to transcluded element
Hope this helped you out

AngularJs dynamic Event handler without using directive

<body ng-controller="MyController">
<mydirective></mydirective>
</body>
Is there any way in AngularJS to attach dynamic event without using directive tag because it may need to add additional tag in html.
<!DOCTYPE html>
<html ng-app="appname">
<head>
<script src="http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.20/angular.min.js"></script>
</head>
<body ng-controller="MyController">
<mydirective></mydirective>
</body>
<script>
var app = angular.module('appname', []);
app.controller('MyController', function($scope){
});
app.directive('mydirective', function(){
return {
restrict: 'E',
link: function(scope, elem, attrs){
angular.element(document).bind('mousedown', function(){
console.log('clicked on document');
});
}
}
});
</script>
</html>
Sure you can. Take a look at the following JSFiddle.
However, always and always remember to unbind events as well, otherwise it might lead to memory leaks and other unwanted scenarios.
var buttonElement = angular.element('#myButton');
buttonElement.bind('click', function (e) {
alert('This is a code bound event');
});
Also, using directives such as 'ng-click', ng-mouseover' is always advised, since these are well-developed and well-tested by thousands and thousands of developers. It will help you to develop robust applications
JSFiddle: Bind events through code << Updated the fiddle based on OP's comments

AngularJS isolate scope with collection does not work

I want to use multiple instances of the same directive to render a collection. I am using an isolate scope to map an array to a name in the isolate scope. The link function in the isolate scope correctly sees the mapped array, however ng-repeat in it does not work.
<html ng-app="MyApp">
<head>
<script type="text/javascript" src="angular.js"></script>
<script type="text/javascript">
var MyCtrl = function($scope) {
$scope.blah = [1,2,4,5];
$scope.bar = [14,52,64,25];
}
angular.module("MyApp", [])
.directive("sephBlah", function($parse) {
return {
scope: {
tags: "=sephBlah"
},
link: function(scope, elem, attrs) {
console.log(scope.tags[0]);
}
}
});
</script>
</head>
<body ng-controller="MyCtrl">
<div seph-blah="blah">
<p data-ng-repeat="t in tags">{{t}}</p><!-- why this renders nothing? -->
</div>
<div seph-blah="bar">
<p data-ng-repeat="t in tags">{{t}}</p><!-- why this renders nothing? -->
</div>
</body>
</html>
I am not sure why the ng-repeat renders nothing. The link function correctly sees the arrays.
You're not supposed to use directives like this. The sort of functionality you're trying to get here should be done with a controller.
When using directives, use the template or templateUrl attribute to provide content. So this will work:
.directive("sephBlah", function($parse) {
return {
scope: {
tags: "=sephBlah"
},
template: '<p data-ng-repeat="t in tags">{{t}}</p>',
link: function(scope, elem, attrs) {
console.log(scope.tags[0]);
}
}
});
And in the html just do:
<div ng-attr-seph-blah="blah"></div>

Required angular directive not found

I am trying to understand the execution of link function in angular directives. However, I am stuck in a very simple setup. Following is the html code:
<!doctype html>
<html ng-app="demoApp">
<body>
<div ng-controller="DemoController" class="container">
<directiveone directivetwo ></directiveone>
</div>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular.min.js"></script>
<script src="app.js"></script>
</body>
</html>
"demoApp" is defined in app.js as follows:
angular.module('demoApp', [])
.controller("DemoController", function(){
})
.directive("directiveone", function(){
var linker = function(scope, element, attrs){
console.log("directiveone link called");
};
return {
link : linker
}
})
.directive("directivetwo", function(){
var linker = function(scope, element, attrs){
console.log("directivetwo link called");
};
return {
require: "directiveone",
link : linker
};
});
When I run this code, I get the error:
Controller 'directiveone', required by directive 'directivetwo', can't be found!
I am unable to figure out the error here. Documentation suggests it might be a typo, but it is not apparent to me.
Directives default to attribute-only. Your directiveone directive isn't being picked up - you need to specify restrict: 'E' in its definition, or apply it as an attribute (<div directiveone directivetwo>...)

Angular js directive issue

Below is my code
I created a simple page and include a directive in it. And on ng-click in directive i want to call parent scope's method.
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Directive Page</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular.min.js"> </script>
</head>
<body>
<div ng-app="myapp" ng-controller="myController">
<ul-dir on-item-click="itemClick(obj)"></ul-dir>
</div>
</body>
</html>
<script>
var myapp = angular.module("myapp", []);
myapp.directive('ulDir', function() {
return {
restrict: 'E',
replace: 'true',
template: '<div id="container"><ul><li ng-repeat="content in contents">{{content.name}}</li></ul></div>',
controller: function ($scope) {
$scope.contents = [{'name':'Nishu', 'age':'20'},{'name':'Nidhi', 'age':'21'},{'name':'Kirti', 'age':'24'}];
},
scope: {
onItemClick: '&' // Pass a reference to the method
}
}
});
myapp.controller('myController', function($scope) {
$scope.itemClick = function(content){
console.log("Success : "+content);
};
});
</script>
So my console log print as "success : undefined"
So content object not passing from directive scope to parentscope.
Please help me.
I believe your call inside template should either be:
<a href="#" ng-click="onItemClick({'content':content})">
or
<a href="#" ng-click="onItemClick({'obj':content})">
Can you try. For more details see this SO post Can an angular directive pass arguments to functions in expressions specified in the directive's attributes?

Resources