Передача $scope имеет задержку

Я создаю угловую всплывающую систему для нескольких целей. Это работает так, что у меня есть директива под названием bitPopup какие три переменные передаются (type, action а также data) как показано ниже:

index.html

<bit-popup type="popup.type" action="popup.action" data="popup.data"></bit-popup>

popup.js

app.directive('bitPopup', function () {
  return {
    restrict: 'E',
    template: html,
    scope: {
      type: '=',
      action: '=',
      data: '='
    },
    [***]
  }
}

Затем всплывающий контроллер загружает другую директиву в зависимости от типа:

popup.html (приведенный выше HTML-шаблон)

<div class="pop-up" ng-class="{visible: visible}" ng-switch="type">
  <bit-false-positive-popup ng-switch-when="falsePositive" type="type" action="action" data="data"></bit-false-positive-popup>
</div>

false_positives.js (содержащий bitFalsePositivePopup директива)

[...]
scope: {
  type: '=',
  action: '=',
  data: '='
}
[...]

А затем HTML-шаблон для bitFalsePositivePopup Директива отображает некоторые свойства из data,

Теперь способ, которым я запускаю всплывающее окно, работает так:

  1. Из шаблона внутри директивы, содержащей bitPopup директива я изменю $scope.popup "s type, action а также data,
  2. я сделаю $scope.$broadcast('showPopup');
  3. bitPopup директива будет реагировать из-за $scope.$on('showPopup', [...]}); и делает всплывающее окно видимым.

Теперь эта действительно странная вещь происходит, когда она работает с первой попытки (всплывающее окно открывается с правильным data информация), но после первой попытки отобразится data с предыдущей попытки.

Что еще более странно, так это то, что я попытался записать информацию с первой попытки, и я обнаружил, что:

  • $scope.popup в index.html непосредственно перед вызовом $scope.$broadcast('showPopup'); отображает правильную информацию.
  • $scope.data на bitPopup директивные дисплеи null
  • $scope.data на bitFalsePositivePopup Директива отображает правильную информацию.

Со второй попытки:

  • $scope.popup на index.html снова правильно.
  • $scope.data на bitPopup Директива отображает информацию с предыдущей попытки
  • То же самое относится и к bitFalsePositivePopup директивы.

Еще одна странная вещь в том, что когда я использую $scope.$apply() он работает правильно, только он отображает $apply already in progress ошибка. Я знаю, что не должен использовать $scope.$apply() в этом случае, потому что это все угловые события. Но как это возможно, что пройденный объем всегда на шаг позади?

Я делаю что-то не так с самого начала?

РЕДАКТИРОВАТЬ:

Из-за ответа amahfouz я решил опубликовать еще немного кода для пояснения. Я упустил некоторые неважные детали для более ясного прочтения.

index.html

<div class="falsePositives" ng-controller="falsePositives">
  <i class="fa fa-minus color-red" ng-click="triggerPopup('falsePositive', 'delete', {detection: getDetection(row.detection, row.source), source: row.source, triggers: row.triggers, hash: row.hash, date: row.date})"></i>
  <i class="fa fa-pencil" ng-click="triggerPopup('falsePositive', 'edit', {detection: getDetection(row.detection, row.source), source: row.source, triggers: row.triggers, hash: row.hash, date: row.date})"></i>

  <bit-popup type="popup.type" action="popup.action" data="popup.data"></bit-popup>
</div>

index.js

var app = require('ui/modules').get('apps/falsePositives');

app.controller('falsePositives', function ($scope, $http, keyTools, bitbrainTools, stringTools) {
  function init() {
    $scope.getDetection = getDetection;

    $scope.popup = {
      type: null,
      action: null,
      data: null
    };
  }

  function getDetection(hash, source) {
    return {
      'ids': 'BitSensor/HTTP/CSRF',
      'name': 'CSRF Detection',
      'description': 'Cross domain POST, usually CSRF attack',
      'type': [
        'csrf'
      ],
      'severity': 1,
      'certainty': 1,
      'successful': false,
      'input': ['s'],
      'errors': []
    };
  }

  $scope.triggerPopup = function (type, action, data) {
    $scope.popup = {
      type: angular.copy(type),
      action: angular.copy(action),
      data: angular.copy(data)
    };

    test();

    $scope.$broadcast('showPopup');
  };

  function test() {
    console.log('$scope.popup: ', $scope.popup);
  }
}

popup.html

<div class="pop-up-back" ng-click="hidePopup()" ng-class="{visible: visible}"></div>
<div class="pop-up" ng-class="{visible: visible}" ng-switch="type">
  <bit-false-positive-popup ng-switch-when="falsePositive" type="type" action="action" data="data"></bit-false-positive-popup>
</div>

popup.js

var app = require('ui/modules').get('apps/bitsensor/popup');

app.directive('bitPopup', function () {
  return {
    restrict: 'E',
    template: html,
    scope: {
      type: '=',
      action: '=',
      data: '='
    },
    controller: function ($scope) {
      $scope.visible = false;

      $scope.$on('showPopup', function () {
        console.log('$scope.data: ', $scope.data);
        $scope.visible = true;
      });

      $scope.$on('hidePopup', function () {
        hidePopup();
      });

      function hidePopup() {
        $scope.visible = false;
      }

      $scope.hidePopup = hidePopup;
    }
  };
});

false_positives.js

var app = require('ui/modules').get('apps/bitsensor/falsePositives');

app.directive('bitFalsePositivePopup', function () {
  return {
    restrict: 'E',
    template: html,
    scope: {
      type: '=',
      action: '=',
      data: '='
    },
    controller: function ($scope, objectTools, bitbrainTools, keyTools) {

      function init() {
        console.log('$scope.data @ fp: ', $scope.data);
      }

      function hidePopup() {
        $scope.data = null;
        $scope.$emit('hidePopup');
      }

      $scope.$on('showPopup', function () {
        init();
      });

      init();

      $scope.hidePopup = hidePopup;
    }
  }
}

2 ответа

Без остальной части кода я могу только догадываться: вам нужно либо использовать обещание при отображении всплывающего окна, либо использовать службу $apply, чтобы внести изменения в видимость всплывающего окна.

Окружите ваше событие трансляции в $timeout как:

$timeout(function() {
  $broadcast('eventName');
});

Он будет ждать обновления $scope и затем вызовет событие.

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