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
Related
I read document from AngualrJS : https://docs.angularjs.org/guide/component
And when I am reading to "Example of a component tree" section, I got confused about how a component tree's loading works, because there is nowhere to find the loading order.
How angular find the root directive and nested directive (may be in a template)? and Which component should start work first? I mean, If a nested component() is called earlier than its directive's appearance, will it be called later when its directive appears? How angular knows the appropriate component to call when a directive/template load? Or just iterate all components method? Or load all components first, then according index.html to form a component hierarchy, then call it properly?
Is there anybody kindly explain? thanks a lot!
Thanks estus!, your anwser is really helpful! According to AngularJS : How does the HTML compiler arrange the order for compiling? and Pete Bacon Darwin's example :
Just in my opinion:
Angular call all components comiple() method first to complete whole template loading, then call their controller() methods regard to directives hierarchy.
And this comes from : How directives are compiled
It's important to note that Angular operates on DOM nodes rather than
strings. Usually, you don't notice this restriction because when a
page loads, the web browser parses HTML into the DOM automatically.
HTML compilation happens in three phases:
$compile traverses the DOM and matches directives.
If the compiler finds that an element matches a directive, then the directive is added to the list of directives that match the DOM
element. A single element may match multiple directives.
Once all directives matching a DOM element have been identified, the compiler sorts the directives by their priority. Each
directive's compile functions are executed. Each compile function
has a chance to modify the DOM. Each compile function returns a
link function. These functions are composed into a "combined" link
function, which invokes each directive's returned link function.
$compile links the template with the scope by calling the combined linking function from the previous step. This in turn will
call the linking function of the individual directives, registering
listeners on the elements and setting up $watchs with the
scope as each directive is configured to do.
I'm learning angular material library, and there is md-autocomplete-parent-scope directive as a part of md-autocomplete directive. I didn't find anything in the documentation. Here is the source code. What is it's purpose, what does it do?
It watches variables on its scope, and then copies them to the parent scope ensuring the data is kept in sync.
I've been working with angular for a month or so now. I'm having an issue working with dom manipulation. As an exercise, I want to create a directive that would repeat a nested object to a tree view. Please don't send me links of online example. I found plenty but most don't explain what they are doing or more importantly why the code is written that way.
I have create a plnkr as a sample code to test with located here: http://plnkr.co/edit/Zcx63dJZxQyDsjAHIALh?p=preview
Every example I found online explains that all the compile functions run before the pre or post link and the post link is where events should be registered and bound. I can also either use a link or a compile function in my directive and a compile function returns a post link. You can see in the plnkr that everything is setup this way.
I understand that the link function can take a transclude function that creates a clone of the element. This is where I'm stuck. I tried to append the clone to the element but i'm always getting my browser to freeze and being none responsive.
In the angular documentation it says:
Note: The compile function cannot handle directives that recursively use themselves in their own templates or compile functions. Compiling these directives results in an infinite loop and a stack overflow errors. This can be avoided by manually using $compile in the postLink function to imperatively compile a directive's template instead of relying on automatic template compilation via template or templateUrl declaration or manual compilation inside the compile function
but there's no example on what's the process of manipulating the dom. How do we handle recursion in the link function using compile? In some examples they clear the element html and then append the clone. Why? How can I recursively build and append templates? Is it better to have the element transcluded into a template or is it better to have my template in the directive and then clone it?
I hope you can help me as I can't find anything that would go in details of the compile function and the steps that are needed when it comes to recursive dom manipulation. If you want to help please provide an explanation of each line of the code.
Thank you for the help,
Hi I fixed the plunkr: http://plnkr.co/edit/gbeljxdShUazBJux7hXB
The biggest problem I saw was that your recursion never ended which is why there was a stack overflow.
let me know if you have any questions.
Hope this helps.
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.
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.