I looked at various similar questions such as this one, this one, this one, this one, and this one that failed to provide a solution to my problem before hitting on a solution myself. However, it still does not feel like the "correct" Angular way, so I'm asking the community for advice.
Here's the setup. I have a layout template (index.html):
<!DOCTYPE html>
<html ng-app="app">
<head>
...
</head>
<body role="document">
<div id="wrapper" class="container" role="main" ng-controller="mainController">
<div id="header">
...
</div>
<div id="diagram" ng-view="ng-view"></div>
<div id="footer>
...
</div>
<script>
...
</script>
</div>
</body>
</html>
I have a partial view template (diagram.html). Note the custom directive, explained below:
<div my-diagram ng-bind-html="diagram"></div>
Here's my routing configuration, specifying the partial view template and controller:
angular.module("app", ["ngRoute", "ngSanitize", "controllers", "directives"])
.config(["$routeProvider",
function ($routeProvider) {
$routeProvider
.when("/process/:processId", {
templateUrl: "diagram.html",
controller: "processDiagramController"
});
}]);
Here's the controller used for the partial view. It uses the processId value from the $routeParams to make a call via $http.get() to retrieve SVG data that it assigns to $scope.diagram, which is bound to the template:
angular.module("controllers")
.controller("processDiagramController", ["$scope", "$http", "$routeParams", "$sce",
function ($scope, $http, $routeParams, $sce) {
var onError = function (response) {
$scope.errors.push(response.data);
}
var onDiagram = function (response) {
$scope.diagram = $sce.trustAsHtml(response.data);
}
$scope.errors = [];
$http.get("/" + $routeParams.processId + ".svg").then(onDiagram, onError);
}
]);
My problem was figuring out how to run code on the SVG content after it had been added to the DOM. Of course, the correct place to do any DOM manipulation in Angular is in a directive, so I wrote one:
angular.module("directives", [])
.directive("myDiagram", function () {
return {
link: function(scope, element, attrs) {
scope.$watch(function() {
return element.html();
},
function () {
diagram.process(element);
});
}
};
});
The only way I could get the diagram.process() function to run AFTER the SVG content got added to the DOM was to use a $watch on element.html() as shown. This is what feels "wrong" to me, and I'd like to know if there is a more "correct" way.