2015-12-11 2 views
4

Я использую ng-bind-html для привязки данных, которые я получаю из базы данных.Угловая JS: обнаружение, если ng-bind-html закончила загрузку, затем выделите синтаксис кода

<p ng-bind-html="myHTML"></p> 


app.controller('customersCtrl', function($scope, $http, $stateParams) { 
    console.log($stateParams.id); 
    $http.get("api link"+$stateParams.id) 
    .then(function(response) { 
     $scope.myHTML = response.data.content; 

     // this will highlight the code syntax 
     $('pre code').each(function(i, block) { 
      hljs.highlightBlock(block); 
     }); 
    }); 
}); 

Когда данные, отображаемые на экране, я хочу, чтобы запустить

$('pre code').each(function(i, block) { 
     hljs.highlightBlock(block); 
}); 

для подсветки синтаксиса кода в данных, но не выделить. (Я использую highlight library in CKEditor для подсветки синтаксиса кода)

И если я оттянуть загрузить код выделения после 1s, он будет работать, но я думаю, что это не является хорошим решением

setTimeout(function() { 
    $('pre code').each(function(i, block) { 
     hljs.highlightBlock(block); 
    }); 
    }, 1000); 

Я думаю, может быть код выделить пробег до ng-bind-html закончен.

=== UPDATE
Я использую $timeout со временем задержки 0, как несколько человек рекомендуют. Тем не менее, когда-то, когда сеть работает медленно и медленная загрузка страницы, код не будет выделен.

$scope.myHTML = response.data.content; 
$timeout(function() { 
    $('pre code').each(function(i, block) { 
     hljs.highlightBlock(block); 
    }); 
}, 0); 
+0

использование '$ timeout' вместо' setTimeout'; '$ timeout' - это оболочка, которая обеспечивает обработку' $ digest'. вам может даже не понадобиться задержка в 1 секунде в этом случае, просто время, которое требуется для обработки '$ digest'. – Claies

+0

Я хочу знать, сколько времени в этом случае занимает? как его рассчитать? –

+0

вам не нужно его вычислять; '$ timeout' автоматически выдает' $ digest' (который перерисовывает интерфейс), а затем выполняет логику внутри, а не ждет статического количества времени. – Claies

ответ

4

Здесь директивы приходят очень кстати. Почему бы не добавить HTML самостоятельно, а затем запустить маркер?

Шаблон:

<div ng-model="myHTML" highlight></div> 

Директива:

.directive('highlight', [ 
    function() { 
     return { 
      replace: false, 
      scope: { 
       'ngModel': '=' 
      }, 
      link: function (scope, element) { 
       element.html(scope.ngModel); 
       var items = element[0].querySelectorAll('code,pre'); 
       angular.forEach(items, function (item) { 
        hljs.highlightBlock(item); 
       }); 

      } 
     }; 
    } 
]); 

Пример: http://plnkr.co/edit/ZbcNgfl6xL2QDDqL9cKc?p=preview

+2

Это, кажется, более профессиональный способ реализовать эту функцию (чем таймауты). В принципе, такая логика должна быть помещена внутри директивы. Есть одна заметка об этом: вы должны подумать о переименовании 'ngModel' в нечто другое, потому что текущая реализация предполагает, что она требует' ngModel' и предоставляет дополнительные функции 'ngModel' (что неверно). – rzelek

+0

не работает – kabrice

+0

@kabrice, не знаете, какую проблему вы испытываете, но если вы посмотрите на предоставленный мной пример, он отлично работает. – iH8

1

, как вы знаете, заявления выполнить асинхронно, если нет тайм-аута $ («предварительно код») будет пустым, поскольку DOM еще не оказаны. использовать $ timeout вместо setTimeout для того же самого.

+0

Не могли бы вы уточнить? – manetsus

+0

Операторы не выполняются асинхронно, они выполняются по порядку. Проблема в том, что изменение '$ scope.myHTML' в контроллере не изменяет его в представлении до следующего цикла дайджест. Но вы правы, что '$ timeout()' может использоваться для решения проблемы. –

4

Итак, вот что происходит:

  1. Вы обновить $scope.myHTML Значение
  2. Вы запускаете ваш Jquery each() петли
  3. В digest cycle работает и ваш шаблон обновляются

Обратите внимание, что цикл дайджеста работает после вашего цикла JQuery each() - или, точнее, после того, как ваш $http функция обратного вызова завершена.

Это означает, что значение $scope.myHTML в вашем контроллере не применяется к директиве ng-bind-html до тех пор, пока ваша петля не закончится.

Чтобы преодолеть это, вы можете использовать функцию Angular's $timeout вместо собственного браузера setTimeout().По умолчанию $timeout вызовет функцию обратного вызова во время следующего цикла дайджеста, что означает, что он будет работать после внесения изменений в $scope.myHTML в директиву ng-bind-html (при условии, что вы обновите $scope.myHTML перед вызовом $timeout()).

Рабочий пример: JSFiddle

+0

извините за более поздний ответ. Теперь я использую '$ timeout', но иногда (примерно 1/10 раз обновляю страницу) код не будет выделен. См. Мое сообщение для обновления –

+0

Я не могу воспроизвести, даже если ответ HTTP занимает 10 секунд. См. Этот вариант моего JSFiddle, в котором вы можете настроить задержку ответа, и он по-прежнему будет запускать функцию таймаута после этого: https://jsfiddle.net/sscovil/qaasL9nx/ - если подсветка не работает в разы , Я вполне уверен, что он не связан с вашим использованием '$ timeout'. –

+0

Тем не менее, вы не должны выполнять манипуляции с DOM в контроллере, поэтому это не лучший метод. Специальная директива была бы более уместной, как показано в ответе iH8 (хотя вы должны прислушаться к замечанию Арека Żelechowski об именовании атрибута 'ngModel'). –