Как правильно пересчитать что-то на основе пользовательского интерфейса после дайджеста AngularJS? - PullRequest
0 голосов
/ 22 декабря 2018

Это кажется таким простым и все же чрезвычайно сложным.

У меня есть компонент типа вкладок навигации, и для поддержки ситуации, когда для экрана слишком много вкладок, у меня есть меню переполнения ...разметка выглядит примерно так:

<ul class="tabs-container">
    <li ng-repeat="feed in $ctrl.visibleFeeds track by feed.Id" ng-class="{active: feed.Id == activeTabId}">
        <a ng-href="#" ng-if="!feed.edit">
            <span ng-click="feed.edit = true">{{feed.Name}}</span>
        </a>
    </li>
    <li uib-dropdown>
        <a ng-href="#" uib-dropdown-toggle role="button">
            <svg>--- menu icon ---</svg>
        </a>
        <ul class="dropdown-menu" uib-dropdown-menu role="menu">
            <li ng-repeat="feed in $ctrl.hiddenFeeds track by feed.Id">
                <a href="#">{{feed.Name}}</a>
            </li>
        </ul>
    </li>
    <li>
        <a ng-href="#" ng-click="$ctrl.addNewFeed()">
            <svg> --- add icon --- </svg>
        </a>
    </li>
</ul>

Надеюсь, вы можете заметить, что у меня есть два связанных массива, один для видимых каналов (вкладок) и один для скрытых каналов.

Теперь для перемещения каналовиз одной коллекции в другую мне нужно рассчитать, что слишком велико для экрана, поэтому у меня есть функция для вычисления того, что видно.Псевдокод этой функции выглядит примерно так:

  1. Сделать visibleTabs всей коллекцией.
  2. Подсчитать, сколько вкладок уместится.
  3. Переместить оставшиеся вкладки в hiddenTabscollection.

Проблема в том, что я не могу найти «правильный» способ ожидания завершения цикла дайджеста, поэтому я могу измерить вкладки.Я не могу использовать $ scope. $ Apply по двум причинам ... 1) возможно, он уже находится в цикле дайджеста, поэтому я могу получить ошибку, и 2) я пытаюсь избежать $ scope, чтобы помочь в дальнейшей миграциидо углового 2 +

Я пробовал несколько разных методов, но большинство из них вернулось к $ timeout.Как я понял, если вы используете $ timeout, он должен запускать все, что вы положили внутрь (после любого цикла дайджеста, который уже может быть запущен), а затем запускать $ apply после вашей функции, а затем продолжать любые обещанные вызовы, которые у вас есть.Так что должно быть что-то вроде этого (согласно моему пониманию) ...

$timeout(() => {
    // this get's executed after current digest cycle if already running.
    this.someBinding = newValue;
}).then(() => {
    // this should execute after the original timeout func, and after a $scope.$apply() call has been made inbetween. 
    measureTheScreen();
})

Проблема, которую я имею, заключается в том, что функция тайм-аута, похоже, не работает так.Часть «then» вызывается до $ scope. $ Apply () Таким образом, элементы еще предстоит визуализировать в пользовательском интерфейсе.

PS I am , пытаясь выяснить болееAngularjs способ привязать это к viewmodel, но так как это требует от браузера рендеринга реальных элементов, я нахожу борьбу, чтобы найти способ, который действительно немного проще, чем этот.

1 Ответ

0 голосов
/ 15 января 2019

То, что происходит в вашем изменении тайм-аута:

  1. Тайм-аут ожидает окончания текущего дайджеста
  2. После выполнения текущего дайджеста this.someBinding = value новый дайджест ставится в очередьup.
  3. Затем запускается немедленно, и вызывается measureTheScreen перед выполнением дайджеста, поставленного в очередь выше.
  4. Дайджест из (2) происходит.

Я сталкивался с этой проблемой несколько раз, и я тоже хотел бы, чтобы был лучший способ, но я считаю, что это всего лишь ограничение AngularJS.

Чтобы обойти это в прошлом, требуется секунда$timeout, поэтому ТОГДА происходит только после того, как дайджест, запущенный с первого $timeout, завершается ...

В вашем случае это будет

//1. waits for a digest to occur
$timeout(() => {
    //2. Digest 1 occurs, code is executed
    this.someBinding = newValue;
    //3. New digest is queued up to occur
}).then(() => {
    //4. waits for digest 2 to occur
    return $timeout(() => {
        //5. Digest 2 occurs, and now I can safely execute code that depends on html being rendered in timeout 1
        measureTheScreen();
    }
});

Таким образом, они указывают, чтодаже если ваш $ timeout действительно вызывает $ scope. $ apply, вам все равно нужно дождаться, пока этот новый дайджест пройдет, используя другой $ timeout.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...