Sharikov Vladislav
Sharikov Vladislav

Reputation: 7269

How to add some HTML code to the DOM with angularJS templates and make AngularJS to interpolate them?

I have some some service. I wanna to debug it and see state of variables in this service. My code is below (explanation below the code):

module.factory('Data', function () {
    var current = [], unlocked = [], all = [];

    return {
        current: current,
        unlocked: unlocked,
        total: all
    }
});
module.controller('debugPlaneController', ['$scope', 'Data', function ($scope, data) {
    $scope.data = data;
}]);
module.factory('someService', ['Data', function (data) {
    var initDebugMode = function () {
        var style = "style='width: 500px; height: 100px; background-color: #ccc;";
        var template = "
            <div "+style+" ng-controller='debugPlaneController'>
                <p>data.current = {{ data.current }}</p>
                <p>data.total = {{ data.total }}</p>
                <p>data.unlocked= {{ data.unlocked }}</p>
            </div>
        ";
        $(".someClass > .childClassOfSomeClass").append(template);
    };
    // some more methods, for example
    var push = function (name) {
        data.current.push(name);
        data.all.push(name);
    }
    // etc
    return {
        initDebug: initDebugMode,
        push: push
        // some more methods
    }
}]);

module.controller('mainController', ['$scope', 'someService', function($scope, someService) {
    someService.initDebug();
    someService.push('lala');
});

So, I have some app with controller mainController. I want to use service someService in it. I am using push method. This method pushes data from name argument to total and current arrays of Data service Data. As you see, I called method initDebug() from mainController, so I want debug window to appear on my screen. I want to show state of arrays current, total and unlocked of Data data-service.

Actually, window appears on screen, but I see this on it:

data.current = {{ data.current }}
data.total = {{ data.total }}
data.all = {{ data.all }}

So, AngularJS templates wasn't interpolated. How I can make them interpolating + I need live update of them in this block (like angularJS actually do).

Update

Using $compile.

So I need to change my initDebugMode function this way?:

module.factory('someService', ['Data', '$compile', function (data, $compile) {
    var initDebugMode = function () {
        var style = "style='width: 500px; height: 100px; background-color: #ccc;";
        var scopeImitation = { data: data };

        var template = "
            <div "+style+" ng-controller='debugPlaneController'>
                <p>data.current = {{ data.current }}</p>
                <p>data.total = {{ data.total }}</p>
                <p>data.unlocked= {{ data.unlocked }}</p>
            </div>
        ";
        $compile(template)(scopeImitation);
        $(".someClass > .childClassOfSomeClass").append(template);
    };
// etc...
]);

How exactly passing variable to 2nd brackets in $compile service works? I used this correctly?

Upvotes: 1

Views: 1383

Answers (1)

m0meni
m0meni

Reputation: 16435

You need to use the $compile service:

$compile

Compiles an HTML string or DOM into a template and produces a template function, which can then be used to link scope and the template together.

You would use it like:

$compile(template)($scope);

Don't forget to inject the $compile service and $scope into your factory first though.

I would also read through this post to understand the other angular services you could use to achieve your goals:

What is the difference between the $parse, $interpolate and $compile services?

Because $interpolate might be more suited to what you're trying to do, but $compile is the most powerful.


Regarding your edit

At first I didn't really take proper notice of the fact that you were inside a factory. I think it is generally inadvisable (maybe impossible?) to pass the scope into into the factory. If you want a reuseable debug interface, I think the best way would not to be putting it in your factory, but instead, making a directive:

module.directive('debug' , function() {
    return {
        restrict: 'E',
        template:'<div><p>data.current = {{ data.current }}</p><p>data.total = {{ data.total }}</p><p>data.unlocked= {{ data.unlocked }}</p></div>',
        controller: 'debugPlaneController'
    }
});

I removed the style from your template because you can actually style the directive from your css by defining a css rule for debug

debug > div {
    width: 500px;
    height: 100px;
    background-color: #ccc;
}

And I removed ng-controller from your template because your directive will use the controller defined in the directive.

Now you can put your directive wherever you want like this. It'll generate the template inside correctly without you having to worry about $compile:

<debug></debug>

Moreover if you want to only show it conditionally you could use ng-if

<debug ng-if="debugMode == true"></debug> //debugMode would be a variable you defined in your controller

Also regarding your question for $compile and your scopeImitation I've never seen it used that way before and I don't think that would work. $compile from what I've seen is always written as $compile(thing to compile)($scope)

Upvotes: 1

Related Questions