angular ng-bind-html dan direktif di dalamnya

96

Tautan Plunker

Saya memiliki elemen yang saya ingin mengikatkan html padanya.

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

Itu bekerja. Sekarang, bersamaan dengan itu saya juga memiliki arahan yang terikat pada html yang terikat:

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

Tetapi arahan upperdengan div dan anchor tidak dievaluasi. Bagaimana cara membuatnya bekerja?

Amitava
sumber
3
Lihat jawaban saya di sini stackoverflow.com/questions/17343696/…
Chandermani
@Chandermani tidak persis menggunakan direktif di dalam ng-bind-html-unsafe tetapi menggunakan filter. Tapi itu akan berhasil, saya baru saja membuat filter dan meneruskan ke direktif. Terima kasih!
Amitava
@SamSerious, apakah Anda dapat menunjukkan bagaimana Anda melakukan apa yang Anda lakukan untuk filter?
CMCDragonkai
solusi di atas tidak menangani banyak perubahan nilai solusi yang lebih baik stackoverflow.com/a/25516311/3343425
fghibellini

Jawaban:

188

Saya juga menghadapi masalah ini dan setelah berjam-jam mencari di internet saya membaca komentar @ Chandermani, yang terbukti menjadi solusinya. Anda perlu memanggil arahan 'kompilasi' dengan pola ini:

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);
            }
        );
    };
}])

Anda dapat melihat biola yang berfungsi di sini

vkammerer.dll
sumber
1
Sejalan # 2, yaitu. function(scope, element, attrs), dari mana Anda mendapatkan tiga argumen, cakupan , elemen , dan atribut tersebut ?
spaffy
1
@spaffy - mereka adalah bagian dari tanda tangan kerangka kerja Angular untuk linkproperti. Mereka akan diteruskan secara otomatis setiap kali linkdipanggil oleh kerangka Angular. Mereka akan selalu tersedia.
Ben
1
Sudah selesai dilakukan dengan baik. Anda menyelamatkan saya pada jam-jam pencarian yang sama. Saya menarik konten dari REST API tampilan SharePoint, yang berisi markup Angular seperti ng-repeat. Arahan Anda membuat semuanya bekerja. Terima kasih!
Phil Nicholas
Terima kasih atas arahan Anda, ini memperbaiki masalah yang saya alami. Sekarang kode sudut dikompilasi tetapi terlalu banyak kali. Sebuah ng-pengulangan dengan 3 objek berubah menjadi nilai yang sama hanya masing-masing 3x. Apa yang salah di sini?
Jason
2
Jika Anda telah menggunakan $sce.trustAsHtmldari fungsi lain untuk membuat HTML yang akan "dikompilasi" dengan petunjuk ini, Anda harus menghapusnya. Terima kasih kepada @apoplexy
Burak Tokak
36

Terima kasih atas jawaban hebat vkammerer. Satu pengoptimalan yang saya rekomendasikan adalah tidak menonton setelah kompilasi berjalan satu kali. $ Eval dalam ekspresi jam tangan dapat memiliki implikasi kinerja.

    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();
            }
        );
    };
}]);

Ini biola bercabang dua dan diperbarui.

pengguna3075469
sumber
Bisakah saya meminta sebaliknya?
Sanyam Jain
ini tidak berfungsi sebagai tanggapan dari ajax tetapi pekerjaan jawaban yang diterima
foozhan
1
Peringatan: Biola untuk jawaban ini berfungsi, tetapi .directive()kode dalam kode yang diposting di jawaban tidak.
Phil Nicholas
yang satu ini berhasil untuk saya. jawaban yang dipilih akan memicu "Kesalahan: $ rootScope: infdig Infinite $ digest Loop"
Gabriel Andrei
Anda tidak perlu explict $eval- Anda bisa menggunakan attrs.compilelangsung sebagai pengganti fungsi anonim yang diawasi. Jika Anda hanya memberikan ekspresi string, angular akan tetap memanggilnya $eval.
Dan King
28

Tambahkan direktif angular-bind-html-compile ini

.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);
      });
    }
  };
}]);

Gunakan seperti ini:

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

Sangat mudah :)

Joël
sumber
1
Hati-hati, jika Anda mengirimkan sesuatu seperti ini: "$ scope.loadContent = function () {return $ sce.trustAsHtml (require ('html / main-content.html'));};" untuk itu Anda bisa mendapatkan loop intisari tak terbatas. Tanpa trustAsHtml itu bekerja.
Lakatos Gyula
13

Sayangnya saya tidak memiliki reputasi yang cukup untuk berkomentar.

Saya tidak bisa membuat ini bekerja selama berabad-abad. Saya memodifikasi ng-bind-htmlkode saya untuk menggunakan arahan khusus ini, tetapi saya gagal menghapus $scope.html = $sce.trustAsHtml($scope.html)yang diperlukan agar ng-bind-html berfungsi. Segera setelah saya menghapus ini, fungsi kompilasi mulai bekerja.

pitam
sumber
6

Bagi siapa pun yang berurusan dengan konten yang telah dijalankan di $sce.trustAsHtmlsini, itulah yang harus saya lakukan secara berbeda

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();
        });
}

Ini hanya linkbagian dari direktif karena saya menggunakan tata letak yang berbeda. Anda juga perlu menyuntikkan $scelayanan $compile.

MStrutt
sumber
-2

Solusi terbaik yang saya temukan! Saya menyalinnya dan berfungsi persis seperti yang saya butuhkan. Terima kasih, terima kasih, terima kasih ...

dalam fungsi tautan direktif yang saya miliki

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

dan dalam template direktif:

<span compile="renderingElement"></span>
yustme
sumber