6

Ich möchte ng-include im Inhalt einer dynamisch generierten Registerkarte mit AngularJs und UI Bootstrap verwenden.Dynamischer Inhalt in der Registerkarte "Dynamisch" (Angular, UI Bootstrap)

Ich habe einen Plunker hier: http://plnkr.co/edit/2mpbovsu2eDrUdu8t7SM?p=preview

<div id="mainCntr" style="padding: 20px;"> 
    <uib-tabset> 
    <uib-tab ng-repeat="tab in tabs" active="tab.active" disable="tab.disabled"> 
     <uib-tab-heading> 
     {{tab.title}} <i class="glyphicon glyphicon-remove-sign" ng-click="removeTab($index)"></i> 
     </uib-tab-heading> 
     {{tab.content}} 
    </uib-tab> 
    </uib-tabset> 
</div> 

JS-Code:

$scope.addTab = function() { 
    var len = $scope.tabs.length + 1; 
    var numLbl = '' + ((len > 9) ? '' : '0') + String(len); 

    var mrkUp = '<div>' + 
     '<h1>New Tab ' + numLbl + ' {{foo}}</h1>' + 
     '<div ng-include="tab.tabUrl" class="ng-scope"></div>' + 
     '</div>'; 

    $scope.tabs.push({title: 'Tab ' + numLbl, content: $compile(angular.element(mrkUp))($scope)}); 
} 

Im Plunker, klicken Sie auf die Schaltfläche "Hinzufügen Tab" -Taste. Es ruft eine Funktion in $ scope auf, die eine neue Registerkarte an die Sammlung sendet, aber dynamisch generierten Inhalt mit einer ng-include-Direktive weitergibt. Die erwartete Ausgabe ist, dass das ng-include innerhalb des Tab-Inhaltsbereichs angezeigt wird.

Dank

+0

Ihr Plunk funktioniert nicht richtig, denke ich? –

+0

Ich konnte es nicht zur Arbeit bringen. Das Plunk ist nur mein Versuch - hoffend, dass jemand hier mir helfen kann, es zur Arbeit zu bringen. – vdiaz1130

+0

... oh, jetzt funktioniert es. Als ich es früher ansah, war es kaputt. Werde mich nochmal umsehen. –

Antwort

4

In Ihrem Plunker Sie ng-bind-html verwenden, die nicht die HTML für Sie nicht kompilieren. Sie können eine neue Direktive erstellen, die das für Sie erledigt.

Quellcode für ng-bind-html:

var ngBindHtmlDirective = ['$sce', '$parse', '$compile', function($sce, $parse, $compile) { 
    return { 
    restrict: 'A', 
    compile: function ngBindHtmlCompile(tElement, tAttrs) { 
     var ngBindHtmlGetter = $parse(tAttrs.ngBindHtml); 
     var ngBindHtmlWatch = $parse(tAttrs.ngBindHtml, function getStringValue(value) { 
     return (value || '').toString(); 
     }); 
     $compile.$$addBindingClass(tElement); 

     return function ngBindHtmlLink(scope, element, attr) { 
     $compile.$$addBindingInfo(element, attr.ngBindHtml); 

     scope.$watch(ngBindHtmlWatch, function ngBindHtmlWatchAction() { 
      // we re-evaluate the expr because we want a TrustedValueHolderType 
      // for $sce, not a string 
      element.html($sce.getTrustedHtml(ngBindHtmlGetter(scope)) || ''); 
     }); 
     }; 
    } 
    }; 
}]; 

Wählen Sie einen Namen für die neue Richtlinie, zum Beispiel compile-html.

Ersetzen Sie tAttrs.ngBindHtml durch tAttrs.compileHtml (oder den von Ihnen gewählten Namen).

Sie müssen $sce.getTrustedHtml mit $sce.trustAsHtml ersetzen, oder Sie bekommen Error: [$sce:unsafe] Attempting to use an unsafe value in a safe context.

Dann müssen Sie rufen $compile:

$compile(element.contents())(scope); 

Voll Richtlinie:

app.directive('compileHtml', ['$sce', '$parse', '$compile', 
    function($sce, $parse, $compile) { 
    return { 
     restrict: 'A', 
     compile: function ngBindHtmlCompile(tElement, tAttrs) { 
     var ngBindHtmlGetter = $parse(tAttrs.compileHtml); 
     var ngBindHtmlWatch = $parse(tAttrs.compileHtml, function getStringValue(value) { 
      return (value || '').toString(); 
     }); 
     $compile.$$addBindingClass(tElement); 

     return function ngBindHtmlLink(scope, element, attr) { 
      $compile.$$addBindingInfo(element, attr.compileHtml); 

      scope.$watch(ngBindHtmlWatch, function ngBindHtmlWatchAction() { 

      element.html($sce.trustAsHtml(ngBindHtmlGetter(scope)) || ''); 
      $compile(element.contents())(scope); 
      }); 
     }; 
     } 
    }; 
    } 
]); 

Verbrauch:

<div compile-html="tab.content"></div> 

Demo:http://plnkr.co/edit/TRYAaxeEPMTAay6rqEXp?p=preview

1

Meine Situation ist vielleicht nicht so komplex sein, so dass diese einfache Lösung funktioniert:

sdo.tabs:{ 
     data:[], 
     active:0, 
     reset: function(){ 
      var tabs = this.data; 
      while(tabs.length > 0) { 
       this.removeTab(tabs[tabs.length-1].child.name); 
      } 
      this.active = 0; 
     }, 
     childExists: function(childName) { 
      var fromTheTop = this.data.length, 
       parentName = (this.active > 0 ? this.data[ this.active - 1 ].child.name : 'zero'); 
      while(fromTheTop > this.active) { 
       var child = this.data[ fromTheTop-1 ].child; 
       if(child && child.parent === parentName && child.name === childName) return fromTheTop; 
       fromTheTop--; 
      } 
      return false; 
     }, 
     removeTab: function(name) { // will remove any descendents of this tab as well, see recursive call near end 
      var fromTheTop = this.data.length; 
      while(fromTheTop > 0) { 
       var tab = this.data[fromTheTop - 1]; 
       if(tab.child.name === name) { 
        angular.element('#'+name).empty(); 
        this.data.splice(fromTheTop - 1); 
        return; 
       } 
       if(tab.child.parent === name) this.removeTab(tab.child.name); 
       fromTheTop--; 
      }; 
     }, 
     /* 
     * tab is string identifies tab but doesn't show in the UI 
     * tempmlate is HTML template 
     * scope is used to compile template 
     * title is string or function for UI tab title, appears in the tab row 
     */ 
     create: function(tab, template, scope, title) { 
      var childName = tab; 
      var tabs = this.data; 
      tab = this.childExists(childName); 
      if(tab === false) { 
       tab = tabs.length + 1; 
      } else { // recycling a tab, kill it & its descendents 
       this.removeTab(childName); 
      } 
      tabs[tab-1] = { 
       title:function(){ 
        if(angular.isFunction(title)) return title(); 
        return title; 
       }, 
       child: { 
        parent:(this.active > 0 ? this.data[ this.active - 1 ].child.name : 'zero'), 
        name:childName 
       }      
      }; 
      var ct = $timeout(function() { 
       angular.element('#'+tabs[tab-1].child.name).html($compile(template)(scope)); 
       sdo.tabs.active = tab; 
       return; // return nothing to avoid memory leak 
      }); 
      scope.$on('$destroy', function() { 
       $timeout.cancel(ct); 
      }); 
      return ct; // ct is a promise 
     } 
    } 

HTML

<uib-tabset active="tabs.active"> 
 
    <uib-tab index='0' heading="{{title}}"> 
 
     <ng-view></ng-view> 
 
    </uib-tab> 
 
    <uib-tab ng-repeat="tab in tabs.data track by tab.child.name" heading="{{tab.title()}}" index='$index+1' > 
 
     <div id="{{tab.child.name}}"></div> 
 
    </uib-tab> 
 
</uib-tabset>

ist

In meinem Fall ist die erste Registerkarte von der Angular Router besetzt, weshalb die Registerkarte Array ist ein Index aus tabs.active

Verwandte Themen