ng-bind-html เชิงมุมและคำสั่งภายใน


95

ลิงค์ Plunker

ฉันมีองค์ประกอบที่ฉันต้องการผูก html กับมัน

<div ng-bind-html="details" upper></div>

ที่ได้ผล ตอนนี้ฉันยังมีคำสั่งที่ผูกไว้กับ html ที่ถูกผูกไว้:

$scope.details = 'Success! <a href="#/details/12" upper>details</a>'

แต่คำสั่งที่upperมี div และ anchor จะไม่ประเมิน ฉันจะทำให้มันทำงานได้อย่างไร?


3
ดูคำตอบของฉันที่นี่stackoverflow.com/questions/17343696/…
Chandermani

@Chandermani ไม่ได้ใช้คำสั่งภายใน ng-bind-html-unsafe แต่ใช้ตัวกรอง แต่จะทำฉันเพิ่งสร้างตัวกรองและส่งผ่านไปยังคำสั่ง ขอบคุณ!
Amitava

@SamSerious คุณสามารถแสดงให้เห็นว่าคุณทำสิ่งที่คุณทำเพื่อฟิลเตอร์ได้อย่างไร?
CMCDragonkai

วิธีแก้ปัญหาข้างต้นไม่สามารถจัดการกับการเปลี่ยนแปลงหลาย ๆ ค่าได้เป็นวิธีแก้ปัญหาที่ดีกว่าstackoverflow.com/a/25516311/3343425
fghibellini

คำตอบ:


187

ฉันก็ประสบปัญหานี้เช่นกันและหลังจากผ่านไปหลายชั่วโมงค้นหาอินเทอร์เน็ตฉันอ่านความคิดเห็นของ @ Chandermani ซึ่งพิสูจน์แล้วว่าเป็นวิธีแก้ปัญหา คุณต้องเรียกคำสั่ง 'คอมไพล์' ด้วยรูปแบบนี้:

HTML:

<div compile="details"></div>

JS:

.directive('compile', ['$compile', function ($compile) {
    return function(scope, element, attrs) {
        scope.$watch(
            function(scope) {
                // watch the 'compile' expression for changes
                return scope.$eval(attrs.compile);
            },
            function(value) {
                // when the 'compile' expression changes
                // assign it into the current DOM
                element.html(value);

                // compile the new DOM and link it to the current
                // scope.
                // NOTE: we only compile .childNodes so that
                // we don't get into infinite loop compiling ourselves
                $compile(element.contents())(scope);
            }
        );
    };
}])

คุณสามารถดูซอที่ใช้งานได้ที่นี่


1
ในบรรทัดที่ 2 เช่น. function(scope, element, attrs), คุณไม่ได้รับมาจากไหนทั้งสามข้อโต้แย้งขอบเขต , องค์ประกอบและattrs ?
spaffy

1
@spaffy - เป็นส่วนหนึ่งของลายเซ็นของ Angular framework สำหรับlinkคุณสมบัติ ซึ่งจะถูกส่งผ่านโดยอัตโนมัติทุกครั้งเมื่อlinkถูกเรียกโดย Angular framework พวกเขาจะพร้อมใช้งานเสมอ
เบ็น

1
ทำได้ดี. คุณช่วยฉันในชั่วโมงเดียวกันในการค้นหา ฉันกำลังดึงเนื้อหาจาก SharePoint view REST API ซึ่งมีมาร์กอัปเชิงมุมเช่น ng-repeat คำสั่งของคุณทำให้ทุกอย่างได้ผล ขอบคุณ!
Phil Nicholas

ขอบคุณสำหรับคำสั่งของคุณที่ช่วยแก้ไขปัญหาที่ฉันพบ ตอนนี้โค้ดเชิงมุมได้รับการคอมไพล์ แต่หลายครั้งเกินไป การทำซ้ำกับวัตถุ 3 ชิ้นจะเปลี่ยนเป็นค่าเดียวกันเพียง 3x ต่อชิ้น เกิดอะไรขึ้นที่นี่?
Jason

2
หากคุณใช้$sce.trustAsHtmlจากฟังก์ชันอื่นเพื่อสร้าง HTML ที่จะ "คอมไพล์" ด้วยคำสั่งนี้คุณควรลบออก ขอบคุณข้อมูล @apoplexy
Burak Tokak

36

ขอบคุณสำหรับคำตอบที่ดี vkammerer การเพิ่มประสิทธิภาพอย่างหนึ่งที่ฉันอยากแนะนำคือยกเลิกการดูหลังจากการคอมไพล์ทำงานครั้งเดียว $ eval ภายในนิพจน์ของนาฬิกาอาจมีผลต่อประสิทธิภาพ

    angular.module('vkApp')
  .directive('compile', ['$compile', function ($compile) {
      return function(scope, element, attrs) {
          var ensureCompileRunsOnce = scope.$watch(
            function(scope) {
               // watch the 'compile' expression for changes
              return scope.$eval(attrs.compile);
            },
            function(value) {
              // when the 'compile' expression changes
              // assign it into the current DOM
              element.html(value);

              // compile the new DOM and link it to the current
              // scope.
              // NOTE: we only compile .childNodes so that
              // we don't get into infinite loop compiling ourselves
              $compile(element.contents())(scope);

              // Use un-watch feature to ensure compilation happens only once.
              ensureCompileRunsOnce();
            }
        );
    };
}]);

นี่คือซอที่แยกและปรับปรุงแล้ว


ฉันสามารถหาทางกลับกันได้หรือไม่?
Sanyam Jain

สิ่งนี้ใช้ไม่ได้ในการตอบสนองของ ajax แต่ได้รับการตอบรับ
foozhan

1
คำเตือน: ซอสำหรับคำตอบนี้ใช้งานได้ แต่.directive()รหัสในรหัสที่โพสต์ในคำตอบใช้ไม่ได้
Phil Nicholas

อันนี้ใช้ได้ผลสำหรับฉัน คำตอบที่เลือกจะทำให้เกิด "ข้อผิดพลาด: $ rootScope: infdig Infinite $ Digest Loop"
Gabriel Andrei

คุณไม่จำเป็นต้องมีการระเบิด$eval- คุณสามารถใช้attrs.compileแทนฟังก์ชันนิรนามที่เฝ้าดูได้โดยตรง หากคุณเพียงแค่ใส่นิพจน์สตริงเชิงมุมก็จะเรียก$evalมันอยู่ดี
Dan King

28

เพิ่มคำสั่งangular-bind-html-compile นี้

.directive('bindHtmlCompile', ['$compile', function ($compile) {
  return {
    restrict: 'A',
    link: function (scope, element, attrs) {
      scope.$watch(function () {
        return scope.$eval(attrs.bindHtmlCompile);
      }, function (value) {
        // Incase value is a TrustedValueHolderType, sometimes it
        // needs to be explicitly called into a string in order to
        // get the HTML string.
        element.html(value && value.toString());
        // If scope is provided use it, otherwise use parent scope
        var compileScope = scope;
        if (attrs.bindHtmlScope) {
          compileScope = scope.$eval(attrs.bindHtmlScope);
        }
        $compile(element.contents())(compileScope);
      });
    }
  };
}]);

ใช้แบบนี้:

<div bind-html-compile="data.content"></div>

ง่ายจริงๆ :)


1
โปรดระวังหากคุณส่งข้อความเช่นนี้: "$ scope.loadContent = function () {return $ sce.trustAsHtml (ต้องใช้ ('html / main-content.html'));};" คุณจะได้รับลูปการย่อยที่ไม่มีที่สิ้นสุด หากไม่มี trustAsHtml ก็ใช้งานได้
Lakatos Gyula

13

น่าเสียดายที่ฉันไม่มีชื่อเสียงมากพอที่จะแสดงความคิดเห็น

ฉันไม่สามารถใช้งานได้นานหลายปี ฉันแก้ไขng-bind-htmlโค้ดเพื่อใช้คำสั่งที่กำหนดเองนี้ แต่ฉันไม่สามารถลบสิ่ง$scope.html = $sce.trustAsHtml($scope.html)ที่จำเป็นเพื่อให้ ng-bind-html ทำงานได้ ทันทีที่ฉันลบสิ่งนี้ฟังก์ชันคอมไพล์ก็เริ่มทำงาน


6

สำหรับใครก็ตามที่เกี่ยวข้องกับเนื้อหาที่ได้รับการดำเนินการแล้ว$sce.trustAsHtmlนี่คือสิ่งที่ฉันต้องทำแตกต่าง

function(scope, element, attrs) {
    var ensureCompileRunsOnce = scope.$watch(function(scope) {
            return $sce.parseAsHtml(attrs.compile)(scope);
        },
        function(value) {
            // when the parsed expression changes assign it into the current DOM
            element.html(value);

            // compile the new DOM and link it to the current scope.
            $compile(element.contents())(scope);

            // Use un-watch feature to ensure compilation happens only once.
            ensureCompileRunsOnce();
        });
}

นี่เป็นเพียงlinkส่วนหนึ่งของคำสั่งเนื่องจากฉันใช้เค้าโครงอื่น คุณจะต้องฉีดให้บริการเช่นเดียวกับ$sce$compile


-2

ทางออกที่ดีที่สุดที่ฉันพบ! ฉันคัดลอกมาและทำงานได้ตรงตามที่ฉันต้องการ ขอบคุณขอบคุณขอบคุณ ...

ในฟังก์ชันลิงก์คำสั่งฉันมี

app.directive('element',function($compile){
  .
  .
     var addXml = function(){
     var el = $compile('<xml-definitions definitions="definitions" />')($scope);
     $scope.renderingElement = el.html();
     }
  .
  .

และในเทมเพลตคำสั่ง:

<span compile="renderingElement"></span>
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.