I get the error "Controller 'gssResponseGroup', required by directive 'ngClass', can't be found!" when using the linked Plunker files. Problem is, sometimes it works perfectly fine and other times I get this error. My guess is that the order of loading/compiling of the directives is not consistent.
Anyone have any ideas?
Plunker
I don't see why it states that it can't be found. It is defined right above in the same JavaScript file.
I can't recreate your error, but I am guessing the imperative transclude() call in your link function is creating a race condition. You're using pre-1.2 transcludes with 1.3, so take a look at the current docs for your transcluding needs: https://docs.angularjs.org/guide/directive
I'm also pretty sure the error is not referring to a dependency injection lookup failure, but because the require: '^gssResponseGroup', line in your sub-directive can't find the not-yet-instantiated / linked controller of a parent directive, since it's being transcluded in an ad-hoc way.
Related
I am trying to get experience with angular by making an app (for my own use) and I ran into an issue.
I decided to try to implement lazy loading (like in the "Complex" part of the answer to this question ) and had that working with my own additions to it.
I wanted to make components more self-contained though and decided to try to make a directive to load any javascript dependencies for me.
This left me with the following template html
<div dependencies="app/components/home/controller.js" ng-controller="HomeCtrl as home">
This is the home page.<br />
{{home.test}}
</div>
When I try to load this page I see the following error
Argument 'HomeCtrl' is not a function, got undefined
If I remove the ng-controller directive then my directive works fine and controller.js is loaded.
Based on the source for ngController I thought that setting the priority for my directive higher than 500 would work but it didnt seem to help.
I also tried moving my directives contents from link to compile.pre. It didnt help either, my directives compile runs before the error but compile.pre does not.
Is there any way to make my directive load/run first, before ngController?
I have an Angular app with a custom element directive (<uber-table>). <uber-table> is supposed to take a collection of objects, render them into a <table> and add some functionality (click row to toggle the underlying object as selected, search box for live filtering, action links on each row with customized click callback(s) for each object). I created a Plunker with the relevant code. Please note that Plunker is giving an error about map (Object [object Object] has no method 'map'), but locally I am not getting any errors.
The post-link function's element parameter is not the <uber-table> element as I expected. Instead it is the template's <div class="uber-table"> element. This is preventing me from extracting data from <uber-table>. What am I doing wrong? Any help will be much appreciated.
Here's a rundown on some of the issues.
First main issue is you want existing content already within the uber-table markup to exist, as well as a new template. Unless told otherwise the existing content ( columns) in this case will be overwritten. In order to include existing content in a directive that has a template, you need to set transclude:true then identify within template where this existing content needs to be placed using ng-transclude on element that will be parent of the content.
Here's demo with transclude fixed
New problems arise now where you are trying to use jQuery to loop over columns and return angular attrs => column.attrs . This throws undefined error.
I haven't tried to unravel this enough to sort out the columns issues yet. They should likely be handled by directive of their own
UPDATE: here's slightly revised error free version using jQuery to parse column count. I'm afraid am still confused a bit by structure of this. I don't see need to use jQuery to parse colunms, this could be converted to directive or pass column definitions into main directive from controller scope
After trying several things and looking at the documentation again, I finally got it working. The solution was to put the post-link function inside the compile function. Also I had to update my isolated scope to use =, set replace to true and set transclude to 'element'.
I updated Plunker if anybody wants to see the changes. The Plunker version isn't working, but since it is working locally, I'm not going to spend too much time on it.
I'm trying to create a new directive that selects among several children using an ng-switch. This example is not much more than creating an ng-switch inside a directive, but eventually the directive will have more display sugar and some automatic functions so it seemed that creating a directive was the right solution.
My progress so far is in this plunker:
http://plnkr.co/edit/yeCiIOCQswYJHyTozQUZ
The $compile I'm doing seems to be evaluating the switch, and determining that the value doesn't match any of the when clauses which shouldn't be true. You can see that by inspecting the elements in the rendered picker.
I'm also concerned that calling $compile at this stage seems to have thrown away the item list, so it seems like I'm barking up the wrong tree.
How do I get the transcluded content to re-evaluate within the current state?
Update
I think I was barking up the wrong tree. Mathew's answer got me started in the right direction, so it was a big help.
As far as I can tell trying to construct a directive (ng-switch) inside a directive is a bad idea. In the previous plunker when the compile happened the template was changed permanently. That means if I changed the which parameter it wouldn't update. That's what was smelling funny to me in the first place.
Here is a revised plunker:
http://plnkr.co/edit/WUVgdXjwedxO4356321s
In this case, there's a watch on the 'which' value that refires the transclusion. That function removes the previous entry (if any) and adds the new one. There's a couple added benefits.
First I removed the 'item' directive. There's no reason for it to exist, since I'm just looking at the class. Second, I used $animator to do the list manipulation. That means you can add ng-animate to the picker and get animation effects.
I hope that helps someone else looking at this question.
There were two problems with your code:
1) Your template had which being evaluated so your on was becoming the number 1, instead of the variable you wanted which is "which":
template: '<div><div ng-switch on="which"></div></div>',
2) When you used compile, you needed to pass in the $scope like so:
$compile(sel)($scope);
Here's an updated plnkr for you: http://plnkr.co/edit/Q6ViJBvkLwQRgUKYMfS9?p=preview
I'm writing a directive to wrap plupload functionality.
The directive is intended to be used as you can see here: http://pastebin.com/sddR0UL7
Here (http://pastebin.com/c09LWeu4) you can find the template the directive reference.
And here's the directive's code (coffeescript): http://pastebin.com/SCwbkHWf
When visiting the page containing the directive I can see "Error: p is null" which
signifies that plupload could not be initialized (usually because references to
container is not defined).
Executing directive step by step I can see that the attributes it references are all
defined, so I think that the error is due to DOM not being compiled/linked yet.
How can I overcome this problem?
Thanks in advance for your help
I think I've found the culprit.
It seems like plupload.init manipulates the DOM so initializing the component within
controller breaks the "don't manipulate DOM in controller" rule.
So, by movine the initialization of plupload into "link" function, everything works
as advertised.
Still I'm open for other advices or best practices.
Thanks
I have this basic plnkr which just implements a basic "Hello, X" directive.
In the link function I am logging scope.name but I get undefined? Why is it so? Shouldn't it log the value of name property in console?
This is a known "problem" where interpolation of # attributes happens after linking function is invoked. There is a pull request open to change this issue but it is not clear if this one is going to be merged.
In the meantime a way of getting an interpolated value is by observing an attribute like so:
attrs.$observe('hello', function(changedValue){
console.log(scope.name);
});
And the plunk: http://plnkr.co/edit/Lnw6LuadTLhhcOTsPC8w?p=preview
So, at the end of the day this is a bit confusing behavior of AngularJS that might be changed in the future.
Pawel is right (https://stackoverflow.com/a/14552200/287070) but I wanted to add that the problem is that any attribute that contains {{}} interpolation will be set to null in the attrs parameter during the link function as the first $digest since the compilation has not yet run to evaluate these.
The fact that # bindings are null in linking functions is just a symptom of this.
Currently there is no real fix, since we can't start running $digests in the middle of the compilation process. So $observe (or $watch) is the only real way to get hold of these values.
For those in 2015 who are reading this post, please note that the way Angular handles "#" attributes has changed.
Angular 1.2 onwards, interpolation occurs prior to the invocation of the linking function.
An excellent post on this topic is present here.