Why can I not access my scope attributes when using $new? - javascript

I'm trying to build a context menu directive with some specific characteristics (that are not directly relevant to this question). I've attempted to implement this as an "attachment" directive that attaches the scope of the element it's set on, to a pre-made "menu" element. Since I was unable to find any canonical documentation on this topic, I've based my implementation on some digging around with the Chrome Developer Tools.
I have made a simplified testcase that shows my implementation (and the problem) here: http://plnkr.co/edit/URafJe0OcRsMsmaEdmDi?p=preview
It effectively uses $new on the element's scope to create a new inheriting child scope, and then attempts to attach that scope to the 'menu' element (referenced by ID), by setting its $scope data property, and setting the ng-scope class.
The problem I am encountering, is that the menu element still does not seem to be able to access the attached scope. Any expression relating to that scope, comes up empty (again, see the Plunker above). The $scope data property is correctly set to the newly created inheriting child scope, and that scope is correctly inheriting so that the parent scope values should be accessible. I have also verified that it is interpreting any bindings at all by adding a simple "1 + 1" expression - this works fine.
Why can I not access the scope that is supposedly attached to the element, and/or what is the correct way to manually attach a scope to an element in a directive?

Here is a fork of your plunkr: http://plnkr.co/edit/V0dbM4NFcxdT8YEXWs4l?p=preview
I dont know how to do what you want without using $compile. I did something like this in the plunkr:
menu_element = $compile(menu_element)(child_scope);

Related

Angular JS - Removing DOM elements that have another directive / scope attached

I have a directive that will remove DOM elements from a page under certain conditions. It'll first remove the child elements, and then remove the parent. It works fine, but if there is another directive on the element, I can see some errors show up. I'm thinking it has to do with the scope of the other directive still existing after the element is removed.
What is the proper way to handle something like this? Do I need to destroy the scope of the other directive? The directive that removes the element has an inherited scope, and the other directive on the same element usually has an isolated scope.

AngularJS how to capture events from inside the directives template?

I have a directive and inside it's template is a <img> element and I want to execute a custom method that is within my directives scope:
<my-directive>
<!-- my directives template -->
<p>...</p>
<img onload="myScopeMethod()">
<p>...</p>
<!-- my directives template -->
</my-directive>
I found this Get width height of remote image from url but this works only if im applying it to a directive that works on the <img> element.
The directives purpose is to show a widget that allows me to manipulate the image (scale it by dragging a slider) but I somehow need to get it's original size.
How can I get it to execute the method from my controllers scope?
You would generally want to take your load handler function out of the template itself and stick it in the link function. From there it kind of depends on your directive and whether you are using an isolate scope, inherited scope, or the same scope as the parent.
If you have a scope key in your directive definition object and it's set to an object literal, then you are using the isolate scope. In that case, you'll need to pass it in somehow, and the most straightforward way is to use the '&' option.
If you don't have a scope key or have a scope key and it's set to a boolean value you're using the same scope or an inherited scope. In this case, all you need to do is call $scope.originalScopeMethod() and it will either call it on the scope or find it in the prototype chain.
Here's an example with the three different scenarios. The table at the bottom is being fed from the 'main' controller scope while the small numbers are fed from the directive scope.
If it were me I'd probably go with either isolate or inherited scope so you can keep track of multiple images separately a little easier. The shared scope version in my example would only work for a single image, but you could make it work with an array or hash if you really wanted.
Let me know if I misunderstood your question in any way.

AngularJS: strange two-way-binding (isolated scope) behaviour when using callbacks within a directive

I am currently writing a directive with an isolated scope. Within this scope I am changing the values of the binded variables. After changing the values I am calling a callback function that uses these variables for further processing steps.
Based on the official documentation samples I have created an simplified plunkr of my problem http://plnkr.co/edit/48WscOc1o9XcQlBxSeEH?p=info
As you can see the name of the customer is passed to the directive where its value is changed when clicking on the name. After changing the name I'm calling the provided function where the corresponding variable from the scope is printed to the console. As you can see in the console, with the first click the variable customer.name has still the old value "Naomi", while the template value has changed.
Is this an intended behaviour?

Should "parent" not be used as javascript variable name (reserved words)

I've often used the word "parent" as a JavaScript variable name, and have never had any problems.
I've recently learned that "parent" can refer to something else such as when used to access an element in an IFrame's parent such as parent.document.getElementById("someID").
Should I stop using the word "parent" as a JavaScript variable name, and go through all my existing script to change it? Note that http://msdn.microsoft.com/en-us/library/ie/0779sbks%28v=vs.94%29.aspx and https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Reserved_Words do not indicate that I shouldn't.
'parent' is not a reserved word but a global object in the browser's execution environment. Whether or not you want to have a variable name that conflicts with that is your decision.
For reference, here is a list of actual reserved words in JS:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Reserved_Words
If it makes sense for your variable to be called parent then go ahead and name it that, you just need to be aware that it will shadow the parent property of the window object (the global scope), but that's not an issue since you can explicitly reference that using window.parent rather than just parent wherever you need to work with it.
The only time it should become an issue is if there is code that shares scope with your parent variable which is attempting to access window.parent without explicitly specifying that they want the property, and that's probably an indication that the code needs to be tweaked.
"JavaScript" isn't the same as "ecosystem within which JavaScript is executed".
Browsers have the window and document references, which have properties... like parent. You can still reference the global parent. If your parent is called on a different object there's no collision anyway.

Angular 1.2.0-rc.3 Directive Priority Change Issue

So I have this code example that uses Angular 1.2 RC2 and everything works fine, you click on the handle to toggle the display of the content and the controller and directive have seperate scopes as intended:
http://plnkr.co/edit/e3XAZuhSMAxmkWzKKM39?p=preview
Now I upgraded to Angular RC3 yesterday and now the functionality does not work as it stands in the plunker, I get the error the specific requires generic which is can't find. Going through the change log, I though this might have to do with this breaking change:
$compile: due to 31f190d4, the order of postLink fn is now mirror opposite of the order in which corresponding preLinking and compile functions execute
To fix this they either suggest converting the post linking to a pre linking (which I can do since my post linking needs access to the scope which is not available in the pre linking) or to decrease the priority of the directive. So this plunker does that and functionality does work:
http://plnkr.co/edit/arP3aruH8HEdiwFg6mWp?p=preview
However there is a major issue and that is now because specific has a higher priority, the isolate scope that generic needs is no longer being created so now contentVisible is on the controller scope which is not good.
Now I could just move the scope: {} from the generic directive to the specific directive however it should be possible to use the generic directive by itself and if I did it would attached to whatever scope it is part of and not its own (which would make it impossible to have multiple instance of this directive, which is way it needs its own scope).
The only thing I can think of is to add a directive, called something like isoScope, make sure it has a very high priority, and have it define scope: {}. Then if I need to use generic by itself, I just have to make sure to also add the isoScope directive to make sure it has an isolate scope. Like this:
http://plnkr.co/edit/1NYHpUcPFWEbAzvkCeRH?p=preview
Now I am hoping there is a better way to accomplish what I am looking for without the isolateScope directive. Am I missing a way of that this without that?
UPDATED EXAMPLE
So here is another plunker that includes hopefully better examples of what I am trying to convey (still has virtually no styles but should not be needed to get the point across):
http://plnkr.co/edit/KtRMa1c9giDrhi1Rqyho?p=preview
I have 3 directives:
expander
notification
isolateScope
The expander directive only adds functionality to be able expander and collapse content, nothing more. This functionality is something that should be able to be used alone or with another directive (which is why it has a controller).
The notification directive is used to display notification however since we don't want to display the notifications all the time, we use it with the expander directive so that the user can toggle the display of the actually notifications (similar to how stackoverflow.com does it in the top left).
While I imagine the expander would most likely be used with another directive it should be possible to use alone and that is where the isolateScope directive comes into play. Since the expander directive adds data to the scope and you may want to have multiple expanders on the same page, it needs to have an isolate scope in order to work. Now on a users profile page you have have data like developer key and address that you don't really need to display all the time so lets have the user control that. I have the isolate scope to be able to control both of those independently because without the isolate scope, both of them would be on the same scope and be controlled by the same instance on contentVisible.
I just don't see anyway with how directives now run in 1.2.0 RC3 to be able to accomplish this without that isolateScope directive (though I would be happy to be proven wrong).
I have updated your code so that it does what I think you want (at a minimum this works the way your old code does, but under rc3 as you wanted): http://plnkr.co/edit/nsq4BGAih3lfNmS2mLP7?p=preview
But I made quite a few changes and a significant architectural change so let me know if this moves away from the spirit of what you're trying to achieve.
I think the gist of the issue was that your two directives (generic and specific) were tightly coupled around contentVisible which created a complex dependency that resulted in you having to very carefully manage invocation timing. My approach was to decouple the two directives- encapsulating contentVisible within generic. This allows generic and specific to instantiate fully independently. So you're not dependent on any invocation timing. And thus the directive priority change no longer has any impact on this code. So, one big win with the solution I propose is it should be robust against further changes by the Angular team.
Specifically, I moved the template in to the same directive (generic) as the controller which manages contentVisible . This way the controller that changes contentVisible lives on the same scope as the template which uses it.
Now specific just calls over to the required: generic controller to toggle visibility (effectively as a setter function).
I also moved the ng-class assignment into the template in order to encapsulate that change within one place (the template) and so you don't need jquery or a link:/compile: on generic.
This is a regression. A fix is in the works: https://github.com/angular/angular.js/issues/4431
I have problem, looks very close to your. So if anything will change want to be notified.
My task: I have contact, that could be shown in defferent ways (very common task), but difference between views is in templates, whereas help functions and preparations are same, so I need generic directive for all views.
What I found:
1. in rc2 it works fine in rc3 unstable
2. in rc3 it could work same only when template is inline, but not when it is templateUrl (even if cached)
So I created two planks rc2 version and rc3 version.
Hope this will help.

Categories