【问题标题】:$watchCollection not updating array length on page$watchCollection 不更新页面上的数组长度
【发布时间】:2016-06-22 16:46:45
【问题描述】:

我正在尝试为用户拥有的警报数量设置一个计数器。如果我控制台记录 $scope.alerts 和 $scope.count,我可以看到两者都在更新,但使用 {{alerts.length}} 或 {{count}} 作为 #msgCount 的值只会给我pageLoad 上的初始计数,并且不会在数组长度更改时更新。我做错了什么?

我的控制器:

myApp.controller('globalAlerts', ['$scope', '$http', function ($scope, $http) {
        $scope.alerts = [{
    "type": "warning",
    "msg": "This is a generic alert. It is best suited for one or two line messages."
},
{
    "type": "danger",
    "msg": "<strong>Past Due!</strong> You have an invoice <a class=\"invoice-link\" href=\"\">192607</a> that is past due. <a href=\"invoices.html\">View all invoices.</a>"
},
{
    "type": "success",
    "msg": "This green alert indicates something positive occurred. Doesn't that make you feel happy?"
},
{
    "type": "info",
    "msg": "This blue alert is another generic warning usually used to inform. Isn't it soothing?"
}
];
    $scope.$watchCollection('alerts.length', function() {
        return $scope.alerts.length;

    }, true);
    $scope.closeAlert = function(index) {
      $scope.alerts.splice(index, 1);
    };



    $scope.dynamicPopover = {
            templateUrl: 'partials/alerts/globalAlerts.html',
            title: 'Recent Alerts'
    };

}]);

还有标记:

<div id="upperNav" ng-controller = "globalAlerts">
        <a class="btn btn-link" id="msg" popover-placement="bottom" uib-popover-template="dynamicPopover.templateUrl" popover-title="{{dynamicPopover.title}}" >
        <div class="badge badge-warning" id="msgCount">{{alerts.length}}</div>
        ALERTS</a></div>

使用弹出框标记:

<div id="alertCntr" ng-controller = "globalAlerts">
         <uib-alert ng-show="alerts.length" ng-repeat="alert in alerts track by $index" type="{{alert.type}}" close="closeAlert($index)">{{alert.msg}}</uib-alert>  
         <p ng-hide="alerts.length">You ain't got no more alerts, kid!</p>   
</div>

【问题讨论】:

  • 我很好奇为什么您甚至需要在您的示波器上使用count 字段。 alerts.length 不能用来干什么?
  • 如果我能得到更新的长度,那绝对没有。我认为这是一个解决长度不更新的解决方案。
  • 我根据我的其他 plnk 之一为你设置了这个,但你应该明白要点。 plnkr.co/edit/oMRDpGnXDU4sV1GWNdne?p=preview 。这是相同的想法,在没有手表的情况下更新了删除和长度。
  • 有趣。这正是我开始的。您是否认为它没有更新,因为 ng-repeat 位于动态 div(例如弹出框)中,不会与 pageLoad 上的页面其余部分一起呈现?我认为是这种情况,但是主要标记如何获取 pageLoad 上的长度?

标签: javascript angularjs


【解决方案1】:

对于其他用户:

HTML 规定每个块都有自己的控制器。这意味着 2 个控制器是独立的,不知道彼此的警报数组何时被触摸过。

最简单的解决方案是嵌套 HTML,以便它们共享一个控制器:

<div id="upperNav" ng-controller = "globalAlerts">
    <a class="btn btn-link" id="msg" popover-placement="bottom" uib-popover-template="dynamicPopover.templateUrl" popover-title="{{dynamicPopover.title}}" >
    <div class="badge badge-warning" id="msgCount">{{alerts.length}}</div>
    ALERTS</a>
    <div id="alertCntr">
       <uib-alert ng-show="alerts.length" ng-repeat="alert in alerts track by $index" type="{{alert.type}}" close="closeAlert($index)">{{alert.msg}}</uib-alert>  
       <p ng-hide="alerts.length">You ain't got no more alerts, kid!</p>   
     </div>
</div>

编辑:

更新的 plnkr 完全符合您的要求:http://plnkr.co/edit/AIwGi7eIzilsGGL7Us3G?p=preview

【讨论】:

  • 因此 Angular UI 需要将不安全的 HTML 放在单独的文件夹中才能正确呈现。如果我将代码移动到 ng-template 脚本标记中,则弹出框不会呈现。 angular-ui.github.io/bootstrap/#/popover
  • @ChristianHill 似乎在您提供的文档中,他们的模板是内联的。为什么你的需要放在单独的文件夹中?我没有看到那里提到的。
  • 它是辅助方法,因为内联方法不支持不安全的 HTML。如果您阅读右侧内容,您会看到调用弹出框的方法有三种,并且模板方法是唯一同时支持编译代码和不安全 HTML 的版本。
  • @ChristianHill 我看到了,但是如果你查看他们的演示,他们使用uib-popover-template="dynamicPopover.templateUrl",它等于myPopoverTemplate.html,并且是内联定义的:&lt;script type="text/ng-template" id="myPopoverTemplate.html"&gt; &lt;div&gt;{{dynamicPopover.content}}&lt;/div&gt; &lt;div class="form-group"&gt; &lt;label&gt;Popup Title:&lt;/label&gt; &lt;input type="text" ng-model="dynamicPopover.title" class="form-control"&gt; &lt;/div&gt; &lt;/script&gt;
  • 当我使用这个方法时,弹出框不渲染。我假设它是因为 HTML 不安全并且正在破坏我的代码。
【解决方案2】:

您在 watch 函数之后添加了另一个参数。像这样。

$scope.$watchCollection('alerts.length', function() {
    $scope.count = $scope.alerts.length;
    return $scope.count;
},true);

你必须提出另一个论点(真),这意味着“深度观察”。这适用于查看嵌套对象或对象数组时。

您也可以在此处查看。 How to deep watch an array in angularjs?

顺便说一句,将 ng-model 放入 div 是没有用的

<div class="badge badge-warning" id="msgCount">{{alerts.length}}</div>

这就够了。

【讨论】:

  • 谢谢。我用我所做的相同编辑编辑了上面的代码。根据 KreepN 的评论,我添加了 true 并删除了与“计数”相关的代码。它仍然没有更新。
  • @ChristianHill 这很可能与您正在启动控制器的 2 个实例并且它们不共享数据的事实有关。这意味着,当您关闭模式并进行拼接时,显示长度的模式不受影响。您的应用结构是这里问题的根本原因。
  • 那么您会推荐什么作为解决方案?
【解决方案3】:

当您想在两个控制器之间进行通信时,您可以使用 $broadcast 或使用 service 来存储值。我更喜欢使用服务,您以后也可以在其他情况下使用此“serviceForStoringValue”。

.controller('controller1',function($scope,serviceForStoringValue){
  $scope.getCount = serviceForStoringValue.getCount;
})
 -----------------
.controller('controller2',function($scope,serviceForStoringValue){
  $scope.$watch('',function(n,o){
     serviceForStoringValue.setCount(n.length);
  },true)
})
-----------------
.factory('serviceForStoringValue',function(){
   var count;
   function getCount(){
     return count;
   }
   function setCount(n){
      count = n;
   }

   return {
    getCount:getCount,
    setCount:setCount
   }
 })


<div>{{getCount()}}<div>

【讨论】:

    【解决方案4】:

    非常感谢 KreepN 给了我一些指导。我终于意识到模板中的控制器调用是不必要的,因为 div 呈现在主页上的控制器 div 中。一旦我删除了所有内容都属于我的控制器标记,并且计数按预期工作。

    【讨论】:

    • 检查我的编辑,我得到了所有的工作,因为我真的很想弄清楚。如果它最终对您有用,请随时接受答案。谢谢。
    猜你喜欢
    • 2023-04-02
    • 2014-04-29
    • 1970-01-01
    • 1970-01-01
    • 2014-08-14
    • 2021-07-30
    • 2014-09-24
    相关资源
    最近更新 更多