Angular javascript: unable to access DOM element - angularjs

Controller code:
$scope.items = [];
$scope.items = [{'name': 'name x', 'id': 'xyz'},
{'name': 'name y', 'id': 'uqh'}];
console.log(document.getElementById('xyz')+'<--- Element is created');
View
<div ng-repeat="item in items">
<div id="{{item.id}}"/>
</div>
So here, as soon as I have created the divs dynamically, i want to draw a chart in each of the div. But I can't get access to it.
The console shows null. I understand whats going wrong here. But can someone suggest me the right way to go about in such a scenario.
The alternative that I know is to bind function calls like this, but then it would get called multiple times. So i cant go ahead in that manner either.
<div ng-repeat="item in items">
<div ng-bind="drawInElement(item.id)" id="{{item.id}}"/>
</div>

well, I would simply suggest to create a directive like this :
<div ng-repeat="item in items">
<div draw-my-chart="{{item.id}}"/>
</div>
Then in your js :
angular.directive('drawMyChart', function() {
return {
link: function(scope, element, attrs) {
// access your element here ...
}
};
})

Related

Get a specific element from an array in Angularjs

I have an array and I want to take specific element from it using directive (for example array[0]), but I don't understand how to achieve it. I realize that this is the basics of angularjs but I can't find anywhere a solution. Please help :)
Here's the array
$scope.array = [
{
text: '1',
},
{
text: '2',
},
{
text: '3',
}]
And I use that construction in a view
<div ng-repeat="element in array">
<content></content>
</div>
And this is what contains that directive
<p>{{array.text}}</p>
In html :
In content directive you will have to add
bindToController: {data: "="}
You could set the same var in your directive instead of data
<div ng-repeat="element in array">
<content></content>
</div>
directive:
<p>{{element.text}}</p>
If the directive is about customer data you should use {{ customer.text }}, if that is the case you can continue using the same scope like this ...
<div ng-repeat="customer in array">
<content></content>
</div>
directive:
<p>{{customer.text}}</p>

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.

Use an Angular directive to generate html from an array

I'm trying to use an Angular directive to create a form where the user can specify the number of children and, for each child, an edit box appears allowing the childs date of birth to be entered.
Here's my HTML:
<div ng-app>
<div ng-controller="KidCtrl">
<form>
How many children:<input ng-model="numChildren" ng-change="onChange()"/><br/>
<ul>
<li ng-repeat="child in children">
<child-dob></child-dob>
</li>
</ul>
</form>
</div>
</div>
Here's the JS:
var app=angular.module('myApp', []);
function KidCtrl($scope) {
$scope.numChildren = 2
$scope.children = [{dob: "1/1/90"}, {dob: "1/1/95"}];
$scope.onChange = function () {
$scope.children.length = $scope.numChildren;
}
}
app.directive('childDob', function() {
return {
restrict: 'E',
template: 'Child {{$index+1}} - date of birth: <input ng-model="child.dob" required/>'
};
});
And here's a jsFiddle
The problem is that it's just not working.
If I enter 1 in the numChildren field then it shows 1 bullet point for the list element but it doesn't show any of the HTML.
If I enter 2 in the numChildren field then it doesn't show any list elements.
Can anyone explain what I'm doing wrong?
Many thanks ...
Your main issue is that the directive childDOB is never rendered. Even though your controller works because 1.2.x version of angular has global controller discover on. It will look for any public constructors in the global scope to match the controller name in the ng-controller directive. It does not happen for directive. So the absence of ng-app="appname" there is no way the directive gets rendered. So add the appname ng-app="myApp" and see it working. It is also a good practice not to pollute global scope and register controller properly with controller() constructor. (Global look up has anyways been deprecated as of 1.3.x and can only be turned off at global level.)
You would also need to add track by in ng-repeat due to the repeater that can occur due to increasing the length of the array based on textbox value. It can result in multiple array values to be undefined resulting in duplicate. SO:-
ng-repeat="child in children track by $index"
Fiddle
Html
<div ng-app="myApp">
<div ng-controller="KidCtrl">
<form>How many children:
<input ng-model="numChildren" ng-change="onChange()" />
<br/>
<ul>
<li ng-repeat="child in children track by $index">{{$index}}
<child-dob></child-dob>
</li>
</ul>
</form>
</div>
</div>
Script
(function () {
var app = angular.module('myApp', []);
app.controller('KidCtrl', KidCtrl);
KidCtrl.$inject = ['$scope'];
function KidCtrl($scope) {
$scope.numChildren = 2
$scope.children = [{
dob: "1/1/1990"
}, {
dob: "1/1/1995"
}];
$scope.onChange = function () {
$scope.children.length = $scope.numChildren;
}
}
app.directive('childDob', function () {
return {
restrict: 'E',
template: 'Child {{$index+1}} - date of birth: <input ng-model="child.dob" required/>'
}
});
})();

AngularJS directive for accessing ng-repeat scope of child

Okay, so let me start off saying that I have a directive that creates a JQueryUI tab setup with a backing field that populate the tab name and the tab contents basically.
<div id="summaryTabPanel">
<ul>
<li ng-repeat="category in SummaryCategories">
{{category.Name}}
</li>
</ul>
<div ng-repeat="category in SummaryCategories" id="tabs-{{$index + 1}}">
{{category.Content}}
</div>
</div>
So as you can see, I have a <ul> with an ng-repeat in the <li>.
As I will be applying JQueryUI Tab function to the parent container id="summaryTabPanel", I need to wait until all the dom is rendered.
So I do some research, and find out I need to create a directive that kind of looks like the following:
Application.Directives.directive("repeatDone", function () {
return {
restrict: "A",
link: function (scope, element, attrs) {
scope.$watch("repeatDone", function () {
if (scope.$last) {
$("#summaryTabPanel").tabs({
event: "mouseover"
});
}
;
});
}
};
});
This watches to see if the last repeated item is found, and then applies the DOM changes via the statement $("#summaryTabPanel").tabs()
This is all fine and good, but it only works if I apply the directive to the last ng-repeated child item of the summaryTabPanel container.
<div id="summaryTabPanel">
<ul>
<li ng-repeat="category in SummaryCategories">
{{category.Name}}
</li>
</ul>
<div ng-repeat="category in SummaryCategories" id="tabs-{{$index + 1}}" repeat-done>
{{category.Content}}
</div>
</div>
If I move it to the previous ng-repeat item things work but not quite right. If I move it to the parent container, things don't work at all.
It seems wrong to me to apply this directive to the last child, and instead have a way to apply it to the root and somehow accomplish the same thing.
<div id="summaryTabPanel" repeat-done>
Is this possible somehow with Angular?
According to this link you should write your directive like this
Application.Directives.directive("repeatDone", function () {
return {
restrict: "A",
link: function (scope, element, attrs) {
$timeout( function () {
$("#summaryTabPanel").tabs({
event: "mouseover"
});
});
}
});
Please have a look at the jsfiddle I created to illustrate your case.

Adding directive dynamically using ng-click

I am working on a modal for a client. I have created a directive that works great, the problem is that one modal is made ahead each time it is used like..
What I have
<div ng-repeat="item in items">
<a data-toggle="modal" data-target="{{item.id}}">Click</a>
<my-dialog element-id="item.id">
<h1>This is the body of the modal</h1>
</my-dialog>
</div>
This works great for a small amount of modals but we are using a very large number of modals. So I would like to add the directive at runtime, something closer to...
What I want...
<div id="warning"></div>
<div ng-repeat="item in items">
<a data-toggle="modal" data-target="{{item.id}}" ng-click="showModal(item)">Click</a>
</div>
...
// inside controller
$scope.showModal = function(item){
$http.get('/someUrl').success(function(data){
var result = $compile('<my-dialog element-id="'+item.id+'">'+data+'</my-dialog>').($scope);
$("#warning").append(result);
});
}
$scope.hideModal = function(){
$( "#warning" ).empty();
}
This of course isn't working yet. Also it doesn't feel like the best way. This would allow me to remove the directive once it has been closed.
Please include a plunker or equivalent for the check.
One way you could do this is to use ng-repeat with your items, then call $scope.$apply() after you push a new item to the list. The HTML could look like this ...
<div ng-repeat="item in items">
<span dialog>
<a class="dialog-anchor">{{item.name}}</a>
<div class="dialog-body">{{item.id}}</div>
</span>
</div>
... and the directive like this
.directive('dialog', [function () {
return {
scope: {
id: '#elementId',
}
, link: function (scope, el, attrs) {
var body = $(el).find('.dialog-body').detach();
$(el).find('.dialog-anchor').on('click', function () {
$('body').append(body);
});
}};
}])
... and the controller like this
.controller('app', ['$scope', function ($scope) {
$scope.items = [
{name: 'first', id: 001},
{name: 'second', id: 002}
];
setTimeout(function () {
$scope.items.push({name: 'three', id: 003});
if (!$scope.$$phase) $scope.$apply();
}, 2000);
}])
Here's the plunker... http://plnkr.co/edit/2ETbeCKGcHW3CJCfD9d7?p=preview. You can see the $scope.$apply call in the setTimeout where I push a new item to the array.
Try this:
var result = $compile('<my-dialog element-id="'+item.id+'">'+data+'</my-dialog>')($scope);

Resources