1

I have an html string that i build dynamically in my Component's controller. This way :

    let strDl = this.domainsLabel.split('>');
            angular.forEach(strDl, (element, index) => {
                if (index < strDl.length - 1)
                    this.domainsLabelHtml += `<a position="${index}" ng-click="TabsDomains.goTo($event.target)">${element}</a>&#62;`;
                else
                    this.domainsLabelHtml += `${element}`;
            });
            if (this.domainsLabelHtml.endsWith('&#62;'))
                this.domainsLabelHtml = this.domainsLabelHtml.slice(0, -5);

The html code :

    <span ng-bind-html="TabsDomains.trustedHtml(TabsDomains.domainsLabelHtml)"></span>

I get the following result :

dynamicallyGeneratedCode

But nothing happens when I click. Since nothing worked, i wrote an html content manually, like this :

    <span><a position="0" ng-click="TabsDomains.goTo($event.target)">TEST</a>blabla</span>

And i get the following result generated staticCode:

Which works perfectly.

Since the two chunks of code look exactly the same to me, I don't understand why the dynamically generated isn't working and the static one does.

Here is the code of the trusted html :

     public trustedHtml = function (plainText) {
        return this.$sce.trustAsHtml(plainText);
    }

My class looks like this :

    /// <reference path='tabs.d.ts'/>

    module rundeckManager.tabs {
        'use strict';

class TabsDomainsComponentController implements ITabsDomainsComponentController {

    static $inject = ['$filter', '$state','$rootScope','jobService','$sce','$compile','$scope'];
    public test = false;
    public domainsLabel: any;
    public jobsLabel: any;
    public domains: any;
    public jobs: any;  
    //Previous domains and jobs of the hierarchy
    //So we always keep the data, no need to reprocess it
    public pDomains: any;
    public ppDomains: any;
    public pppDomains: any;
    public pJobs: any;
    public ppJobs: any;
    public pppJobs: any;
    public pFolder: any;
    public ppFolder: any;
    public pppFolder: any;

    public firstBack: any;
    public jobDetails: jobs.IJobDetails;
    public idJob: string;
    public showJobDetails: boolean;
    public showLoadingBar: boolean;
    public domainsLabelHtml: any;

    constructor(public $filter: any, public $state: any, public $rootScope: any, public jobService: jobs.IJobService, public $sce: any, public $compile: any, public $scope: ng.IScope) {
        this.firstBack = $rootScope.back;
        this.showJobDetails = false;
        this.showLoadingBar = false;
        this.domainsLabelHtml = ``;
    }

    public $onChanges(changes) {
        if (changes.domains) {
            this.domains = changes.domains.currentValue;
        }
        if (changes.jobs) {
            this.jobs = changes.jobs.currentValue;
        }
        if (changes.domainsLabel) {
            this.domainsLabel = changes.domainsLabel.currentValue;
            let strDl = this.domainsLabel.split('>');
            angular.forEach(strDl, (element, index) => {
                if (index < strDl.length - 1)
                    this.domainsLabelHtml += `<a position="${index}" ng-click="TabsDomains.goTo($event.target)">${element}</a>&#62;`;
                else
                    this.domainsLabelHtml += `${element}`;
            });
            if (this.domainsLabelHtml.endsWith('&#62;'))
                this.domainsLabelHtml = this.domainsLabelHtml.slice(0, -5);




            this.$compile(document.querySelector('#id-of-span'))(this.$scope);                
        }
        if (changes.jobsLabel) {
            this.jobsLabel = changes.jobsLabel.currentValue;
        }
    }

    public trustedHtml(plainText: string) {
        return this.$sce.trustAsHtml(plainText);
    }

    public goToDetails(id: string) {
        this.idJob = id;
        //console.log(id);
        this.showLoadingBar = true;
        this.jobService.getJobDetails(id).then((data) => {
            this.jobDetails = data.data.job;               
            this.showJobDetails = true;
            this.showLoadingBar = false;
        });              

        this.$rootScope.back = () => {
            this.showJobDetails = false;
            this.showLoadingBar = false;
            this.$rootScope.back = this.firstBack;
        };
    }

    public goTo(element:any) {
        let position = element.attributes['position'].value;
        let strDomains = this.domainsLabel.split('>');            
        console.log('its working');
    }

    public redirectTo(name: string) {
        switch (this.$state.current.name) {
            case 'root.domains':
                var proj = this.$filter('filter')(this.domains, { id: name }, true);
                var subDomainsParam = proj[0].subDomains;
                var jobsParam = proj[0].jobs;
                var obj = {
                    subDomName: this.domainsLabel + '>' + name,
                    pDomains: this.domains,
                    subDomains: subDomainsParam,
                    jobs: jobsParam,
                    pJobs: this.jobs,
                    pFolder: this.domainsLabel
                };
                this.$state.go('root.subDomains', obj);
                break;
            case 'root.subDomains':
                var proj = this.$filter('filter')(this.domains, { id: name }, true);
                var subSubDomainsParam = proj[0].subSubDomains;
                var jobsParam = proj[0].jobs;
                var obj2 = {
                    subSubDomName: this.domainsLabel + '>' + name,
                    pDomains: this.domains,
                    ppDomains: this.pDomains,
                    subSubDomains: subSubDomainsParam,
                    jobs: jobsParam,
                    pJobs: this.jobs,
                    ppJobs: this.pJobs,
                    pFolder: this.domainsLabel,
                    ppFolder: this.pFolder
                };

                this.$state.go('root.subSubDomains', obj2);
                break;
            case 'root.subSubDomains':
                var proj = this.$filter('filter')(this.domains, { id: name }, true);
                var jobsParam = proj[0].jobs;
                var obj1 = {
                    lastLevelName: this.domainsLabel + '>' + name,
                    pDomains: this.domains,
                    ppDomains: this.pDomains,
                    pppDomains: this.ppDomains,
                    jobs: jobsParam,
                    pJobs: this.jobs,
                    ppJobs: this.pJobs,
                    pFolder: this.domainsLabel,
                    ppFolder: this.pFolder,
                    pppFolder: this.ppFolder
                };

                this.$state.go('root.lastLevel', obj1);
                break;
        }
    }
}

class TabsDomainsComponent implements ng.IComponentOptions {
    public bindings: any;
    public controller: any;
    public controllerAs: string;
    public templateUrl: string;

    constructor() {
        this.bindings = {
            domains: '<',
            jobs: '<',
            jobsLabel: '<',
            domainsLabel: '<',
            pDomains: '<',
            ppDomains: '<',
            pppDomains: '<',
            pJobs: '<',
            ppJobs: '<',
            pppJobs: '<',
            pFolder: '<',
            ppFolder: '<',
            pppFolder: '<'
        };
        this.controller = TabsDomainsComponentController;
        this.controllerAs = 'TabsDomains';
        this.templateUrl = 'public/app/views/components/tabsDomains/tabs.domains.html';
    }

}

angular.module('rundeckManager.tabs')
    .component('tabsDomains', new TabsDomainsComponent());

    }

I found an answer which looked like the problem I'm having at first, but the solution didn't apply to my case :

Links not working in ng-bind-html

I'd be great if anyone can explain it to me and help me with a solution.

Thank you

Zakaria Sahmane
  • 210
  • 2
  • 16

1 Answers1

0

You have to run $compile(this.domainsLabelHtml)($scope); after you inject Html code, that should be managed by Angular.

EDIT

I think compiling this.domainsLabelHtml might not work. Try to add an Id to than span that should bind the Html and than do:

//Html
 <span id="id-of-span" ng-bind-html="TabsDomains.trustedHtml(TabsDomains.domainsLabelHtml)"></span>

//JS
$compile(angular.element('#id-of-span'))($scope);
scipper
  • 2,944
  • 3
  • 22
  • 45
  • I tried this but it doesn't work. I don't get an error or anything. It's acting as if i'm clicking on a blank space. I tried this : this.$compile(angular.element(document.querySelector('#id-of-span')))(this.$scope); after binding $compile and $scope to my controller. – Zakaria Sahmane Oct 25 '17 at 15:08
  • you dont need document.querySelector within angular.element. but i dont think that this is the problem, thou. – scipper Oct 25 '17 at 18:54
  • The thing is, i had the following error when i didn't use it : "Looking up elements via selectors is not supported by jqLite!" – Zakaria Sahmane Oct 26 '17 at 06:57
  • good point, sorry about that. I always use a full jquery by default, so I forgot that. – scipper Oct 26 '17 at 07:21
  • Is it possible for you, to set a debugger statement or console.log within the TabsDomains.goTo method? Just to be sure, that it is not entered? I was looking at your screenshot `dynamicallyGeneratedCode` and I saw, that Angular rendered the classes ng-scope and ng-binding, which tells me, that this element is parsed by Angular. – scipper Oct 26 '17 at 07:25
  • I already have "console.log('its working');" in the method "TabsDomains.goTo", which display with the static code but not with the dynamically generated one. I commented the other stuff in the method to let only the console.log to be sure nothing's interfering. It doesn't even enter in the method. It's the same as clicking on an empty div. Since i have no errors on the Console, i think he doesn't get the right scope but that's just a hypothesis. – Zakaria Sahmane Oct 26 '17 at 08:19
  • Just a thought: can you replace the a tag by, lets say a button? – scipper Oct 26 '17 at 08:34
  • Just did, we see the button, the visual effect occurs on click, but it doesn't enter the method on the ng-click. Also tried to write "console.log" directly in the ng-click, doesn't trigger either. – Zakaria Sahmane Oct 26 '17 at 08:52
  • could you paste the whole component declaration in your question? – scipper Oct 26 '17 at 11:15
  • I updated my class code in my question. If it can help. – Zakaria Sahmane Oct 26 '17 at 13:12
  • hmm the code looks good as far as I can see. I am afraid, that I cant help you anymore. At this point, I usually would debug thing like the $compile execution, or the onclick event of the pasted element. – scipper Oct 26 '17 at 13:36
  • Thanks a lot anyway ! – Zakaria Sahmane Oct 26 '17 at 13:52
  • Yes ! You were right all along but for some reason, the wrong scope was used(Still can't figure out why, even my colleagues couldn't explain). All i had to do is copy the same code into a directive that i created, everything worked fine after that. So insted of ng-bind-html i had my own directive bind-compile-hml ! – Zakaria Sahmane Nov 10 '17 at 10:02
  • Thanks for the help anyway ! – Zakaria Sahmane Nov 10 '17 at 10:03