【问题标题】:$scope passing has a Delay$scope 传递有延迟
【发布时间】:2016-04-04 19:13:48
【问题描述】:

我正在为多种目的构建一个 Angular 弹出系统。它的工作方式是我有一个名为bitPopup 的指令,其中三个变量被传递给(typeactiondata),如下所示:

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: '='
}
[...]

然后,bitFalsePositivePopup 指令的 html 模板会显示来自 data 的一些属性。

现在我触发弹出窗口的方式如下:

  1. 从包含bitPopup 指令的指令中的模板,我将更改$scope.popuptypeactiondata
  2. 我会做$scope.$broadcast('showPopup');
  3. bitPopup 指令会因为$scope.$on('showPopup', [...]}); 而做出反应,并使弹出窗口可见。

现在这个非常奇怪的事情发生在第一次尝试时(弹出窗口以正确的data 信息打开),但在第一次尝试后它将显示上一次尝试的data

现在更奇怪的是,我尝试在第一次尝试时记录信息,结果发现:

  • index.html 上的$scope.popup 就在调用$scope.$broadcast('showPopup'); 之前会显示正确的信息。
  • $scope.databitPopup 指令处显示null
  • bitFalsePositivePopup 指令中的 $scope.data 显示正确的信息。

第二次尝试:

  • index.html 处的$scope.popup 再次正确。
  • bitPopup 指令中的 $scope.data 显示上一次尝试的信息
  • bitFalsePositivePopup 指令也是如此。

另一个奇怪的事情是,当我使用$scope.$apply() 时,它确实可以正常工作,只是它显示$apply already in progress 错误。我知道在这种情况下我不应该使用 $scope.$apply(),因为这都是 Angular 事件。但是传递的范围怎么可能总是落后一步呢?

我一开始是不是做错了什么?

编辑:

由于amahfouz's answer,我决定发布更多代码以进行澄清。为了更清晰的阅读,我省略了一些不重要的细节。

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;
    }
  }
}

【问题讨论】:

    标签: javascript angularjs angularjs-directive angularjs-scope angular-broadcast


    【解决方案1】:

    没有其余代码,我只能猜测:您要么需要在显示弹出窗口时使用 Promise,要么使用 $apply 服务来更改弹出窗口的可见性。

    【讨论】:

    • 感谢您的回复!我在原始帖子中添加了更多代码,也许这有助于澄清问题的原因。
    • 我查看了Angular's promise 的文档,但是将弹出窗口设置为异步服务感觉很奇怪。同样如原帖中所述,使用 $apply 会给我$apply already in progress 错误。
    • 我知道,但是我在下拉服务中遇到了类似的问题,并且承诺解决了它。总之,值得一试。
    • 遗憾的是,使用 promise 并没有为我做这件事。还有其他建议吗?
    • 让我仔细看看,但如果发布一个 plunk 来隔离问题会有所帮助。
    【解决方案2】:

    在 $timeout 中围绕您的 $broadcast 事件,如下所示:

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

    它会等待 $scope 更新然后触发事件。

    【讨论】:

      猜你喜欢
      • 2022-12-14
      • 1970-01-01
      • 2019-07-18
      • 1970-01-01
      • 2012-08-09
      • 2014-09-27
      • 2011-08-03
      • 2011-03-27
      相关资源
      最近更新 更多