0

我为以下小部件属性创建了一个自定义指令:

<div widget></div>

基本上,该指令只是创建一些模板代码并将 html 放在小部件标签中。这是指令:

skdApp.directive("widget", function() {
  return {
    restrict: 'A',
    template: htmlTemplate,
    link: function($scope, element, attri) {
      /*
       * setup event handler and twitter bootstrap components here
       */
    }
  }

htmlTemplate 是基本的 html 代码,它也使用自定义指令(例如<seal>标签):

var htmlTemplate = '<div ng-controller="OfferCtrl">' +
                     '<div class="container">' +
                       <seal></seal>' +
                       '...'+
                     '</div>' +
                   '</div>';

在我的控制器中,我首先请求在 <div widget> 中显示一些数据。我有一个“提供”服务,它封装了从服务器请求数据的所有逻辑。我使用的方法称为 Offer.query()。

skdApp.controller('OfferCtrl', function OfferCtrl ($scope, Offer) {
  var o = Offer.query({id: 1}, function (response) {
    $scope.offer = response;
  });
});

在响应处理程序中,我将结果绑定到范围。我现在面临的问题是指令也请求数据,但这个请求取决于从 Offer.query() 接收到的数据。即来自 Offer.query() 的响应返回一个 ID(我们称之为 myID),这是 seal 指令请求更多数据所必需的。因此,我只是将我所有的逻辑都放在了回调 Offer.query 回调函数中。这似乎不是最好的方法。

所以我想把这部分移到<seal>指令的链接函数中:

skdApp.directive("seal", function() {

  var sealHTML = '<div>{{offer.data.foobar}}</div>';

  return {
    restrict: 'E',
    template: sealHTML,
    link: function($scope, element, attrs) {

      $scope.$watch('offer.myId', function (newValue, oldValue) {

       if (typeof newValue !== "undefined") {

         /* request more data with myId 
          * and bind the result to offer.data
          */    

       }

      });

    }
});

这种方法是“角度”兼容的还是有其他更好的方法(在结构方面)可以在角度上做到这一点?

4

2 回答 2

0

您可以在 child 指令中查看 offer.myId,因为 parent(widget) 和 child(seal) 共享相同的范围。默认情况下,指令不会创建新范围。

我认为您广播自定义事件以通知子指令并在需要时隔离范围以避免范围破坏。

http://docs.angularjs.org/api/ng.$ro​​otScope.Scope

于 2013-01-26T21:27:11.800 回答
0

我将采用这种 Reverse-Jeopardy 风格(以答案形式提出的问题)。我一直在考虑解决我最近看到的这个问题。它显然有效,但它有一些行为特征,我最初很想将其标记为“错误”。经过深入思考,我意识到这些特征在某些非常具体的场景中可能是可取的。

我当然不会将其作为每次遇到需要绑定异步返回的数据时使用的通用解决方案。我提出它是为了强调这样一个事实,即这种情况提出的问题有多个可能的答案。在某些情况下,可能存在真正的业务逻辑需要阻止 UI 呈现,直到服务调用返回。在其他情况下,保持 UI 活跃并响应不相关的工作可能更合适。

例如,在订单处理系统的情况下,我可能非常希望阻止客户端线程与视图元素交互,直到知道销售交易的结果。对于具有服务器端公式计算的基于 Web 的电子表格应用程序,情况并非如此。

我认为满足这种需求的异步和同步模式可以共存是一件很棒的事情。也就是说,返回一个 Promise 对象并不会强制客户端使用它,就像将返回值放在范围内会强制客户端观察它们一样。

以下演示了一种与先前探索的异步样式同步处理此要求的方法:watch( )

var servicesModule = servicesModule || angular.module('myModule', []);

servicesModule.factory('thingClient', 
    ['$http', '$q', function( $http, $q ) {
        return new ThingClient($http, $q);
    }]
);

function ThingClient($http, $q) {
    function callService(scopeObject) {
        var defer = $q.defer();
        var promise = defer.promise;
        $http({
            method: 'POST',
            url: 'http://at/some/url/',
            data: { x: 'y', y: 'z', z: 'x', one: 1, two: 2, three: 3},
            cache: false
        }, function(data) {
            scopeObject.data = data;
            defer.resolve(data);
        }, function() {
            scopeObject.data = null;
            defer.resolve(null)
        });

        return promise;
    }
}

客户端服务.js

function ConsumingController( $scope, thingClient ) {
    // Be careful to use an object (so you have data wrapped such that it
    // is eligible for prototypical inheritance and call by reference without
    // passing the scope itself).  Leave the 'data' element undefined so you
    // can trigger the transition from undefined -> null in the failure case
    // and not just the on-success case. 
    $scope.dto = { data: undefined };
    var promise = thingClient.callService(scope.dto);

    // Asynchronous strategy
    $scope.$watch('offer.myId', function (newValue, oldValue) {
        if( newValue == null ) {
            // Fail!
        } else {
            // Succeed!
        }
    }

    // Synchronous strategy
    if( promise.then( 
        function(data) { 
            if( data == null ) { 
                // Fail
            } else {
                // Succeed
            }
        }
    }
}

消费控制器.js

于 2013-05-11T03:16:21.320 回答