Angular Directive parent template? - angularjs

Let's say I have something like:
<body>
<section id="page_content">
<div myDirective></div>
</section>
</body>
And I want my AngularJS directive to return:
<body>
<div id="newDivFromDirective">
...with some stuff inside!
</div>
<section id="page_content">
<div myDirective></div>
</section>
</body>
I currently have:
myAngularApp.directive('myDirective', function() {
return {
template: '<div id="newDivFromDirective" style="display: none">' +
'...with some stuff inside!' +
'</div>'
}
});
But that doesn't return the result I need. I looked into using link - but unsure how I can use template with link too and then get element.parent I guess?

You can use the Node.insertBefore() function to move the element to somewhere else in the link function. Based on the structure above, you want it to be before the parent element so you need to basically do grandParentNode.insertBefore(directiveElemNode,parentNode).
Here is a simplified directive code that you can use:
app.directive('myDirective', function() {
return {
template: "<div>... some text</div>",
link: function(scope,elem,attrs) {
var myParent = elem.parent();
var newParent = myParent.parent();
newParent[0].insertBefore(elem[0],myParent[0]);
}
};
});
If as you said you don't mind it being after the <section> element then you can also do myParent.after(elem)
Node.insertBefore() - https://developer.mozilla.org/en-US/docs/Web/API/Node.insertBefore
Sample plunker - http://plnkr.co/edit/FD08cP4aj0InJwf8okeC?p=preview

Related

Calling controller from directive

I am trying to call a controller from directive....Here is the code which i am writing
penApp.directive('enpo', function() {
return {
restrict: 'E',
scope: {
info: '=',
dragEvent: '&dragParent'
},
templateUrl: 'enpo.html',
link: function(scope, element, attrs){
var circleDiv = element.find(".circle")
element.droppable({
})
element.draggable({
handle: ".circle",
drag: function( event, ui ) {
scope.dragEvent();
}
});
var eDiv = element.find(".temp")
$(eDiv).draggable({revert: true});
}
};
})
and this is the code for .html file
<div class="row ">
<div id="n_div" class="col-xs-12 dd_area">
<end-point drag-parent="drawLine()" ng-repeat="info in stageObjectArray" info="info"></end-point>
</div>
</div>
and this is the function i have written in controller
$scope.drawLine = function(){
console.log("Called thsssssse function")
}
I am not able to figure out what is going wrong here...can anyone please guide...the controller function is not getting called
Can you please be a little clearer what each piece of code is?
Hope this will help you out:
Looks to me like you have created a directive with a link function and an html template.
From the HTML template you are trying to call the function in a controller that you have written, however I do not see that you are attaching the controller to the HTML, where you want to use it.
Try adding ng-controller="MyController" (MyController being the name of your controller which contains the $scope.drawline function) to your HTML, as follows:
<div class="row ">
<div id="n_div" class="col-xs-12 dd_area" ng-controller="MyController">
<end-point drag-parent="drawLine()" ng-repeat="info in stageObjectArray" info="info"></end-point>
</div>
</div>
BTW, I don't see where you are actually using your 'enpo' directive in your HTML. I am assuming that you are in fact calling it, but omitted that part of the code here.

generate dynamic html on ng click

I want to insert dynamic html element which contains ng-bind and directive on ng-click. I want to insert new html elements inside
Html looks like this
<body data-ng-controller="controller">
<div id="toolbox">
<label>Page Width</label>
<input type="text" data-ng-model="pageWidth" />
<input type="button" value="H1" data-ng-click="createH1()" />
</div>
<div id="editor">
<div data-ng-style="{width:pageWidth + 'px'}" data-ng-page>
</div>
</div>
</body>
Controller >
app.controller('controller', ['$scope', function ($scope) {
$scope.createH1 = function () {
document.getElementById("page").innerHTML = document.getElementById("page").innerHTML + ("<div class='h1' data-ng-h1 draggable></div>");
};
}]);
The above controller is inserting html element, but the directives of new html elements are not working.
However I came to know that unless we $compile template/html they'll not work. If I use app.directive( ngPage, ..) to add my dynamic html, it is inserting while app is started. But I want to insert only on button ng-click.
I'm new to angular js, a bit confused please help me out with this.
Thanks in advance.
I will Always prefer to do DOM manipulation from directive. So here code will look like below
HTML
<body ng-controller="MainCtrl as vm">
<button add-html>click me</button>
<div id="page">
This will be replaced by text
</div>
</body>
CODE
app.directive('addHtml', function($compile){
return {
restrict: 'AE',
link: function(scope, element, attrs){
var html = `<div class='h1' data-ng-h1 draggable>Test</div>`,
compiledElement = $compile(html)(scope);
element.on('click', function(event){
var pageElement = angular.element(document.getElementById("page"));
pageElement.empty()
pageElement.append(compiledElement);
})
}
}
});
Plunkr Here

ng-include not working with script type="text/ng-template"

Here is my Plunker:
http://plnkr.co/edit/oIei6gAU1Bxpo8VUIswt
When the button is clicked, the following should be inserted before the "Hello World!" span:
<script type="text/ng-template" id="tempTest">
<div>
<span>Properly Inserted</span>
</div>
</script>
minus the script tags, of course.
I achieve this by dynamically inserting the following div:
<div ng-include="tempTest"></div>
And then compiling it. However, if you look at the log, the only thing that is left after the compilation is this:
<!-- ngInclude: tempTest -->
What is going on here? Why isn't my insert properly compiling? the logic is as follows:
$scope.insert = function(){
// Create elements //
var container = angular.element('<div id="compiled-container"></div>');
var element = angular.element('<div ng-include="tempTest"></div>');
//Insert parent Container
$('#greeting').before(container);
// insert the element
$animate.enter(element, container);
// test insertion
console.log("Before Compile: " +container.html() )
$compile(element);
//look again after compile
console.log("After Compile: " +container.html() )
};
The quick answer might have been:
<div ng-include="'tempTest'"></div>
Probably you just forgot the single quotes to reference the template.
The long answer:
It is not advised to access the DOM inside a controller - you will get in trouble as the code will be flooded with $scope.$apply() calls. Think about implementing this feature with a directive. I tried to create a starting point from your code here
http://plnkr.co/UWUCqWuB9d1dn6Zwy3J3
var app = angular.module('plunker', ['ngAnimate']);
app.directive('greeting', function($compile){
return {
restrict: 'E',
scope: {
name: '='
},
template: '<div>'+
' <span>Hello {{name}}!</span>'+
' <button ng-click="insert()">test</button>'+
'</div>',
link: function(scope, element, attrs) {
scope.insert = function() {
var container = angular.element('<div ng-include="\'tempTest.html\'"></div>');
element.before($compile(container)(scope));
}
}
}
})
app.controller('MainCtrl', function($scope) {
$scope.name = 'World';
});
<greeting name="name"></greeting>
The template elements are inserted before the Hello World! textnode everytime the button is clicked.
Side note You dont even need the scope{ name: '='} as the directive will inherit its surrounding scope, but its the cleaner way to pass (actually bind) controller variables to a directive explicitly.
<div ng-include src="tempTest"></div>
This should work
^^^ note that this will NOT even begin to work unless single quotes are added (as #JHixson has already pointed out), like so:
<div ng-include src="'tempTest'"></div>
Simply your script :
<script type="text/ng-template" id="tempTest">
<div>
<span>Properly Inserted</span>
</div>
</script>
Must be inside the MainCtrl controller selector like this :
<div ng-app="plunker" ng-controller="MainCtrl">
<script type="text/ng-template" id="tempTest">
<div>
<span>Properly Inserted</span>
</div>
</script>
</div>

What is the *Angular* way to get an elements siblings?

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

ng-click attribute on angularjs directive

I think it should be easy to use the well known angular attributes on a directive out of the box.
For example if the name of my directive is myDirective I would like to use it this way:
<div ng-controller="myController">
<my-directive ng-click="doSomething()"><my-directive>
</div>
instead of needing to define a custom click attribute (onClick) as in the example below
<div ng-controller="myController">
<my-directive on-click="doSomething()"><my-directive>
</div>
It seems that ng-click can work, but then you need to specify ng-controller on the directive tag too which I don't want. I want to define the controller on a surrounding div
Is it possible to use ng-click on a directive together with a controller defined on a parent html element?
Here is updated code. Maybe is this what you were looking for.
Html:
<div data-ng-app="myApp">
<div data-ng-controller="MyController">
<my-directive data-ng-click="myFirstFunction('Hallo')"></my-directive>
<my-directive data-ng-click="mySecondFunction('Hi')"></my-directive>
</div>
</div>
Angular:
var app = angular.module('myApp', []);
app.directive('myDirective', function(){
return {
restrict: 'EA',
replace: true,
scope: {
eventHandler: '&ngClick'
},
template: '<div id="holder"><button data-ng-click="eventHandler()">Call own function</button></div>'
};
});
app.controller('MyController', ['$scope', function($scope) {
$scope.myFirstFunction = function(msg) {
alert(msg + '!!! first function call!');
};
$scope.mySecondFunction = function(msg) {
alert(msg + '!!! second function call!');
};
}]);
Edit
Check solution that I made in jsFiddler is that what you were looking for?
http://jsfiddle.net/migontech/3QRDt/1/

Resources