Kompilowanie dynamicznych łańcuchów HTML z bazy danych

Sytuacja

Zagnieżdżona w naszej aplikacji Angular jest dyrektywa o nazwie Page, wspierana przez kontroler, który zawiera div z atrybutem ng-bind-html-unsafe. Jest to przypisane do zmiennej $ scope o nazwie 'pageContent'. Ten var otrzymuje przypisany dynamicznie generowany HTML z bazy danych. Gdy użytkownik przewraca się do następnej strony, robi się wywołanie do DB, a pageContent var jest ustawiony na ten nowy HTML, który jest renderowany na ekranie przez NG-bind-html-unsafe. Oto kod:

Page directive

angular.module('myApp.directives')
    .directive('myPage', function ($compile) {

        return {
            templateUrl: 'page.html',
            restrict: 'E',
            compile: function compile(element, attrs, transclude) {
                // does nothing currently
                return {
                    pre: function preLink(scope, element, attrs, controller) {
                        // does nothing currently
                    },
                    post: function postLink(scope, element, attrs, controller) {
                        // does nothing currently
                    }
                }
            }
        };
    });

Szablon dyrektywy Page ("strona.html " z właściwości templateUrl powyżej)

<div ng-controller="PageCtrl" >
   ...
   <!-- dynamic page content written into the div below -->
   <div ng-bind-html-unsafe="pageContent" >
   ...
</div>

Page controller

angular.module('myApp')
  .controller('PageCtrl', function ($scope) {

        $scope.pageContent = '';

        $scope.$on( "receivedPageContent", function(event, args) {
            console.log( 'new page content received after DB call' );
            $scope.pageContent = args.htmlStrFromDB;
        });

});
To działa. Widzimy HTML strony z DB ładnie renderowane w przeglądarce. Gdy użytkownik przewraca się do następnej strony, widzimy zawartość następnej strony i tak dalej. Jak na razie dobrze.

Problem

Problem polega na tym, że chcemy mieć interaktywne treści wewnątrz zawartość strony. Na przykład, HTML może zawierać miniaturkę obrazu, gdzie, gdy użytkownik kliknie na niego, Angular powinien zrobić coś niesamowitego, takiego jak wyświetlanie wyskakującego okna modalnego. Umieściłem wywołania metody Angular (ng-click) w łańcuchach HTML w naszej bazie danych, ale oczywiście Angular nie rozpozna ani wywołań metod, ani dyrektyw, chyba że w jakiś sposób parsuje łańcuch HTML, rozpoznaje je i kompiluje.

W naszym DB

Treść strony 1:

<p>Here's a cool pic of a lion. <img src="lion.png" ng-click="doSomethingAwesone('lion', 'showImage')" > Click on him to see a large image.</p>

Zawartość strony 2:

<p>Here's a snake. <img src="snake.png" ng-click="doSomethingAwesone('snake', 'playSound')" >Click to make him hiss.</p>

Z powrotem do kontrolera strony, dodajemy odpowiednią funkcję $scope:

Page controller

$scope.doSomethingAwesome = function( id, action ) {
    console.log( "Going to do " + action + " with "+ id );
}

Nie wiem, jak wywołać metodę 'doSomethingAwesome' z łańcucha HTML z DB. Zdaję sobie sprawę, że Angular musi jakoś parsować łańcuch HTML, ale jak? Czytałem niejasne bełkoty o usłudze $ compile, skopiowałem i wkleiłem kilka przykładów, ale nic nie działa. Ponadto większość przykładów pokazuje dynamiczne treści są ustawiane dopiero w fazie łączenia dyrektywy. Chcielibyśmy, aby strona pozostała żywa przez cały okres użytkowania aplikacji. Stale otrzymuje, kompiluje i wyświetla nowe treści, gdy użytkownik przewraca strony.

W abstrakcyjnym sensie, myślę, że można powiedzieć, że staramy się dynamicznie zagnieżdżać kawałki Angular w aplikacji Angular i musimy być w stanie je wymieniać.

Czytałem kilka razy różne fragmenty dokumentacji kątowej, a także wszystkie wpisy na blogu i JS Nie wiem, czy kompletnie nie rozumiem, czy po prostu brakuje mi czegoś prostego, czy może jestem powolny. W każdym razie, przydałaby mi się Rada.

Author: isherwood, 2013-08-10

5 answers

ng-bind-html-unsafe renderuje tylko zawartość jako HTML. Nie wiąże zakresu kątowego z uzyskanym DOM. W tym celu należy skorzystać z usługi $compile. Stworzyłem Ten plunker aby zademonstrować jak używać $compile do tworzenia dyrektywy renderującej dynamiczny HTML wprowadzany przez użytkowników i wiążący się z zakresem kontrolera. Źródło znajduje się poniżej.

Demo.html

<!DOCTYPE html>
<html ng-app="app">

  <head>
    <script data-require="[email protected]" data-semver="1.0.7" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.js"></script>
    <script src="script.js"></script>
  </head>

  <body>
    <h1>Compile dynamic HTML</h1>
    <div ng-controller="MyController">
      <textarea ng-model="html"></textarea>
      <div dynamic="html"></div>
    </div>
  </body>

</html>

Scenariusz.js

var app = angular.module('app', []);

app.directive('dynamic', function ($compile) {
  return {
    restrict: 'A',
    replace: true,
    link: function (scope, ele, attrs) {
      scope.$watch(attrs.dynamic, function(html) {
        ele.html(html);
        $compile(ele.contents())(scope);
      });
    }
  };
});

function MyController($scope) {
  $scope.click = function(arg) {
    alert('Clicked ' + arg);
  }
  $scope.html = '<a ng-click="click(1)" href="#">Click me</a>';
}
 246
Author: Buu Nguyen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-10 01:55:42

W angular 1.2.10 linia scope.$watch(attrs.dynamic, function(html) { zwracała błąd nieprawidłowego znaku, ponieważ próbowała obserwować wartość attrs.dynamic, którą był tekst html.

Naprawiłem to pobierając atrybut z właściwości scope

 scope: { dynamic: '=dynamic'}, 

Mój przykład

angular.module('app')
  .directive('dynamic', function ($compile) {
    return {
      restrict: 'A',
      replace: true,
      scope: { dynamic: '=dynamic'},
      link: function postLink(scope, element, attrs) {
        scope.$watch( 'dynamic' , function(html){
          element.html(html);
          $compile(element.contents())(scope);
        });
      }
    };
  });
 19
Author: Alexandros Spyropoulos,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-01-30 00:44:55

Znalezione w grupie dyskusyjnej google. Mi pasuje.

var $injector = angular.injector(['ng', 'myApp']);
$injector.invoke(function($rootScope, $compile) {
  $compile(element)($rootScope);
});
 5
Author: kwerle,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-15 19:04:28

Możesz użyć

Ng-bind-html https://docs.angularjs.org/api/ng/service / $sce

Dyrektywa dynamicznie wiążąca html. Musisz jednak uzyskać dane za pośrednictwem usługi $sce.

Zobacz demo na żywo na http://plnkr.co/edit/k4s3Bx

var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope,$sce) {
    $scope.getHtml=function(){
   return $sce.trustAsHtml("<b>Hi Rupesh hi <u>dfdfdfdf</u>!</b>sdafsdfsdf<button>dfdfasdf</button>");
   }
});

  <body ng-controller="MainCtrl">
<span ng-bind-html="getHtml()"></span>
  </body>
 3
Author: Rupesh Kumar Tiwari,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-14 17:59:15

Wypróbuj poniższy kod do wiązania html przez attr

.directive('dynamic', function ($compile) {
    return {
      restrict: 'A',
      replace: true,
      scope: { dynamic: '=dynamic'},
      link: function postLink(scope, element, attrs) {
        scope.$watch( 'attrs.dynamic' , function(html){
          element.html(scope.dynamic);
          $compile(element.contents())(scope);
        });
      }
    };
  });

Spróbuj tego elementu.html (scope.dynamiczny); niż element.html (attr.dynamiczny);

 1
Author: Ramesh M,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-18 08:13:47