AngularJS $timeout isn't waiting for UI-Router to finish rendering before computing values

Я использую angularJS а также requirejs с помощью angularAMD to wire together a complex application.

One of my states has two simple views like so:

  $stateProvider
    .state("common", {
      url: "/",
      views: {
        "view1": {
          templateUrl: "view1.tpl.html"
          },
        "view2": {
          templateUrl: "view2.tpl.html"
        }
      }
    });

HTML

<div ui-view="view1"></div>
<div ui-view="view2"></div>

View1 has a directive:

  .directive('checkViewOneBoxWidth', function ($timeout) {
    return {
      restrict: 'A',
      link: function (scope, elem, attrs) {
        var linkFunctionAfterDomComplete = function () {
          console.log(elem[0].scrollWidth);
        }
        $timeout(linkFunctionAfterDomComplete, 0);
      }
    }
  })

А также view2 has a stylesheet that applies some styling to the page, including changing the height а также width из view1 контейнер.

Я хочу функцию linkFunctionAfterDomComplete to compute the element's height а также width properties after the DOM has been modified by the stylesheet in view2, so I wrapped the linkFunctionAfterDomComplete функция в $timeout(),

console.log от checkViewOneBoxWidth here is reporting the size of this element, before the styling from the stylesheet in view2 modified the size of this element, despite the fact that we would expect the $timeout to cause the linkFunctionAfterDomComplete function to calculate the size of this element after styling from view2 is applied and the DOM is complete.

Как я могу получить linkFunctionAfterDomComplete to calculate element properties that reflect those which reflect the true state of the element after it had been fully rendered and all styling has been applied?

http://plnkr.co/edit/WjGogh?p=preview

1 ответ

Решение

Вам нужно передать функцию $timeout:

$timeout(function() {
  console.log('timeout: view 1 linked')
}, 0);

Или же:

var fn = function () {
  console.log('timeout: view 1 linked');
};

$timeout(fn, 0);

Следующие:

$timeout(console.log('timeout: view 1 linked'), 0);

Выполнит console.log мгновенно затем передать возвращаемое значение (undefined) в качестве первого аргумента $timeout,

Демонстрация: http://plnkr.co/edit/zWgoJihcMH693fWfUp09?p=preview

Не уверен, что у вас есть такая же проблема в вашем реальном приложении, но я решил, что я все равно должен это опубликовать.


Новый ответ на основе редактирования

Проблема в том, что ваш элемент ссылки находится в шаблоне представления, а не в index.html.

Если вы переместите его в index.html, он будет работать так, как вы ожидаете (и вам не нужно $timeout в этом случае, если ваше реальное приложение не добавляет пользовательский HTML из директивы):

Демоверсия: http://plnkr.co/edit/m3sriF2YYH5T8y42R5Lr?p=preview

Если вы сохраняете ссылку в шаблоне представления и сохраняете время ожидания, это в основном то, что происходит:

  1. Angular запустит функцию компиляции, чтобы подготовить все привязки и представления.
  2. HTML из представлений будет вставлен в DOM, директивы будут выполнены и console.log будут добавлены в очередь времени ожидания.
  3. Элемент ссылки теперь вставлен в DOM, и браузер начнет извлекать CSS. console.log в очереди ожидания будет выполняться.

Обратите внимание, что выборка CSS является асинхронной и console.log по истечении времени ожидания очередь будет выполняться до завершения извлечения и анализа CSS.

Также обратите внимание, что вы можете увидеть различное поведение в разных браузерах.

Есть решения, но они могут стать очень грязными.

Чтобы узнать больше об этом:

Когда действительно загружается таблица стилей?

Я бы порекомендовал просто переместить ссылку на index.html.

Другие вопросы по тегам