I'm looking to programmatically add ng-* HTML attributes to various DOM elements. I've had some success with using $compile(obj)($scope);
but this secondary compile causes issues with a number of components.
I add the ng-* attributes via jQuery... and yes, I know, directives, but this won't work for me as the ng-* HTML attributes I'm adding are boilerplate actions based on DOM structures. That and directives seem clunky (to say the least) as compared to jQuery DOM manip.
So... is there any way I can add in these boilerplate ng-* HTML attributes BEFORE Angular runs so that I can avoid the re-$compile
? What I'd really love is a way to do a pre-init hook on Angular, is there such a beast?
SOLUTION:
@ChrisMartin sent me on the right path to figure out an answer to this question (thanks Chris!). What I ended up doing is this...
First I created a file named "angular-defer-bootstrap.js" that is included before "angular.js" with the following code:
//# Set the window.name to signal Angular to delay bootstrapping until `angular.resumeBootstrap()` is called.
//# See: http://stackoverflow.com/a/21049890/235704 and https://docs.angularjs.org/guide/bootstrap
//# NOTE: This MUST be included BEFORE angular*.js
window.name = 'NG_DEFER_BOOTSTRAP! ' + window.name;
I then created the following function with jQuery to preform any pre-Angular bootstrap code:
//####################
//# Setup the jQuery onDocumentLoad event to handle the pseudo-ng-directive of ng-preinit
//####################
$(document).ready(function () {
var $this, $pre = $('[ng-preinit]');
//# If we have some [ng-preinit]'s to process
if ($pre.length > 0) {
//# Traverse the [ng-preinit] attributes, eval'ing/running each and removing them so Angular doesn't freak out
$pre.each(function() {
$this = $(this);
eval($this.attr('ng-preinit'));
$this.removeAttr('ng-preinit');
});
}
//# Let Angular know it can .resumeBootstrap and remove the flag from window.name
angular.resumeBootstrap();
window.name = window.name.replace('NG_DEFER_BOOTSTRAP! ', '');
});
This is then utilized by including a ng-preinit
pseudo-Angular directive/HTML attribute:
<div class="row" ng-controller="IndexController" ng-init="init()" ng-preinit="globalScope.preinit()">
The rub here is that the eval
'd code contained within the pseudo-Angular directive ng-preinit
has the global scope, rather than the Angular controller's $scope
.
With these few lines of code, I can now cleanly hook the "pre-init" (that is, pre-bootstrap) of Angular and do whatever I like without the need to re-$compile
(and it's unintended consequences), which is exactly what I wanted!