【问题标题】:Callback function inside directive attr defined in different attr在不同的 attr 中定义的指令 attr 内的回调函数
【发布时间】:2013-03-31 14:10:31
【问题描述】:

所以我有这个指令叫做 mySave,差不多就是这个

app.directive('mySave', function($http) {
   return function(scope, element, attrs) {
      element.bind("click", function() {
          $http.post('/save', scope.data).success(returnedData) {
              // callback defined on my utils service here

              // user defined callback here, from my-save-callback perhaps?
          }
      });
   }
});

元素本身看起来像这样

<button my-save my-save-callback="callbackFunctionInController()">save</button>

callbackFunctionInController 现在只是

$scope.callbackFunctionInController = function() {
    alert("callback");
}

当我在 my-save 指令中 console.log() attrs.mySaveCallback 时,它只给了我一个字符串 callbackFunctionInController(),我读到 somewhere 我应该 $parse 这个,它会很好,所以我尝试 @987654329 @ 它给了我一些功能,但几乎不是我正在寻找的功能,它给了我

function (a,b){return m(a,b)} 

我做错了什么?这种方法从一开始就有缺陷吗?

【问题讨论】:

    标签: javascript ajax angularjs angularjs-directive


    【解决方案1】:

    因此,最好的方法似乎是使用 ProLoser 建议的隔离范围

    app.directive('mySave', function($http) {
       return {
          scope: {
            callback: '&mySaveCallback'
          }
          link: function(scope, element, attrs) {
            element.on("click", function() {
                $http.post('/save', scope.$parent.data).success(returnedData) {
                    // callback defined on my utils service here
    
                    scope.callback(); // fires alert
                }
            });
          }
       }
    });
    

    要将参数传递回控制器,请执行此操作

    [11:28] <revolunet> you have to send named parameters 
    [11:28] <revolunet> eg my-attr="callback(a, b)" 
    [11:29] <revolunet> in the directive: scope.callback({a:xxx, b:yyy})
    

    【讨论】:

    • 问题是为什么要向控制器发送值,可以轻松创建双向绑定
    • 如果你想将值发送回控制器,你必须发送一个带有命名参数的对象,例如:{result: returnedData}
    • @ArunPJohny,不使用双向绑定的原因之一:有时您不想为回调函数需要的值添加额外的范围属性。
    • 这是在哪里记录的?
    • 我仍然认为您应该使用 ng-click,因为将保存/业务逻辑放入指令中是不好的 juju
    【解决方案2】:

    有很多方法可以处理您正在做的事情。您应该知道的第一件事是$http.post() 将在模板引擎渲染出该DOM 元素后立即被调用,仅此而已。如果你把它放在一个重复中,调用将针对中继器中的每个新项目完成,所以我猜这绝对不是你想要的。如果它,那么您确实没有正确设计事物,因为仅 DOM 的存在不应该要求后端查询。

    不管怎样,直接回答你的问题;如果您在 $parse 上阅读虽然很糟糕的文档,它会返回一个评估表达式。当您通过传递要评估的范围来执行此函数时,将返回您传递的范围内该表达式的当前状态,这意味着您的函数将被执行。

    var expression = $parse(attrs.mySave);
    results = expression($scope); // call on demand when needed
    expression.assign($scope, 'newValu'); // the major reason to leverage $parse, setting vals
    

    是的,一开始有点令人困惑,但您必须了解,$scope 在异步应用程序中会不断变化,这完全取决于您希望何时确定该值,而不仅仅是如何确定。 $parse 更适用于引用您希望能够为其赋值而不只是从中读取的模型。

    当然,您可能想阅读有关创建隔离作用域或如何$eval() 表达式的内容。

    $scope.$eval(attrs.mySave);
    

    【讨论】:

    • 哎呀,我实际上忘记将 element.bind("click") 放入帖子中,同时剥离我不必要的混乱代码。固定
    • 好的,所以我应该首先使用隔离范围。但是,如果我现在仍然想使用$parse,我将如何执行从 $parse 返回的函数?我试过callback.apply();callback.call();callback();,其中callback$parse(attrs.mySaveCallback),他们都没有解雇我的alert()
    • @foxx,在链接函数中使用如下解析:var cb = $parse(attrs.mySaveCallback);,然后在点击回调中:cb(scope);Fiddle
    【解决方案3】:

    您可以使用.$eval 在给定范围内执行语句

    app.directive('mySave', function($http) {
       return function(scope, element, attrs) {
          $http.post('/save', scope.data).success(returnedData) {
              // callback defined on my utils service here
    
              // user defined callback here, from my-save-callback perhaps?
              scope.$eval(attrs.mySaveCallback)
          }
       }
    });
    

    TD:Demo

    如果你想在指令和控制器之间共享数据,你可以使用双向绑定

    app.controller('AppController', function ($scope) {
       $scope.callbackFunctionInController = function() {
          console.log('do something')
       };
    
       $scope.$watch('somedata', function(data) {
          console.log('controller', data);
       }, true);
    });
    
    app.directive('mySave', function($http, $parse) {
       return {
         scope: {
           data: '=mySaveData',
           callback: '&mySaveCallback' //the callback
         },
         link: function(scope, element, attrs) {
           $http.get('data.json').success(function(data) {
             console.log('data', data);
             scope.data = data;
             scope.callback(); //calling callback, this may not be required
           });
         }
       };
    });
    

    演示:Fiddle

    【讨论】:

    • 这确实有效,但这是正确的做法,还是@ProLoser 建议的隔离范围仍然是最好的?以及如何将returnedData 传递回mySaveCallback?
    • @foxx,我想你首先需要确定what kind of scope your directive needs。然后从那里,您可以确定如何将数据和回调传递给您的指令。
    • 第一种方式调用时如何传递参数?即 scope.$eval(attrs.mySaveCallback(parameters)),我尝试这样做但得到 attrs.mySaveCallback 不是函数
    【解决方案4】:
    scope: {
        callback: '&mySaveCallback'
    }
    

    显式设置范围可能是一个很好的解决方案,但如果您希望访问原始范围的其他部分,则不能,因为您刚刚覆盖了它。出于某种原因,我也需要到达范围的其他部分,所以我使用了与 ng-click 相同的实现。

    我的指令在 HTML 中的使用:

    &lt;div my-data-table my-source="dataSource" refresh="refresh(data)"&gt;

    在指令内部(不明确设置范围):

    var refreshHandler = $parse(attrs.refresh);
        scope.$apply(function () {
        refreshHandler( {data : conditions}, scope, { $event: event });
    });
    

    有了这个我可以调用控制器中的函数并传递参数给它。

    在控制器中:

    $scope.refresh= function(data){
        console.log(data);
    }
    

    它会正确打印出条件。

    【讨论】:

      【解决方案5】:

      这对我有用

      在视图脚本内部

      <tag mycallbackattrib="scopemethod">
      

      指令内部

      $scope[attrs.mycallbackattrib](params....);
      

      它被正确调用并传递了参数,但可能不是最好的“角度方式”工作。

      【讨论】:

        【解决方案6】:

        您应该使用ng-click 而不是创建自己的指令。

        【讨论】:

        • 在一些简单的情况下工作,而不是如果你想禁用按钮和东西,显示一些动画,在多个地方使用相同的指令等等。我不太记得我为什么想要不过,这已经有一段时间了。
        • 您可以使用 ng-click 完成所有这些操作。它做动画,你可以禁用按钮。一切。在您的版本中绝对没有 ng-click 不具备的功能。
        • 不知道为什么我被否决了。将业务逻辑(例如保存)放入完全与视图相关的指令中是不好的做法。你可以做一个 $scope.save() 来做你想做的一切。
        【解决方案7】:
        app.directive('mySave', function($http, $parse) {
           return {
             scope: {
               data: '=mySaveData',
               callback: '&' //the callback
             },
             link: function(scope, element, attrs) {
               $http.get('data.json').success(function(data) {
                 console.log('data', data);
                 if (scope.callback()) scope.callback().apply(data);
               });
             }
           };
        });
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2016-12-29
          • 2023-03-11
          • 1970-01-01
          • 2016-05-22
          • 2017-10-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多