Angularjs 1.5 component modal with callback functi

2020-04-26 13:15发布

问题:

In IE 11, I have an Angularjs 1.5 modal component as below. The modal opens and on render event it calls a function outside of the angular app with a callback function contained in this component. This outside function initiates a install process which kicks off an embedded object as shown below and this then periodically calls the callback function.

The issue I am having is the binding is not being updated in the template on each callback function called from the embedded object call. The console.log is executed and i can see the message in the console. The binding is initially updated with 'starting process' so binding is correct

<span ng-bind="$ctrl.messages[$ctrl.messages.length - 1]"></span>

I tried calling scope.apply as below but nothing happens. Only when the initiateprocess is completed, the binding is then updated with the last message shown from the final callback call. So the initiateprocess function is blocking the binding but no blocking the console.log's

is this the correct way to handle multiple callbacks and updating bindings

  angular.module('components')
  .component('testModal', {
    bindings:{
      modalInstance: '<',
      resolve: '=',
      dismiss: '&',
      close: '&'
    },
    controller: TestController,
    templateUrl: 'scripts/components/TestModal.html'
});

TestController.$inject = ['$scope'];
function TestController($scope) {
  var ctrl = this;

  ctrl.$onInit = function(){
    ctrl.messages = [];
    ctrl.messages.push('starting process');
  };

  ctrl.modalInstance.rendered.then(function(){
    CallVanillaJSFunction(callback); 
  });

  function callback(message){
    ctrl.messages.push(message);
    console.log(ctrl.messages[ctrl.messages.length - 1]);
    CheckScopeBeforeApply();
  }

  function CheckScopeBeforeApply() {
    if(!$scope.$$phase) {
      $scope.$apply();
      console.log('scope applied');
    }
  };

}

Vanilla Function

var globalCallback;

function CallVanillaJSFunction(callback){
    globalCallback = callback;
    var complete = initiateprocess();
    globalCallback(complete);
}

Embedded Object

<OBJECT ID="testObj" CLASS......
<SCRIPT language=javascript for=testObj event="OnEvent(message);">
      if(navigator.userAgent.indexOf("Trident") != -1)
      {
         globalCallback(message);
      }
    </SCRIPT>

This question has been marked as duplicate but having looked at the duplicates I don't think it is the same. The global callback function can be called multiple times and the angular application does not know how many times it will be called.

回答1:

Use the $timeout service to force a browser tick:

  function callback(message){
    $timeout(function() {
       ctrl.messages.push(message);
       console.log(ctrl.messages[ctrl.messages.length - 1]);
    });
    ̶C̶h̶e̶c̶k̶S̶c̶o̶p̶e̶B̶e̶f̶o̶r̶e̶A̶p̶p̶l̶y̶(̶)̶;̶
  }

If the updates to the message occur all in the same browser tick, only the last update will be rendered. The $timeout service does both a framework digest cycle and a browser rendering cycle.

For more information, see AngularJS $timeout Service API Reference