AngularJS : ng-if and ng-repeat not working after custom transclusion - javascript

I am attempting to do custom transclusion of a directive in angularJS as I need to transclude two separate elements into two separate locations.
The issue is that whilst some directives carried over on the transcluded content work such as ng-bind others such as ng-if or ng-repeat do not, even after recompiling the transcluded elements with the correct scope.
Example: http://jsbin.com/menakapoma/1/edit?html,js,output
As you can see in the example the ng-bind works but the ng-if does not even though they are both on the same scope and accessing the same value. Neither the true or false state of the ng-if works.
I believe this is because the ng-if directive gets transcluded as a comment, however even if I set the priority of the transcluding directive to 9999 and perform it in the pre-linkage function it still does not work.
Does anyone know how to get these directives working?

The issue is that no matter what by the time the transclude function executes the nested directives have already been compiled and replaced with comments.
I have managed to achieve this by completely foregoing the transclude options, and manually requesting the template via $templateRequest.
I specify a compile function which replaces the element with a comment placeholder to ensure nothing is rendered during the request.
In the linkage function I manually compile the template and then replace directive's element with it.
See the updated example here: http://jsbin.com/rocedarono/3/edit?html,js,console,output
It certainly doesn't feel like the cleanest/optimal solution and I am open to any other solutions that can do it a little nicer. Especially as any DOM events have to be bound to after the $templateRequest promise is resolved and checked for existence before removal on the $destroy event to ensure it resolved beforehand.

Related

Variable passed by = into isolate scope not binding

I'm working on a directive I hope to make public for use and ridicule, and I've found a pretty major issue I can't figure out if its my controller code or my directive.
I have a variable I pass to the directive via '=' in the isolate scope. If I pass the variable as a child object of an object, it works perfectly in any case, but when I pass it a top level variable, it works in one case, any changes the directive makes are reflected in the parent scope, while in the second, any changes the directive makes are not seen in the parent
In the working case, I don't define the variable before it gets sent to the directive. It's modified in the directive, and shows up properly in the parent scope.
In the non-working case, it is defined before being sent to the directive, but none of the changes in the directive show in the parent scope.
In both case, I tried both predefining and removing any initial definitions of the variable being sent to the directive; in the working case, it continued to work, in the non-working case, no progress was made.
This is the first time I've seen a '=' scoped variable not change based on changes made in the directive, and I'm at a loss.
Unfortunately, I don't have a working case to show you. I put the code into a plnkr to show a co-worker, and you can see all my code to see if there's something stand out wrong, and while I'll try to put together a working case, it involves an API, a bunch of code around it, and I suspect my simplifying it to make a working plnkr will solve the problem and not help figure out the issue I'm having. Unfortunately, I don't even know what code I should show you directly, as SO only lets me link plnkrs if I have code here.
Basically I have a directive
<combobox data="dataList" value="result"></combobox>
Data can be sent in as an array of strings or an array of objects of this format: { 'value': 'car_3', 'display': 'BMW' }. Value returns as an object of the same type (if an array of strings is passed to data, its converted to objects in that format).
In case 1, result comes back with the data the directive sets, in case 2, it never changes (it maintains it's initial value.
http://plnkr.co/edit/hUCuZuBu9BUbdwD0V6AO
In the plnkr, main.js contains my directive, and both case files show how the directive is called in the HTML. I'm sure there's some junk code in there, as I've been debugging this like crazy...
hmm without seeing your code it sounds an awful lot like you're dealing with the common (super frustrating!) problem of js primitives being duplicated inside of child scopes, causing an unexpected non-bi-directional chain of binding. Are you using dot syntax on your model to force prototype?
Check out:
"Not having a dot in your ng-model (or other places you need it!)"
http://nathanleclaire.com/blog/2014/04/19/5-angularjs-antipatterns-and-pitfalls/

Add ng-click to highcharts-ng column chart xAxis labels

I am using highcharts-ng within an angular app, I need to run a function when the xAxis labels are clicked see below the categories and labels I am adding to the chart.
Currently I can add an onclick to the label and alert but am not able to get this to work with angular.
return "<a onclick='alert(1)'>" + this.value + "</a>";
http://pablojim.github.io/highcharts-ng/
Working example of current code here.
http://jsfiddle.net/3gLr4vcu/
Angular directives are not processed until $compile is called, which is usually done when Angular inserts templates, for directives and ng-include for instance. If you modify the DOM yourself, Angular doesn't know quite what do with the HTML unless you call $compile yourself. After the DOM is modified by highcharts-ng, you will need to call $compile like this:
$compile(element)(scope)
Ideally you want element to be an element that hasn't been $compiled already (I am unsure what happens if that is not the case) and scope to be first scope encountered in an upwards traversal of the DOM tree. If the scope hierarchy is not needed, then you can just attach the element to the $rootScope.
You will need to inject $compile (as well as $rootScope if you use it as described). For more information, see the $compile documentation, which also explains the odd syntax off the $compile expression. If you post your full code, I can tell you where to put the $compile statement and how to find the appropriate scope to use.
EDIT: Here is a working JSFiddle: http://jsfiddle.net/tsclaus/bpg4556c/

Angular.js directive template using variable from parent/inherited scope

I want to chose directives templateUrl depending on some variable from its parent scope. I can't use templateUrl function, since it doesn't have a scope yet. I can $compile the template from $templateCache(note that it's already there, I'm not loading it) from inside the linking function, but I am afraid it's gonna have a negative impact on performance(let say this is a table cell directive.. and there's quite a few cells).
Do I have any other, better option?
There is indeed no other way around. Although you should $compile this way to achieve somewhat satisfactory performance results.
https://stackoverflow.com/a/22646392/301596

angularjs directive with ng-if in the template

I'm building a directive that utilizes an ng-if inside of it's template. What's strange is that the element provided to the link function does not have the ng-if code expanded, it is only a comment line for the ng-if. Playing around, I found that by wrapping my link code in a $timeout seems to get it to work, but I am wondering if that is not the correct way of going about it....and more so, why is this happening.
I've added a plunk to demonstrate: http://plnkr.co/edit/Gl7v8yJLevi664nUKcFY?p=preview
Most directives actually do most of their logic in a $watch(). For example ng-if will setup a watch on it's attribute, and then render/remove the dom when that changes. Watches execute during a digest cycle, so even though directives have been compiled and linked, the watch hasn't run yet to determine whether it should show the if or not.
EDIT:
You should probably think about what you are actually doing to make sure if it's what you want. Keep in mind that the ng-if is dynamic. And so at any time it might get removed or added based on whether the items array is empty or not.
This means that even if you manage to defer your dom manipulation until after the if is rendered, you run the risk of the if going away and coming back (at which point your css code will not be run again).
A much better way to do this would be to setup a watch and add your css in a watch, or better still, use ng-class and add the css in your template.
The angular framework needs to have $scope.$apply() called in order to update the bindings and expand the template. $timeout() is an async wrapper which assumes that changes were made outside angular world and it calls $scope.$apply() as a final step. in your case, using $scope.$apply(); directly, immediately before your element call achieves the desired effect.

Difference between the directives and static DOM elements in AngularJS

I have already read the
Compilation process, and directive matching
on AngularJS Doc.
but I really didn't understand the directives.
Example:
I have static html:
<div class="test test2" cid="549" sid="a5e3c4f8a9">text-text-text</div>
when I do it manually, I know it will only created and called one time at browser's parse time.
but what happens when I create a directive with the same dom element ?
<x my-directive>text-text-text</x>
is this the same effect?
I am asking such a newbie question, because I am using over 200 elements on my html page.
If I change them to single directive: for sure it will be much more easier to manage them.
and its no problem if its only slow at browser's compile time but what happend in run time?
and I am sorry, if the qustion is not pro enought. I am just new to Stackoverflow.
Thank You
Daniel
If I understand you correctly, you want to know how AngularJS creates a directive and how many times your directive methods are called.
When you create a directive (with module.directive('myDirective', ...)), you are really just creating a definition. Every time you use that directive (like <div my-directive>), AngularJS will run through the process described in the guide: that is, it will compile and link each use. It has to be this way because the directive doesn't exist in isolation; it exists not only in the $scope in which it was called, but also it can make use of element attributes and transcluded contents. The definition occurs once, but each instance is compiled and linked.
Once the directive is created, it's technically done; if you don't set up any $watch or $observe or event bindings, your "directive" is now just whatever's in the DOM at the end of your link function - there's no more computation. In other words, what happens after compilation and linking is entirely up to you.
So back to your example: if you use 200 of the same directive on the page, the directive will be defined once, but all 200 will be compiled and linked separately. But I'm not really sure what you're implying by asking. What's the question behind your question?

Categories

Resources