如何使用ng-click调用多个函数/链式调用

时间:2014-12-30 21:44:42

标签: javascript html angularjs function angularjs-controller

嗨,我有一个按钮可以触发两个这样的功能。有没有办法让updateDetails只在changeColor完成后才能运行? updateDetails目前正在使用旧颜色拉旧配置,而不是更改颜色。

ng-click="changeColor(color.code); updateDetails()"

以下是观点:

<div ng-controller="ColorsCtrl">
  <div ng-controller="HeaderCtrl">
    <div byo-header>
    </div>

    <div ng-repeat="color in colors" class="row">
      <div class="small-12 columns">
            <div ng-controller="ButtonsController">
                <div class="button-group">
              {{ isSelected(color.code) }}
                <button ng-click="changeColor(color.code); updateDetails()" type="radio" class="button" ng-model="selectedColor" btn-radio="color.code">{{color.name}}</button>
            </div>
            </div>  
      </div>
    </div>
    <br/>
    <br/>
    <div class="row">
        <div class="small-4 small-offset-4 columns">
        <!-- Proceed to packages if available -->
            <a ng-if="hasPackage" href="#/packages/{{modelCode}}" class="button">Packages</a>
        <!-- Proceed to options if packages not available -->
        <a ng-if="!hasPackage" href="#/options/{{modelCode}}" class="button">Options</a>
        </div>
    </div>    
  </div>
</div>

这是ColorsCtrl中的changeColor():

$scope.changeColor = function(newColorCode){
        //swap previous selected color with new
        configuratorService.addOption($scope.modelCode, newColorCode, function(configuration){
            $scope.configuration = configuration;               
        });

    }

  }

这是HeaderCtrl中的updateDetails

    $scope.updateDetails = function(){
        $scope.summaryDetails = getSummaryDetails();
    }

2 个答案:

答案 0 :(得分:6)

由于changeColor是异步操作 - 否,您无法内联等待。您必须在回调中调用该函数:

$scope.changeColor = function(newColorCode){
    //swap previous selected color with new
    configuratorService.addOption($scope.modelCode, newColorCode, function(configuration){
        $scope.configuration = configuration;  
        $scope.updateDetails();             
    });
}

如果在其他地方使用此功能而您并不总是想要调用更新,请传递一个标志参数:

$scope.changeColor = function(newColorCode, shouldUpdate){
    //swap previous selected color with new
    configuratorService.addOption($scope.modelCode, newColorCode, function(configuration){
        $scope.configuration = configuration;  
        if (shouldUpdate) $scope.updateDetails();             
    });
}

ng-click="changeColor(color.code, true);"

答案 1 :(得分:4)

从技术上讲,你可以编写内联提供的changeColor返回promise并且你的服务调用必须返回一个promise(与传统的传递回调相比更好)。

首先更改您的服务以返回承诺,例如: -

 function configuratorService($http){
      this.addOption = function(modelCode, colorCode){
          return $http.post("Addoption", {modelCode:modelCode, colorCode:colorCode})
                 .then(function(response){ 
                   //logic to get configuration or whatever
                   return response.data
          });
     }
  }

在ColorsCtrl中:

$scope.changeColor = function(newColorCode){
     //return promise   
    return configuratorService.addOption($scope.modelCode, newColorCode)
         .then( function(configuration){
            $scope.configuration = configuration;     
            /*You could even return the data by doing the following*/          
            //return $scope.configuration = configuration;
        });
    }
 }

在HeaderCtrl中:

$scope.updateDetails = function(){//<-- if you are returning data from changeColor you could even use it here
    $scope.summaryDetails = getSummaryDetails();
}

最后在你看来:

ng-click="changeColor(color.code).then(updateDetails)"

示例演示

angular.module('app', []).controller('HeaderCtrl', function($scope) {
  $scope.updateDetails = function() {
    //check the console
    console.log('UpdateDetails');
    $scope.summaryDetails = "Summary Details after option changeColor";
  }
}).controller('ColorsCtrl', function($scope, configuratorService) {
  $scope.changeColor = function(newColorCode) {
    //swap previous selected color with new
    return configuratorService.addOption().then(function(configuration) {
      //check the console
      console.log('Option Added');
      $scope.configuration = configuration;
    });
  }
}).service('configuratorService', function($timeout) {
  this.addOption = function() {
    //Justa proxy for an ansyn operation and return call
    return $timeout(function() {
      return "Color Updated"
    }, 1000);
  }
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app">

  <div ng-controller="ColorsCtrl">
    <div ng-controller="HeaderCtrl">

      <button ng-click="changeColor().then(updateDetails)">Update</button>
      {{summaryDetails}}
    </div>
  </div>

还有许多其他选择和更好的方法。在TymeJV答案中提供的一个问题是,你的控制器彼此紧密耦合并可能影响可重用性,你需要做额外的模拟,以便在测试{{1}时添加不存在的方法updateDetails }}。

虽然我的回答中的这种方法有其自身的问题,因为现在你的视图需要知道某些东西(该方法返回了promise),它不应该。还有其他方法可以更好地处理这种情况:一种简单的方法是使用事件或发布/发布模式,通知其他控制器这里发生的事情做你想做的事情。这种设计将使其更松散地耦合,更可重复使用和可测试。

您可以根据 {{3 }} ,要执行此任务,您可以创建$broadcast

通过简单的事件你可以这样做: -

在ColorsCtrl中:

ColorsCtrl

在HeaderCtrl中订阅一个事件并注册updateDetails方法:

    $scope.changeColor = function(newColorCode){
        configuratorService.addOption($scope.modelCode, newColorCode, function(configuration){
            $scope.configuration = configuration;
            //BroadCast an event, this will notify any child scopes that has subscribed to this event.   
            $scope.$broadCast("Configuration_Udpated");                           
          });
       }
   }

附注: - 尝试使用 $emit ,而不是将回调传递给服务。您可以在网上找到很多关于 $on 的文章。