6

我是 javascript/angularjs 的新手。当鼠标悬停在某些元素上时,我想显示一个引导弹出窗口。

我为此创建了一个指令

(function(angular, app) {
  app.directive('popOver',["$window","$http",function($window,$http){
    return function(scope,elem,attrs){
      elem.on('mouseover',function(){
        console.log('mouseover');
        var data = scope.$apply(attrs.popOver);
        console.log('in directive again');
        console.log(data);
      });
    };
  }]);
})(angular, app);

指令的值是一个函数

<span class="asdf" pop-over="getVCard(id)">name</span>

函数 vcard(id) 在我的 angularjs 控制器中定义。它检查数据是否已经存在于本地存储中,如果存在,则返回数据。否则它会执行 $http get 请求并将数据存储在本地存储中。

$scope.getVCard = function(id){

  var vcardKey = vcardKeyPrefix+id;

  var vCardFromLS = localStorageService.get(vCardKey);
  if(vCardFromLS){
    return localStorageService.get(vCardKey);
  }

  $http.get(app.common.vcardUrl(id)).
    success(function(data){
      localStorageService.set(vCardKey,data);
    }).
    error(function(error){
      F1.common.error(data,function(){});
    });

    return localStorageService.get(vCardKey);
};

由于 $http 返回承诺,我在指令中得到了 undefined 的值。如何确保函数getVCard同步返回?

我在谷歌搜索后阅读了一些结果。但建议的想法是使用回调。但我不确定回调如何使这个同步。任何帮助表示赞赏。

更新 1(响应 Foo L 的评论)我计划在多个地方使用相同的指令。vcards和产品信息等的弹出窗口。唯一不同的是 pop-over 指令的参数。这样,指令就会为只显示弹出窗口而烦恼。获取数据的位置将在传递给指令的单独函数中

4

1 回答 1

10

你不能强迫$http.get()同步。由于$http.get()不可避免地是异步的,因此您只能返回一个值的承诺,而不是值本身。

并且因为您需要在$http.get()被调用时执行此操作,所以您还必须在其他条件下返回一个承诺 - 何时vCardFromLS从本地存储中成功检索。这确保返回到任何调用的对象$scope.getVCard()都有一个.then()方法,即它是一个承诺,无论是否$http.get()被调用。

所以代码应该是这样的:

$scope.getVCard = function(id) {
    var vcardKey = vcardKeyPrefix + id;
    var vCardFromLS = localStorageService.get(vCardKey);
    var dfrd = $q.defer();
    if(vCardFromLS) {
        dfrd.resolve(localStorageService.get(vCardKey));
    }
    else {
        $http.get(app.common.vcardUrl(id)).success(function(data) {
            localStorageService.add(vCardKey, data);//.add() rather than .set() ?
            dfrd.resolve(data);
        }).error(function(error) {
            F1.common.error(data, function() {
                dfrd.reject('$http.get(app.common.vcardUrl(id)) failed');
            });
        });
    }
    return dfrd.promise;
};

现在您需要确保对 的响应$scope.getVCard()得到适当处理,例如:

$scope.getVCard(id).then(function(data) {
    //success - do whatever is required with data
}, function(reason) {
    //failure - log and/or display `reason` as an error message
})

编辑:

我的“……你还必须在其他条件下返回一个承诺……”是夸大其词。

我应该说,“......你可以,为了简单起见,在其他条件下返回一个承诺......”。

另一种可能性是根据返回的 Promise 或其他类型的对象/值进行分支。但是,这很混乱,通常会导致一些代码重复。

于 2013-06-28T13:46:00.903 回答