2017-04-25 76 views
3

我试图创建一个指令,允许我传入一个属性字符串,然后在订阅事件时将其用作“name”参数使用$ scope。$ on。本质上,这一系列事件是这样的:

  1. 一个对象被广播使用$ rootScope。$ broadcast在另一个控制器中调用'validationResultMessage'。
  2. 我有一个指令,其中有一个属性叫“订阅”,我传递字符串'validationResultMessage'。
  3. 该指令将“subscription”属性的值传递给其作用域,并使用“$ scope。$ on”对其进行订阅。

问题是,它看起来像属性的值是“未定义”的时候,所有的评估,所以当我尝试使用$ scope。$ on进行订阅时,它实际上订阅我“undefined “而不是 ”validationResultMessage“

这里是我的指令:

app.directive('detailPane', function() { 
return { 
    restrict: 'E', 
    scope: { 
     selectedItem: '=', 
     subscription: '@', 
    }, 
    templateUrl: 'app/templates/DetailPane.html', //I'm also worried that this is causing my controller to get instantiated twice 
    controller: 'DetailPaneController' 

    }; 
}); 

然后我用这样的:

<td class="sidebar" ng-controller="DetailPaneController" ng-style="{ 'display': sidebarDisplay }"> 
      <detail-pane 
        selected-item='validationResult' 
        subscription='validationResultMessage'/> 

</td> 

而那我想这个属性传递到控制器:

app.controller('DetailPaneController', ['$scope', '$http', 'dataService', 'toastr', '$uibModal', '$rootScope', '$attrs', function ($scope, $http, dataService, toastr, $uibModal, $rootScope, $attrs) { 
$scope.fetching = []; 
$scope.validationResult = null; 
$scope.sidebarDisplay = 'block'; 



console.log('subscription is ', $scope.subscription); 
var thisSubscription = $scope.subscription; 

//if I hardcode the param as 'validationResultMessage', this works 
$scope.$on($scope.subscription, function (event, arg) { 
    $scope.validationResult = arg; 
    }); 
}]); 

回答

1

我打算发布我的答案1,鉴于它有点代码,请让我知道如果这是必需的结果,那么我可以提供意见。您应该能够运行提供的代码片段。

var app = angular.module('myApp', []); 
 

 
app.directive('detailPane', function() { 
 
    return { 
 
    restrict: 'E', 
 
    transclude: false, 
 
    scope: { 
 
     selectedItem: '=', 
 
     subscription: '@' 
 
    }, 
 
    link: function(scope, elem, attr) { 
 
     scope.$on(scope.subscription, function(e, data) { 
 
     scope.selectedItem = data.result; 
 
     elem.text(data.message); 
 
     }); 
 
    }, 
 
    }; 
 
}); 
 

 
app.controller('DetailPaneController', function($scope) { 
 
    $scope.validationResult1 = ""; 
 
    $scope.validationResult2 = ""; 
 
}); 
 

 
app.controller('SecondController', function($rootScope, $scope, $timeout) { 
 

 
    $timeout(function() { 
 
    $rootScope.$broadcast('validationResultMessage1', { 
 
     message: 'You fail!', 
 
     result: 'Result from 1st fail' 
 
    }) 
 
    }, 2000); 
 

 
    $timeout(function() { 
 
    $rootScope.$broadcast('validationResultMessage2', { 
 
     message: 'You also fail 2!', 
 
     result: 'Result from 2nd fail' 
 
    }) 
 
    }, 4000); 
 

 
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script> 
 

 
<body ng-app='myApp'> 
 
    <div ng-controller="DetailPaneController"> 
 
    <detail-pane class='hello' selected-item='validationResult1' subscription='validationResultMessage1'></detail-pane> 
 
    <br/> 
 
    <detail-pane class='hello' selected-item='validationResult2' subscription='validationResultMessage2'></detail-pane> 
 

 
    <hr/> 
 
    <span>{{validationResult1}}</span> 
 
    <br/> 
 
    <span>{{validationResult2}}</span> 
 

 
    </div> 
 
    <div ng-controller="SecondController"> 
 

 
    </div> 
 
</body>

+1

从表面上看,这确实提供了我之后的行为。如果我的理解正确,它将父节点DetailPaneController的作用域的validationResult设置为SecondController正在广播的内容。我想我可以使用模板引用validationResult1和validationResult2来显示我想要的信息,如果我不想插入内联。 我看到你正在使用链接功能来完成这种行为,这不是我以前考虑过的事情。我是否正确理解此解决方案的基本机制? – istrupin

+1

是的,'$ broadcast'给'$ root'并让任何订阅的侦听器获得事件。在这个要求中,我们通过指令来做到这一点,每一个细节帕恩只应该听取它订阅的内容。需要可重复使用和独立。 'selected-item'是当收到消息时需要更新的'model',可能绑定到声明的控制器/视图。对于这种类型的DOM操作以及需要指令逻辑的'link'是强大的。我已经使用'validationresult1'和2来模拟你的设置并显示可以传递细节。不是必需的。@ istrupin – Searching

0

我想你应该设置$ scope.subscription守望,如果新的值设置检查,然后开始订阅传递事件。

$scope.$watch('subscription', function(nv, ov){ 
//this makes sure it won't trigger at initialization 
if(nv!==ov){ 
    $scope.$on($scope.subscription, function (event, arg) { 
     $scope.validationResult = arg; 
    }); 
} 
}); 
+0

嗯,我看你是想在这里做什么,我想这可能是问题的一部分,但是实施这个没有用。现在看起来我的$ $从来没有被击中。 – istrupin

2

所以另一种方式,我设法解决这个具体问题是只使用内部DetailPaneController在指令体定义。我的部分问题是,我让控制器作为父控制器在我的html中使用ng-controller=以及在指令主体中定义两次被实例化。这样我就可以使用直接的“@”绑定,并且所有内容都按照正确的顺序解决。我甚至可以在我的模板中有另一个指令,我可以将我的validationResult传入。

新的设置是这样的:

DetailPaneController:

app.controller('DetailPaneController', ['$scope', '$http', function ($scope, $http) { 

$scope.$on($scope.subscription, function (event, arg) { 
    $scope.validationResult = arg; 
    $scope.exception = JSON.parse(arg.Exception); 
    }); 
}]); 

DetailPane指令:

app.directive('detailPane', function() { 
return { 
    restrict: 'E', 
    scope: { 
     subscription: '@' //notice I am no longer binding to validationResult 
    }, 
    templateUrl: 'app/templates/DetailPane.html', 
    controller: 'DetailPaneController' 
    }; 
}); 

指令在HTML中使用

 <div class="sidebar" ng-style="{ 'display': sidebarDisplay }"> <detail-pane subscription='validationResultMessage' /> </div> 

指令模板(好措施):

<div class="well sidebar-container"> 
<h3>Details</h3> 
<div ng-show="validationResult == null" style="padding: 15px 0 0 15px;"> 
    <h5 class=""><i class="fa fa-exclamation-triangle" aria-hidden="true" /> Select a break to view</h5> 

</div> 
<div ng-show="validationResult != null"> 
    <table class="table table-striped"> 
     <tr ng-repeat="(key, value) in validationResult"> 
      <td class="sidebar-labels">{{key | someFilter}}</td> 
      <td >{{value | someOtherFilter : key}}</td> 
     </tr> 
    </table> 
    <another-directive selected-item="validationResult" endpoint="endpoint" /> 
</div> 

相关问题