【问题标题】:AngularJS Two binding in directiveAngularJS指令中的两个绑定
【发布时间】:2016-03-25 19:45:08
【问题描述】:

问题:我有一个控制器,它可以获取一组玩家,并将它们呈现给用户。这些玩家有一组统计数据,用户可以增加或减少这些统计数据,因为一个玩家可以有多个统计数据,我希望它们的行为相同,所以我正在创建一个指令,它有一个数字和 2 个按钮“+”& “-”。当用户单击“+”时,值应该上升,当用户单击“-”时,值应该下降。该指令的目标是使调整模板变得容易并在任何地方反映出来,该指令还试图与统计数据无关,这样它就可以重复用于几个不同的统计数据。用户可以拥有 selectedPlayer,此指令将绑定到此 selectedPlayer 上的统计信息。我遇到的问题是,如果我更改了 selectedPlayer,指令似乎没有用新的 selectedPlayer 更新,或者指令中的新值似乎并没有真正更新所选的播放器。

代码可能有助于更好地解释这一点。

<div class="h3 text-center">{{title}}</div>
<button class="btn btn-lg plusMinus-btn btn-danger" ng-click="statCtrlr.statDown()">-</button>
<span class="stat-val digits md vcenter text-center" style="width: 50px;" ng-cloak>{{statCtrlr.statValue}}</span>
<button class="btn btn-lg plusMinus-btn btn-success" ng-click="statCtrlr.statUp()">+</button>

js(实际上是.ts)文件:

var app = angular.module("stat-val", []);

app.directive("statVal", () => {

    return {
        restrict: 'E',
        templateUrl: 'templates/statValue.html',
        //transclude:true,
        scope: {
            title: "@",
            data: "=" 
            //prop:"="
            //statValue: "=val",
            //statCol: "@col",
            //plrid: "@plrid",
            /*plr:"=plr"*/
        },
        controller: ['$scope', '$http', function ($scope, $http) {
            //$scope.statValue
            var ctrl = this;

            //ctrl.statValue = $scope.data[$scope.prop];
            console.log("$scope", $scope);


            ctrl.statValue = $scope.data;

            console.log('stat-val::$scope', $scope.data, $scope, ctrl.statValue);
            //console.log($scope.$parent.entryCtrlr.selectedPlayer.plrid);


            this.statDown = () => {
                console.log("statDown", ctrl.statValue);
                if (ctrl.statValue > 0) {
                    ctrl.statValue--;

                }
            };

            this.statUp = () => {
                console.log("statUp", ctrl.statValue);
                ctrl.statValue++;

            };
        }],
        controllerAs: 'statCtrlr'
    }
});

它是如何在 html 中调用的

<div class="col-xs-3 no-gutter">
     <stat-val title="FGM" data="entryCtrlr.selectedPlayer.stats.fgm" prop="fgm"
     ></stat-val>
</div>

使用的json数据:

player: [
{
 stats: {
  fgm: 0,
  fga: 0,
  fgm3: 0,
  fga3: 0,
  ftm: 0,
  fta: 0,
  tp: 0,
  blk: 0,
  stl: 0,
  ast: 0,
  min: "",
  oreb: 2,
  dreb: 4,
  treb: 6,
  pf: 0,
  tf: 0,
  to: 0
},

},

更新

控制台转储:

【问题讨论】:

    标签: javascript html angularjs data-binding typescript


    【解决方案1】:

    关键问题隐藏在这里:

    ...
    ctrl.statValue = $scope.data;
    ...
    

    这是发生在控制器构造阶段的语句。 IE。 $scope.data 在那一刻可能为空...所以我们不分配对以后数据的引用...只是分配了一个 NULL(或未定义):

    // these is two way binding - but no could empty $scope.data
    // it is like doing this
    
    ctrl.statValue = null; // no reference
    

    an example在父控制器中加载异步数据(指令外)

      .directive('statVal', function()
      {
        return {
            restrict: 'E',
            templateUrl: 'templates/statValue.html',
            //transclude:true,
            scope: {
                data: "=",
                // ...
            },
            controllerAs: 'statCtrlr',
            controller: ['$scope', '$http', function ($scope, $http) {
                //$scope.statValue
                var ctrl = this;
    
                //ctrl.statValue = $scope.data[$scope.prop];
                console.log("$scope", $scope);
    
                ctrl.statValue = $scope.data;
            }],
        };
      })
    
    .controller("myCtrl", function($scope, $http) {
      $http.get("data.json")
        .then(function(response){
          $scope.data = response.data;
        })
    })
    

    我们如何解决它?最简单的就是使用“.”。在模型名称中,使用Model : { data }

    updated example

    控制器创建模型

    .controller("myCtrl", function($scope, $http) {
      $scope.Model = {};
      $http.get("data.json")
        .then(function(response){
          $scope.Model.data = response.data;
        })
    })
    

    然后传递给指令

    <stat-val model="Model"></stat-val> 
    

    指令现在将模型分配给它的控制器

      .directive('statVal', function()
      {
        return {
            restrict: 'E',
            templateUrl: 'templates/statValue.html',
            //transclude:true,
            scope: {
                Model: "=model",
                // ...
            },
            controllerAs: 'statCtrlr',
            controller: ['$scope', '$http', function ($scope, $http) {
                //$scope.statValue
                var ctrl = this;
    
                //ctrl.statValue = $scope.data[$scope.prop];
                console.log("$scope", $scope);
    
                //ctrl.statValue = $scope.data;
                ctrl.Model = $scope.Model;
            }],
        };
      })
    

    查看here

    另一种方法是观察原始数据...直到它们真正进入指令,然后将它们分配给控制器...但我试图解释正在发生的事情,上面的例子更精确

    注意:我只使用了 JavaScript 作为示例,因为这里的问题与 Typescript 无关

    【讨论】:

    • 感谢您提供了非常好的答案,但是@avijit gupta 首先回答并且它有效。所以我将选择他作为最终答案,再次感谢您的帮助!
    • 重点是 - 你有答案。这太棒了!享受 UI-Router,先生 ;)
    【解决方案2】:

    您的$scope.data 是双向绑定的,而不是ctrl.statValue

    this.statDown = () => {
        console.log("statDown", $scope.data);
        if ($scope.data > 0) {
            $scope.data--;
        }
    };
    
    this.statUp = () => {
       console.log("statUp", $scope.data);
       $scope.data++;
    };
    

    【讨论】:

    • 但 ctrl.statValue 不应该只是对同一事物的引用吗?
    • ctrl.statValue 只是$scope.data 的副本,但只有作用域变量是双向绑定的。因此,您必须明确更新 $scope.data 才能在其他地方反映更改。
    • 我的 html 像这样绑定然后 {{$scope.data}}。我还使用数据吗:“=”?
    • 您永远不会在 .html 中使用 $scope,您的 .html 会像这样绑定:&lt;span&gt;{{data}}&lt;/span&gt;。是的,你仍然应该使用data: "="
    • 是的,我让它工作了!事后看来如此简单,这就是我猜的事情。既然我已经让它工作了,我认为使用“&”传递一个 ref 函数可能更有意义,因为将来统计数据可能会以不同的方式递增,等等。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-09-08
    • 2012-10-28
    • 2013-09-23
    • 2017-12-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多