We're using AngularJS to render a schedule table with ng-repeat.
I also need to call an initialization function for a jQuery plugin that acts on the DOM objects being rendered by the Angular code.
However, I do not know how to make it call this initialization until AFTER the DOM objects have been created because the plugin requires the DOM elements to be built before initialization.
How can I do that?
Can use $timeout which won't run until element exists
app.directive('makeMeGreen',function($timeout){
return{
restrict:'A',
link:function(scope,elem,attrs){
$timeout(function(){
elem.makeMeGreen();
},0)
}
}
});
DEMO
Alternate approach is to $observe attributes
Related
$scope.addNew = function(){
$('.thumb-img-gallary').append("<li><span class='img-del' ng-click='delThumbImgGallaryPhoto($event)'>X</span><img class='thumb-img' src='data:image/jpeg;base64,"+imageData+"'/></li>");
}
I am calling this function to add element dynamically. But then delThumbImgGallaryPhoto() is not getting called.
you cannot just append an element with a ng-click or any other directive, and expect it to work. it has got to be compiled by angular.
explenation about compilation from angular docs:
For AngularJS, "compilation" means attaching directives to the HTML to make it interactive
compelation happens in one of two cases:
When Angular bootstraps your application, the HTML compiler traverses the DOM matching directives against the DOM elements
when you call the $compile service inside an angular context
so what you need to do, is first to compile it(remeber to inject the $compile service in your controller), and then append it:
$scope.addNew = function(){
var elem = $compile("<li><span class='img-del' ng-click='delThumbImgGallaryPhoto($event)'>X</span><img class='thumb-img' src='data:image/jpeg;base64,"+imageData+"'/></li>")($scope);
$('.thumb-img-gallary').append(elem);
}
BTW, remember it is prefable not to have any DOM manipulations done in the controller. angular has directives for that.
You have to compile it with scope
try like this
var item="<li><span class='img-del' ng-click='delThumbImgGallaryPhoto($event)'>X</span><img class='thumb-img' src='data:image/jpeg;base64,"+imageData+"'/></li>"
$('.thumb-img-gallary').append(item);
$compile(item)($scope);
angular doesn't know anything about your newly added element. You need to compile your newly added element using $compile. and you should better use directive for this task.
It is a bad habit to access ui elements from controller.
edit: it would be best using ng-repeat for this task. lets say you have a thumb-gallery directive which is repeated using ng-repeat by thumbs array.
when you need to add a new image you only need to add it to your thumbs array.
it is simple and straightforward
Your html would look like
<thumb-gallery ng-repeat="gallery in galleries"></thumb-gallery>
and your js would look like
var gallery = {};
$scope.galleries.add(gallery);
Consider an application that utilizes ngRepeat to show a list of directive instances.
When an element is removed from the list, should I manually destroy the directive instance or is it safe enough to call splice() on the array that holds the element?
The developer guide is not very helpful here.
If you are in doubt and want to check whether the directive is actually getting destroyed, you could put a watch on $destroy in your directive. For example:
// inside your link function
scope.$on('$destroy', function() {
console.log("destroyed");
});
I'm learning AngularJs and I'm playing with a third party Javascript component.
At a certain point the control is initialized as follows:
$(document).ready(function () {
$('#SomeId').initialize();
});
Is there a way to convert this to something more Angularish? I don't want to manipulate the DOM from the controller, but I'm not sure how to initialize this.
This code is not necessarily wrong as is. What you want to be careful about is javascript outside of the angular context (jQuery callbacks/plugins etc) manipulating $scope values because those functions will not trigger an angular digest loop, and will result in a disconnect between the DOM and the $scope.
Here is some more information about this cycle and what you need to know about it: http://jimhoskins.com/2012/12/17/angularjs-and-apply.html
Here is a common use case with jQuery (and also why you should try to use angular services (ie: $http) instead:
// When you manipulate the $scope with a non-angular callback,
// you have to run $scope.$apply() to tell angular about the
// change in order to repaint the DOM
$.get( "/getUser", function( data ) {
$scope.user = data; // set $scope data in callback
$scope.$apply(); // run digest so anything in the DOM binded to the {{user}} model gets updated
});
Generally you don't need to manipulate the DOM like this with Angular...so you really don't need jQuery. Using an Angular "directive" is the declarative, encapsulated way to do it in Angular. There are a ton of 3rd party components out there for you to use that have been built properly with directives: I would recommend using these rather than trying to convert a jQuery plugin (which is really just adding the jQuery bloat for things that you already have access to with Angular). A good place to start looking for Angular directives that you can use is http://ngmodules.org/
I'm creating a fall back image directive that looks like this http://plnkr.co/edit/wxy4Sp2K02iXoQNsvkah
angular.module('directives').directive('myDirective', function() {
return {
restrict: 'C',
link: function(scope, element, attrs) {
console.log('linking');
}
}
});
My directive doesn't work for elements that are added to the DOM by the typeahead.js plugin (https://github.com/twitter/typeahead.js).
<div class='tt-suggestion'>
<div><span class="my-directive">bla</span></div>
</div>
I guess it's because Angular is not informed about the elements that are added by jQuery and hence it doesn't invoke the directive. How do I notify Angular of these changes?
You can use the Angular compile service to do this: http://docs.angularjs.org/api/ng/service/$compile
Basicly it works like this:
document.getElementById("test").innerHTML = $compile("")($scope);
ideally you shouldnt be mixing jquery and angular because they both are based on different philosophy.
jquery-- is event driven i.e. have event listeners which cause changes to model and then the programmer has to code numerous lines to change the view i.e. changing css,text etc
angular-- woo hoo! just change the model which is binded to $scope and :) your view is automatically updated
to automatically react on changing of such events angular has a compiler which studies entire html code before the app is loaded so even if there is a template which you might use later you must enclose it in so that angular compiles this so that all the special angular directive and controller perform as expected even when you remove or add templates to the dom.
here you are using typehead.js and jquery to manually manipulate the view which is against angular philosophy because when you do such maipulation angular compiler wouldnt be aware of it as it runs only when the app is initialized. Thats why before appending you should use $compile to make the angular compiler aware of this template .
in your case i would suggest the typehead present on this url
http://angular-ui.github.io/bootstrap/
I am trying to learn AngularJS. I was reading the https://github.com/angular/angular.js/wiki/Understanding-Directives : "You do NOT have to wrap AngularJS elements in jQuery()"
What is meant by an AngularJS element?
In Jquery, if I have a DOM element, say by using document.getElementByID() and if I want to make it a jquery element with access to all of its awesome functions, I will simply say
var domElement = document.getElementByID("elemID");
var $domElement = $(domElement); (To cache the element)
So, if in angular I dont have to wrap the DOM element as in Jquery, then can I simply query the DOM and access it and still be able to access all the angular methods.
If so, how it is done? Is it because of the ng-app binding?
Are all DOM elements inside ng-app internally accessed by Angular and turned to equivalent AngularJS elements?
The wiki page is talking about the elements passed by Angular as arguments to the compile and link functions of the directive:
link: function LinkingFunction($scope, $element, $attributes) { ... }
^-- here
If you get an element from the DOM using document.getElementById(), it won't be wrapped in jQuery automatically.