Reputation: 6635
As the title states, I am trying to compile, and link an angular controller, to dynamic HTML.
My goal is to create a service, that takes a set of options, one of which would be a controller, that I could link to the dynamic HTML before appending it to the DOM, which would then give the user of this service acces to that bound controller's $scope
as well, with the ability to optionally override the scope, should they so wish.
I've attempted this with the $controller
and $compile
services, but for some reason the template is being appended, but is not being processed, it does not seem like scope is being set, as once appended, it displays the template tags, as opposed to the actual values.
Should I be using either $controller
or $compile
, but not in conjunction?
I'm not entirely sure where I am going wrong, some guidance would be much appreciated.
panel_template.html
<div class="pathwindow">
<div class="pathwindow_title">
<h1>{{ title }}</h1>
</div>
<div class="pathwindow_content">
{{ content }}
</div>
</div>
app.controller.js
(function () {
'use strict';
var appController = angular.module('app.controller', []);
appController.controller('appController', ['$state', '$scope', '$rootScope', 'PanelService', function ($state, $scope, $rootScope, PanelService) {
$scope.title = 'A Awesome Title';
$scope.content = 'This is some content...';
$scope.clickMe = function () {
PanelService.show('panel_template.html', 'appController');
};
}]);
})();
app.factory.js
(function () {
'use strict';
var appFactory = angular.module('app.factory', []);
appFactory.factory('PanelService', ['$injector', '$controller', '$compile', '$rootScope', '$http', function ($injector, $controller, $compile, $rootScope, $http) {
var self = {};
self.show = function (template_url, controller, scope) {
var $scope = angular.isObject(scope) ? scope.$new() : $rootScope.$new();
$http.get(template_url).then(function(response){
var html = response.data;
angular.element('#panels').append(html);
$controller(controller, { $scope: $scope, $element: html });
$compile(angular.element(html))($scope);
});
};
return self;
}]);
})();
Upvotes: 0
Views: 2609
Reputation: 40296
You are passing a detached element to $compile
, not the element that was created by appending the response.data
to the DOM. This element is thrown away right after the statement. The response.data
string without compilation is attached to the DOM, that is why you are seeing the "uncompiled" template.
You will have more luck with the following:
$http.get(template_url).then(function(response) {
var elem = $compile(response.data)($scope);
angular.element('#panels').append(elem);
$controller(controller, { $scope: $scope, $element: elem });
});
This is frightening code though: Does the compiled element get destroyed correctly when it should? Does the controller get destroyed correctly? Does the controller even apply, or are references to it lost after the $controller(...)
statement and thus it ceases to exist?
You must check these out and may have to adjust the code, e.g. listen to the $destroy
event and cleanup and/or keep a reference to the controller.
It also frightens me that a service does DOM manipulation like that. I am pretty sure there is another way (could be the nested views of ui-router - but I am not entirely sure of your exact use case).
Upvotes: 1