Transcluding without running digest on contents (passing raw HTML) in Directive - javascript

I am trying to pass raw HTML inside a directive for later transclusion (when I open a modal - I will use the HTML to populate it)
The problem is - that if I do it like this, the contents of dialog-body get run and the ng-repeat is implemented, which means when I pass the template along, it gets run again causing an ahem stack overflow.
Is there a way for me to use transclusion or something else to pass the inner HTML without running any digest on it?
<dialog-body>
<div ng-repeat="item_value in item.values">
{{item_value.string}}
</div>
</dialog-body>

By the way, I figured out how to get this done.
Angular was running ng-repeat on the initial code, then re-running it once I used it later on. To avoid this - I did this to skip the first ng-repeat run:
<dialog-body ng-non-bindable>
<div ng-repeat="item_value in item.values">
{{item_value.string}}
</div>
</dialog-body>
This meant that I was only passing the actual HTML and not running Angular on it. I then used a querySelector to find all the ng-non-bindable attributes and remove them. Seems to work fine.
Hope this helps someone!

Related

angular, directives not running on content being brought in through json

Sort of a weird problem that I'm not exactly sure what is going on so I will try to be as clear as I can.
I am bringing html content through a json object and placing it in a div. The problem I am having is when I bring html in that runs javascript in through a directive, it does not seem to be running. For example - I'm playing around with this http://cmaurer.github.io/angularjs-nvd3-directives/ , a d3 directive for angular.
If I have the html on the template it works fine - I'm using an example from their page that looks like so -
<nvd3-stacked-area-chart data="exampleData" id="exampleId" showXAxis="true" showYAxis="true" showControls="true" width="700" height="200"> <svg></svg> </nvd3-stacked-area-chart>
This works fine when placed on the page, however when I bring it in through the json, it seems the directive (or angular? ) is not running on it.
For reference the part of the json comes in like this -
'content' : '<nvd3-stacked-area-chart data="exampleData" id="exampleId" showXAxis="true" showYAxis="true" showControls="true" width="700" height="200"> <svg></svg> </nvd3-stacked-area-chart>',
then is bound like this
ng-bind-html="widget.content"
This seems to work fine, if I inspect the element I can see the correct html sitting there. I have a $sce.trustAsHtml inside my controller to make sure it's properly escaped.
So I'm not sure how to approach this issue, because there are no specific errors thrown, so I'm not sure if it's angular, or the directive, or the order of events? Is there a way to re-initialize the d3 directive for example on this once the html content is loaded into the div?
I'm not sure where to begin with this, so I would much appreciate any insight. Thank you for reading!
By the time you load the content received by wire, angular has already finished compiling and linking the page. therefor, you need to tell it to recompile. Have a look at this SO and try to call $compile by hand after receiving the content and placing it in the div: How do I make angular.js reevaluate / recompile inner html?
Keep in mind though that this is rather tricky business and you should really check the security of what you're doing.

Accessing the dom outside ng-app

Say I have an angularJS application, where I want to modify the dom. It makes sense that one should not do it via a service or a controller. Instead use a directive for DOM manipulations. But what should one do if the dom lies out of the scope of the angular app?
For Example:
Say I want to access the BODY tag and disable the scroll bars on it. I can't write a directive because ng-app directive is on a div which is deep inside the dom and thus the BODY tag is not accessible.
How does one tackle this problem? I read this blog, and it seems like it ok to do dom manipulations via a service. So what is really the best practice to access doms? Especially if its out of the scope of an angularjs app?
I'm not sure I understand without seeing your code. But in general, the ng-app should be at the highest tag that encompasses all the functionality you want to manipulate with angular. For most, that is the body tag itself.

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.

AngularJS : Why ng-bind is better than {{}} in angular?

I was in one of the angular presentation and one of the person in the meeting mentioned ng-bind is better than {{}} binding.
One of the reason, ng-bind put the variable in the watch list and only when there is a model change the data get pushed to view, on the other hand, {{}} will interpolate the expression every time (I guess it is the angular cycle) and push the value, even if the value changed or not.
Also it is said that, if you have not much data in on the screen you can use {{}} and the performance issue will not be visible. Can someone shed some light on this issue for me?
Visibility:
While your angularjs is bootstrapping, the user might see your placed brackets in the html. This can be handled with ng-cloak. But for me this is a workaround, that I don't need to use, if I use ng-bind.
Performance:
The {{}} is much slower.
This ng-bind is a directive and will place a watcher on the passed variable.
So the ng-bind will only apply, when the passed value does actually change.
The brackets on the other hand will be dirty checked and refreshed in every $digest, even if it's not necessary.
I am currently building a big single page app (~500 bindings per view). Changing from {{}} to strict ng-bind did save us about 20% in every scope.$digest.
Suggestion:
If you use a translation module such as angular-translate, always prefer directives before brackets annotation.
{{'WELCOME'|translate}} => <span ng-translate="WELCOME"></span>
If you need a filter function, better go for a directive, that actually just uses your custom filter. Documentation for $filter service
UPDATE 28.11.2014 (but maybe off the topic):
In Angular 1.3x the bindonce functionality was introduced. Therefore you can bind the value of an expression/attribute once (will be bound when != 'undefined').
This is useful when you don't expect your binding to change.
Usage:
Place :: before your binding:
<ul>
<li ng-repeat="item in ::items">{{item}}</li>
</ul>
<a-directive name="::item">
<span data-ng-bind="::value"></span>
Example:
ng-repeat to output some data in the table, with multiple bindings per row.
Translation-bindings, filter outputs, which get executed in every scope digest.
If you are not using ng-bind, instead something like this:
<div>
Hello, {{user.name}}
</div>
you might see the actual Hello, {{user.name}} for a second before user.name is resolved (before the data is loaded)
You could do something like this
<div>
Hello, <span ng-bind="user.name"></span>
</div>
if that's an issue for you.
Another solution is to use ng-cloak.
ng-bind is better than {{...}}
For example, you could do:
<div>
Hello, {{variable}}
</div>
This means that the whole text Hello, {{variable}} enclosed by <div> will be copied and stored in memory.
If instead you do something like this:
<div>
Hello, <span ng-bind="variable"></span>
</div>
Only the value of the value will be stored in memory, and angular will register a watcher (watch expression) which consists of the variable only.
Basically the double-curly syntax is more naturally readable and requires less typing.
Both cases produce the same output but.. if you choose to go with {{}} there is a chance that the user will see for some milliseconds the {{}} before your template is rendered by angular. So if you notice any {{}} then is better to use ng-bind.
Also very important is that only in your index.html of your angular app you can have un-rendered {{}}. If you are using directives so then templates, there is no chance to see that because angular first render the template and after append it to the DOM.
{{...}} is meant two-way data binding. But, ng-bind is actually meant for one-way data binding.
Using ng-bind will reduce the number of watchers in your page. Hence ng-bind will be faster than {{...}}. So, if you only want to display a value and its updates, and do not want to reflect its change from UI back to the controller, then go for ng-bind. This will increase the page performance and reduce the page load time.
<div>
Hello, <span ng-bind="variable"></span>
</div>
This is because with {{}} the angular compiler considers both the text node and it's parent as there is a possibility of merging of 2 {{}} nodes. Hence there are additional linkers that add to the load time. Of course for a few such occurrences the difference is immaterial, however when you are using this inside a repeater of large number of items, it will cause an impact in slower runtime environment.
The reason why Ng-Bind is better because,
When Your page is not Loaded or when your internet is slow or when your website loaded half, then you can see these type of issues (Check the Screen Shot with Read mark) will be triggered on Screen which is Completly weird. To avoid such we should use Ng-bind
ng-bind has its problems too.When you try to use angular filters, limit or something else, you maybe can have problem if you use ng-bind. But in other case, ng-bind is better in UX side.when user opens a page, he/she will see (10ms-100ms) that print symbols ( {{ ... }} ), that's why ng-bind is better.
There is some flickering problem in {{ }} like when you refresh the page then for a short spam of time expression is seen.So we should use ng-bind instead of expression for data depiction.
ng-bind is also safer because it represents html as a string.
So for example, '<script on*=maliciousCode()></script>' will be displayed as a string and not be executed.
According to Angular Doc:
Since ngBind is an element attribute, it makes the bindings invisible to the user while the page is loading... it's the main difference...
Basically until every dom elements not loaded, we can not see them and because ngBind is attribute on the element, it waits until the doms come into play... more info below
ngBind
- directive in module ng
The ngBind attribute tells AngularJS to replace the text content of the specified HTML element with the value of a given expression, and to update the text content when the value of that expression changes.
Typically, you don't use ngBind directly, but instead you use the double curly markup like {{ expression }} which is similar but less verbose.
It is preferable to use ngBind instead of {{ expression }} if a template is momentarily displayed by the browser in its raw state before AngularJS compiles it. Since ngBind is an element attribute, it makes the bindings invisible to the user while the page is loading.
An alternative solution to this problem would be using the ngCloak directive. visit here
for more info about the ngbind visit this page: https://docs.angularjs.org/api/ng/directive/ngBind
You could do something like this as attribute, ng-bind:
<div ng-bind="my.name"></div>
or do interpolation as below:
<div>{{my.name}}</div>
or this way with ng-cloak attributes in AngularJs:
<div id="my-name" ng-cloak>{{my.name}}</div>
ng-cloak avoid flashing on the dom and wait until all be ready! this is equal to ng-bind attribute...
You can refer to this site it will give you a explanation which one is better as i know {{}} this is slower than ng-bind.
http://corpus.hubwiz.com/2/angularjs/16125872.html
refer this site.

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