I have been working on a angular js site, which get the data from webservice/api. One api returns html and angular js code to dynamically add conroller or whatever new angular component we want to add new. This string will come in api response
<div id="homecontainer" class="flex-center p-page" loader style="overflow:hidden;">
<div class="column-1">
<div class="grid m-0 col-xs-12">
<div ng-repeat="Widget in V3Widgets track by $index" class="grid-item">
<div class="grid-sizer"></div>
{{Widget}}
</div>
</div>
<div ng-controller="WelcomeController">
{{greeting}}
</div>
<script>
var app = angular.module('demo', [])
//RestService is Other Module Which is Already Working fine
.controller('WelcomeController', function ($scope,RestService) {
$scope.greeting = 'Welcome!';
});
angular.bootstrap(document, ['demo']);
</script>
</div>
</div>
Now i have a directive to bind this string to page
<renderdynamicwidgethtml ng-if="Widget.Id==null && Widget.Html!=null" html="Widget.Html"/>
Directive's js
.directive('renderdynamicwidgethtml', ['$compile', function ($compile) {
return function (scope, element, attrs) {
scope.$watch(
function (scope) {
return scope.$eval(attrs.html);
},
function (value) {
element.html(value);
$compile(element.contents())(scope);
}
);
};
}])
scope.$eval
should convert the string to angular components, but it failed with this error.
[ng:btstrpd] http://errors.angularjs.org/1.3.17/ng/btstrpd?p0=document
Since Angular 1.5, there's a new
angular.component
tool. This answer uses the word Component to make a reference to all the possible tools Angular provides (such as directives, filters, etc), includingangular.component
.
First let me start with the way AngularJS sets everything up:
When the javascript files are loaded, you can see all the angular code starts with angular.module
, angular.controller
, angular.directive
, etc. And all those receive a function as a parameter (except angular.module
, which receives a name and a list of dependencies). At this moment, those components are not created, just registered.
Once Angular has registered all the modules and components, it is ready to be bootstrapped, either with the ng-app
directive or manually with angular.bootstrap
. Both methods receive a string as a parameter, which is the name of the root module. Using that root module, Angular looks deeply into it's dependencies (which can be seen as a tree of dependencies), and starts loading the components from it's leaves (modules that do not have dependencies) up to the root module's components.
For each module, Angular builds them in a certain order, starting from constants, then providers, then running config blocks in the order they were registered, then loading values, then factories/services, then directives and finally run blocks in the order they were registered (I'm not completely sure about the order, I suggest you double check)
Finally, after everything is setup, it's 'seals' the application, so nothing else can be registered.
The error means that you are bootstraping your application twice. This can happen when using the ng-app
directive and calling angular.bootstrap
, or just calling angular.bootstrap
more than once.
As the documentation says in the manual initialization section:
You should call
angular.bootstrap()
after you've loaded or defined your modules. You cannot add controllers, services, directives, etc after an application bootstraps.
So, in order to load new controllers dynamically, you should register them before the bootstrap process. You can do this by retrieving the data you need from your API (you'd need any other tool like JQuery since Angular isn't set up yet), executing the code with JavaScript's standard eval
function (do this inside the request's promise), and then bootstraping AngularJS manually with angular.bootstrap
.
For this to work, the code you execute with eval
should be purely javascript, I recommend separating it from the HTML either by changing the API's response (if possible), or doing it programmatically after getting the response.
Also, if you need to do this more than once, make sure that the code execute with eval
doesn't bootstrap Angular before registering all the components you need.
Why are you using scope.$eval
instead of $compile
service which is intended to compile your template string.
link: function (scope, ele, attrs) {
scope.$watch(attrs.html, function(html) {
$compile(ele.contents())(scope);
});
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With