How to unload AngularJS directive when changing templates - angularjs

I have a web app built with AngularJS and it includes various routes/controllers/views/etc.
Several views require directives that I include. I've noticed though that when I change the route and a new template is loaded the directives from the old template continue to be run. Simply creating a directive that logs to console you'll continue to have it logging when the new route is loaded.
Is there a way to avoid this? It seems a bit of a waste of memory.

You need to unbind events bound to within the directive.
For example, if you had a resize event bound to the window you would do the following:
$scope.$on('$destroy',function() {
angular.element($window).unbind('resize')
})

Related

Compile AngularJS pages and remove ng-* directives

Is it possible to compile AngularJS application to remove ng-* directives like (ng-click) and generate plain HTML like Angular 2+? If we inspect Angular 2 application with say chrome dev tools, it does not show event handlers like onClick. However AngularJS shows ng-click, ng-for etc.
Short answer:
No.
Long answer:
I won't prvide one, as your question touches many (complex) topics that are already explained elsewhere and possibliy better than I could do, but I will provide some usefull links in my short explanation.
Medium answer:
What you asking for is not possible, because AngularJS uses a different approach for change detection and event bindings.
One of the cool things about AngularJS/Angular is it's ability to to detect changes and perform updates automtically. To make this possible, Angular(JS) has to notice if things change.
Taking your example with the click event, AngularJS uses event based directives to notice the click event, whereas Angular performs a event binding using one-way bindng from the template view to the component. Angular has this possibility because it uses Zones to get aware of changes. Therefore it doesn't need a directive as AngularJS did.
This explains why you don't see event handlers on the HTML element, because Angular directly sets up the event binding. You can verify that the event is handled by Zone.js if you check the Event Listeners tab in Chrome:
Other usefull links to the topic:
https://angular.io/guide/architecture-components#data-binding
https://blog.thoughtram.io/angular/2016/01/22/understanding-zones.html

Best practices how to hide elements in web app using Angular

For example we have a web app and sometimes we need to hide or show some custom directives or html parts using ng-if/ng-show/ng-hide. What we do, we click on a link "Example Show Link" and our elements appear or disappear.
So, here is the Problem:
When you go to another page/state/controller of course your directive/html part is still visible.
Is there any cool solution to hide this parts?
Except using rootScope or pushing true/false flag in every controller, 'couse there could be a lot of directives and a lot of controller
You can use routes for this, and ui-router is what I think the best one that handles this. When you use routes, only the current states' templates are shown, when you navigate out of the state, its template (together with all the directives in it) are destroyed. It automatically do it for you.

How to control and react to events outside ngapp

I am trying to build an angular app on SharePoint (this question is not related to SharePoint though).
I have a page where which has a div that has angular app directive (Its a form with bunch of text boxes). The page has other components on it, which reside outside the ngapp like Ribbon control and I specifically do not have control on it.
Typically if its a jquery app, I would write document.ready function and add my custom components to the ribbon using SharePoint javascript api and wireup any events required like Save, cancel.
I would like to accomplish similar using angularjs if possible. The problem is since they reside outside ngapp I do not understand how to initialize and wire up events.
In specific I would like to know how to accomplish below.
a) Initialize ribbon buttons, which reside outside ngapp. I do not have control on specifics of html. I can only tell api to add a button on ready. In short I would like to call some code when dom is ready to initialize some UI controls that reside outside of ngapp.
b) When user clicks on that button, I would like my app to react to it.
I would like to know if its possible.
Ex:
<body>
<div>
//some area I do not have direct control over but would like to
//initialize and react to events in angular
</div>
<div ng-app="myApp">
</div>
Ok first things first.
1 initialize your ribons buttons the same way you would do it w/o the angular app, use jquery if you want, jquery and angular play well together, so no harm there
except in the buttons events add this peace of code
if using jquery
var rootScope=angular.element($('[ng-app]')[0]).scope()
this will give you the rootScope of your app and once there if you want to pass values to your app you can either attach the values to the rootScope or use
rootScope.$broadcast()
to broadcast events in any case always remember to use
rootScope.$apply()
otherwise angular will not be aware of the changes immediately.
there are other ways, using the app injector to get hold on a service or a value and make your update there,
you can also set localStorage values and have angular to watch those values. but the firs approach is the most straigt forward

how prevent angular compile specify element

I'm developing a chrome extension using angularjs (with a content script open a popup),but it meet some problem when it's parent page already use angularjs, it's parent try to compile the content inserted, so is there anyway to prevent the parent angularjs instance to compile the element I added, and the angularjs instance in extension can bootstrap the element manually ?
It's hard to answer without an example, or what is your extension flow.
Basically, angular shouldn't compile anything on it's own, it either does it when bootstrapping the app, or when you explicitly tell it to.
What I guess you are doing is have the html change before angular is loaded, and then when it loads it compiles your stuff as well.
Try adding your directives etc. after angular has finished loading on the main page (how to detect that angular finished bootstrapping is a whole other question :)).
And after you add your new element with your ng-app <div ng-app="myAngularExtensionApp"></div>, however I am not sure how it will work if it's nested inside another angular application, I don't think it will allow you to do it. If the ng-app of the main application is on the body you can add your div outside the body (weird, but legit), and it shouldn't conflict. but if it's on the html it might cause problems. (I tested it, you can bootstrap another one inside an existing app, but it can cause some really weird problems, I'd avoid it).
A bullet proof solution, that makes things a little more complicated is one I used and I like it alot:
Create an iframe on the page, which you add the angularJS script inside, and it will be your application, do not set the src of the iframe, but rather use iframe.document.open() .write(
<html><body ng-app="myExtensionApp"> etc (i.e. a complete bone structure of an angular page), now since the src is the same, you won't have same origin problems, and you can access the main page with top.
I recommend having services that will interact with the main page.
I am not sure what you want to do, but if you want a directive on the main page for example, first create it in the iframe, then move it to the main page via jquery, it will belong to YOUR angular application (since scope binding is based on prototype and the chain doesn't get broken by moving the element), it will keep reacting to changes to your scope.
However you have to remember that styles are unaffected etc.

Loading views with angularJS

I saw in many websites like twitter.com when you navigate between views by clicking navigation bar menus, then views loaded only one time and the loading spinner appear only for the first time the view has been loaded. If you back to the view again,it loaded directly and the loading spinner does not appear again.
I wonder, how can i do something like that using AngularJS ?. I need any tutorials to help me doing this or put me on the road.
This is already a core part of angular. Have a read of the $templateCache documentation. Here is a simple excerpt:
The first time a template is used, it is loaded in the template cache for quick retrieval. You can load templates directly into the cache in a script tag, or by consuming the $templateCache service directly.
So when using something like ng-include to grab a remote template via a file, it will only be loaded once, and automatically placed into this cache and reused when necessary.
If instead you are wondering how you go about only reloading part of the page, then you need to look at ng-view (which is part of the basic route module), or ui-router for more complex hierarchical view layouts.

Resources