【问题标题】:AngularJS - Custom directive not updating view even with $scope.$applyAngularJS - 即使使用 $scope.$apply 自定义指令也不会更新视图
【发布时间】:2017-12-14 11:51:10
【问题描述】:

我开发了一个自定义角度指令来清除通知数组(在控制器中使用 controllerAs 'this' 语法定义),当单击按钮时然后当单击确认按钮时出现的对话框。

所以流程是:

click on 'Clear Notifications'  >  dialog appears  >  click on 'Confirm'  >  clear array

或者,在同一个指令中,我定义了如果在对话框出现时单击“取消”,则数组不受影响。

我已经使用 angular material 中的 $mdMDialog 完成了这项工作,所有这些都在指令代码中。

然而,即使模型由于确认数组清除而明显受到影响,视图也不会使用各种方法更新,包括将指令函数包装在 $scope.$apply 和添加 $scope.$apply 回调控制器中的函数,作为参数注入到指令链接函数中。

我最初在控制器中有这个函数,它工作得很好,但是由于将它移动到一个指令中,当模型改变时视图不再更新。

类似于我在 JSFiddle 中的应用的示例:http://jsfiddle.net/c9v83vo4/7/

(我已经包含了一个注释掉的控制器方法来演示。)

-

HTML:

<md-list-item ng-repeat="notification in notifications.shownNotifications | orderBy:notifications.sortProperty " ng-click="notifications.selectedNotification=notification; notification.read=true" ng-class=" { 'active': notifications.selectedNotification==notification, 'unread': notification.read == false } " class="md-3-line notification-item" md-ink-ripple="#fff">

控制器:

app.controller('notificationsController', function($scope, $state, $http, $document, $mdDialog, $filter, $timeout, $mdToast) {

var main = this;

this.test = 'TEST';

this.selectedNotification = null;
this.notifications = [
    {
        title: 'Notification One',
        description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean eu nisl nec quam iaculis aliquet. Suspendisse potenti. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Fusce felis leo, ornare nec pharetra non, elementum non dui. Fusce sed lacinia libero, a luctus ligula. Integer in felis ex. Nam sed pellentesque tellus, in luctus nibh.',
        time: '2017-10-27T16:39:32+00:00',
        importance: 'Low',
        read: false
    },
    {
        title: 'Notification Two',
        description: 'Donec quis ligula odio. Sed sit amet magna eu erat posuere maximus. Nulla vitae erat pharetra, molestie augue in, pellentesque urna. Nullam gravida, turpis ac imperdiet cursus, elit lorem facilisis est, nec posuere magna arcu sed metus. Cras a ex ultrices, sagittis quam sit amet, sollicitudin massa. Nam orci turpis, sagittis ut sapien vel, mattis sodales lectus. Phasellus malesuada commodo metus, eget tempus nibh consectetur ac. Nullam dictum dui ac nunc accumsan, tristique varius risus porta. Mauris velit diam, cursus eu enim sit amet, egestas suscipit augue.',
        importance: 'High',
        time: '2017-11-28T12:38:34+00:00',
        read: false
    },
    {
        title: 'Notification Three',
        description: 'Praesent varius metus et efficitur sollicitudin. Mauris diam neque, feugiat vitae lorem non, accumsan lacinia urna. Morbi faucibus enim ut eros ullamcorper, ultricies malesuada massa ultrices. Vivamus rutrum urna purus, sed blandit ipsum finibus sed. In molestie diam ut justo convallis maximus. Nulla massa arcu, molestie et mauris eu, semper sodales magna. Nunc faucibus iaculis dictum. Nulla feugiat, est lobortis scelerisque pellentesque, est enim rutrum nulla, non laoreet orci ligula quis ex.',
        importance: 'Low',
        time: '2017-11-29T09:56:43+00:00',
        read: false
    },
    {
        title: 'Notification Four',
        description: 'Praesent varius metus et efficitur sollicitudin. Mauris diam neque, feugiat vitae lorem non, accumsan lacinia urna. Morbi faucibus enim ut eros ullamcorper, ultricies malesuada massa ultrices. Vivamus rutrum urna purus, sed blandit ipsum finibus sed. In molestie diam ut justo convallis maximus. Nulla massa arcu, molestie et mauris eu, semper sodales magna. Nunc faucibus iaculis dictum. Nulla feugiat, est lobortis scelerisque pellentesque, est enim rutrum nulla, non laoreet orci ligula quis ex.',
        importance: 'Low',
        time: '2017-12-04T12:38:34+00:00',
        read: true
    },
    {
        title: 'Notification Five',
        description: 'Praesent varius metus et efficitur sollicitudin. Mauris diam neque, feugiat vitae lorem non, accumsan lacinia urna. Morbi faucibus enim ut eros ullamcorper, ultricies malesuada massa ultrices. Vivamus rutrum urna purus, sed blandit ipsum finibus sed. In molestie diam ut justo convallis maximus. Nulla massa arcu, molestie et mauris eu, semper sodales magna. Nunc faucibus iaculis dictum. Nulla feugiat, est lobortis scelerisque pellentesque, est enim rutrum nulla, non laoreet orci ligula quis ex.',
        importance: 'Low',
        time: '2017-11-27T16:39:32+00:00',
        read: false
    },
    {
        title: 'Notification Six',
        description: 'Praesent varius metus et efficitur sollicitudin. Mauris diam neque, feugiat vitae lorem non, accumsan lacinia urna. Morbi faucibus enim ut eros ullamcorper, ultricies malesuada massa ultrices. Vivamus rutrum urna purus, sed blandit ipsum finibus sed. In molestie diam ut justo convallis maximus. Nulla massa arcu, molestie et mauris eu, semper sodales magna. Nunc faucibus iaculis dictum. Nulla feugiat, est lobortis scelerisque pellentesque, est enim rutrum nulla, non laoreet orci ligula quis ex.',
        importance: 'High',
        time: '2018-01-04T12:38:34+00:00',
        read: false
    },
    {
        title: 'Notification Seven',
        description: 'Praesent varius metus et efficitur sollicitudin. Mauris diam neque, feugiat vitae lorem non, accumsan lacinia urna. Morbi faucibus enim ut eros ullamcorper, ultricies malesuada massa ultrices. Vivamus rutrum urna purus, sed blandit ipsum finibus sed. In molestie diam ut justo convallis maximus. Nulla massa arcu, molestie et mauris eu, semper sodales magna. Nunc faucibus iaculis dictum. Nulla feugiat, est lobortis scelerisque pellentesque, est enim rutrum nulla, non laoreet orci ligula quis ex.',
        importance: 'Low',
        time: '2017-11-27T16:39:32+00:00',
        read: false
    },
    {
        title: 'Notification Eight',
        description: 'Praesent varius metus et efficitur sollicitudin. Mauris diam neque, feugiat vitae lorem non, accumsan lacinia urna. Morbi faucibus enim ut eros ullamcorper, ultricies malesuada massa ultrices. Vivamus rutrum urna purus, sed blandit ipsum finibus sed. In molestie diam ut justo convallis maximus. Nulla massa arcu, molestie et mauris eu, semper sodales magna. Nunc faucibus iaculis dictum. Nulla feugiat, est lobortis scelerisque pellentesque, est enim rutrum nulla, non laoreet orci ligula quis ex.',
        importance: 'High',
        time: '2017-11-27T13:38:34+00:00',
        read: true
    },
    {
        title: 'Notification Nine',
        description: 'Praesent varius metus et efficitur sollicitudin. Mauris diam neque, feugiat vitae lorem non, accumsan lacinia urna. Morbi faucibus enim ut eros ullamcorper, ultricies malesuada massa ultrices. Vivamus rutrum urna purus, sed blandit ipsum finibus sed. In molestie diam ut justo convallis maximus. Nulla massa arcu, molestie et mauris eu, semper sodales magna. Nunc faucibus iaculis dictum. Nulla feugiat, est lobortis scelerisque pellentesque, est enim rutrum nulla, non laoreet orci ligula quis ex.',
        importance: 'Low',
        time: '2017-11-28T13:38:34+00:00',
        read: false
    },
    {
        title: 'Notification Ten',
        description: 'Praesent varius metus et efficitur sollicitudin. Mauris diam neque, feugiat vitae lorem non, accumsan lacinia urna. Morbi faucibus enim ut eros ullamcorper, ultricies malesuada massa ultrices. Vivamus rutrum urna purus, sed blandit ipsum finibus sed. In molestie diam ut justo convallis maximus. Nulla massa arcu, molestie et mauris eu, semper sodales magna. Nunc faucibus iaculis dictum. Nulla feugiat, est lobortis scelerisque pellentesque, est enim rutrum nulla, non laoreet orci ligula quis ex.',
        importance: 'Low',
        time: '2016-07-11T12:11:20+00:00',
        read: true
    },
    {
        title: 'Notification Eleven',
        description: 'Praesent varius metus et efficitur sollicitudin. Mauris diam neque, feugiat vitae lorem non, accumsan lacinia urna. Morbi faucibus enim ut eros ullamcorper, ultricies malesuada massa ultrices. Vivamus rutrum urna purus, sed blandit ipsum finibus sed. In molestie diam ut justo convallis maximus. Nulla massa arcu, molestie et mauris eu, semper sodales magna. Nunc faucibus iaculis dictum. Nulla feugiat, est lobortis scelerisque pellentesque, est enim rutrum nulla, non laoreet orci ligula quis ex.',
        importance: 'Low',
        time: '2017-10-21T09:36:37+00:00',
        read: false
    },
    {
        title: 'Notification Twelve',
        description: 'Praesent varius metus et efficitur sollicitudin. Mauris diam neque, feugiat vitae lorem non, accumsan lacinia urna. Morbi faucibus enim ut eros ullamcorper, ultricies malesuada massa ultrices. Vivamus rutrum urna purus, sed blandit ipsum finibus sed. In molestie diam ut justo convallis maximus. Nulla massa arcu, molestie et mauris eu, semper sodales magna. Nunc faucibus iaculis dictum. Nulla feugiat, est lobortis scelerisque pellentesque, est enim rutrum nulla, non laoreet orci ligula quis ex.',
        importance: 'High',
        time: '2017-01-01T01:11:10+00:00',
        read: true
    },
    {
        title: 'Notification Thirteen',
        description: 'Praesent varius metus et efficitur sollicitudin. Mauris diam neque, feugiat vitae lorem non, accumsan lacinia urna. Morbi faucibus enim ut eros ullamcorper, ultricies malesuada massa ultrices. Vivamus rutrum urna purus, sed blandit ipsum finibus sed. In molestie diam ut justo convallis maximus. Nulla massa arcu, molestie et mauris eu, semper sodales magna. Nunc faucibus iaculis dictum. Nulla feugiat, est lobortis scelerisque pellentesque, est enim rutrum nulla, non laoreet orci ligula quis ex.',
        importance: 'Low',
        time: '2016-06-16T06:35:22+00:00',
        read: false
    },
    {
        title: 'Notification Fourteen',
        description: 'Praesent varius metus et efficitur sollicitudin. Mauris diam neque, feugiat vitae lorem non, accumsan lacinia urna. Morbi faucibus enim ut eros ullamcorper, ultricies malesuada massa ultrices. Vivamus rutrum urna purus, sed blandit ipsum finibus sed. In molestie diam ut justo convallis maximus. Nulla massa arcu, molestie et mauris eu, semper sodales magna. Nunc faucibus iaculis dictum. Nulla feugiat, est lobortis scelerisque pellentesque, est enim rutrum nulla, non laoreet orci ligula quis ex.',
        importance: 'High',
        time: '2017-05-27T16:39:32+00:00',
        read: false
    },
    {
        title: 'Notification Fifteen',
        description: 'Praesent varius metus et efficitur sollicitudin. Mauris diam neque, feugiat vitae lorem non, accumsan lacinia urna. Morbi faucibus enim ut eros ullamcorper, ultricies malesuada massa ultrices. Vivamus rutrum urna purus, sed blandit ipsum finibus sed. In molestie diam ut justo convallis maximus. Nulla massa arcu, molestie et mauris eu, semper sodales magna. Nunc faucibus iaculis dictum. Nulla feugiat, est lobortis scelerisque pellentesque, est enim rutrum nulla, non laoreet orci ligula quis ex.',
        importance: 'Low',
        time: '2017-08-19T19:12:00+00:00',
        read: false
    },
    {
        title: 'Notification Sixteen',
        description: 'Praesent varius metus et efficitur sollicitudin. Mauris diam neque, feugiat vitae lorem non, accumsan lacinia urna. Morbi faucibus enim ut eros ullamcorper, ultricies malesuada massa ultrices. Vivamus rutrum urna purus, sed blandit ipsum finibus sed. In molestie diam ut justo convallis maximus. Nulla massa arcu, molestie et mauris eu, semper sodales magna. Nunc faucibus iaculis dictum. Nulla feugiat, est lobortis scelerisque pellentesque, est enim rutrum nulla, non laoreet orci ligula quis ex.',
        importance: 'Low',
        time: '2017-09-28T18:56:22+00:00',
        read: true
    },
    {
        title: 'Notification Seventeen',
        description: 'Praesent varius metus et efficitur sollicitudin. Mauris diam neque, feugiat vitae lorem non, accumsan lacinia urna. Morbi faucibus enim ut eros ullamcorper, ultricies malesuada massa ultrices. Vivamus rutrum urna purus, sed blandit ipsum finibus sed. In molestie diam ut justo convallis maximus. Nulla massa arcu, molestie et mauris eu, semper sodales magna. Nunc faucibus iaculis dictum. Nulla feugiat, est lobortis scelerisque pellentesque, est enim rutrum nulla, non laoreet orci ligula quis ex.',
        importance: 'Low',
        time: '2017-07-07T07:11:49+00:00',
        read: false
    },
    {
        title: 'Notification Eighteen',
        description: 'Praesent varius metus et efficitur sollicitudin. Mauris diam neque, feugiat vitae lorem non, accumsan lacinia urna. Morbi faucibus enim ut eros ullamcorper, ultricies malesuada massa ultrices. Vivamus rutrum urna purus, sed blandit ipsum finibus sed. In molestie diam ut justo convallis maximus. Nulla massa arcu, molestie et mauris eu, semper sodales magna. Nunc faucibus iaculis dictum. Nulla feugiat, est lobortis scelerisque pellentesque, est enim rutrum nulla, non laoreet orci ligula quis ex.',
        importance: 'High',
        time: '2016-02-27T09:11:32+00:00',
        read: true
    },
    {
        title: 'Notification Nineteen',
        description: 'Praesent varius metus et efficitur sollicitudin. Mauris diam neque, feugiat vitae lorem non, accumsan lacinia urna. Morbi faucibus enim ut eros ullamcorper, ultricies malesuada massa ultrices. Vivamus rutrum urna purus, sed blandit ipsum finibus sed. In molestie diam ut justo convallis maximus. Nulla massa arcu, molestie et mauris eu, semper sodales magna. Nunc faucibus iaculis dictum. Nulla feugiat, est lobortis scelerisque pellentesque, est enim rutrum nulla, non laoreet orci ligula quis ex.',
        importance: 'Low',
        time: '2017-11-13T13:14:55+00:00',
        read: false
    },
    {
        title: 'Notification Twenty',
        description: 'Praesent varius metus et efficitur sollicitudin. Mauris diam neque, feugiat vitae lorem non, accumsan lacinia urna. Morbi faucibus enim ut eros ullamcorper, ultricies malesuada massa ultrices. Vivamus rutrum urna purus, sed blandit ipsum finibus sed. In molestie diam ut justo convallis maximus. Nulla massa arcu, molestie et mauris eu, semper sodales magna. Nunc faucibus iaculis dictum. Nulla feugiat, est lobortis scelerisque pellentesque, est enim rutrum nulla, non laoreet orci ligula quis ex.',
        importance: 'High',
        time: '2017-09-27T06:43:32+00:00',
        read: false
    }
]

this.shownNotifications = this.notifications;

-

指令:

app.directive('clearNotifications', function($mdDialog, $mdToast, $timeout) {
return {
    restrict: 'A',
    controller: 'notificationsController', 
    controllerAs: 'notifications',
    scope: false,
    bindToController: true,
    link: function($scope, element, attrs, callback) {
        element.bind('click', function() {

            var notifications = $scope.notifications;

            notifications.notifications.length = 0;
            console.log(notifications.notifications);

            console.log('notifications.test: ' + notifications.test);

            /* Show confirmation prompt dialog */
            var confirm = $mdDialog.confirm()
                .parent(angular.element('body'))
                .clickOutsideToClose(true)
                .title('Are you sure you want to clear all notifications?')
                .textContent('This action cannot be undone.')
                .ariaLabel('Confirm notifications list clearance')
                .ok('Yes')
                .cancel('No')
                .targetEvent(element)


            /* On confirm */
            $mdDialog.show(confirm).then(function() {
                $scope.status = 'All notifications deleted';
                console.log($scope.status);

                /* Show notifications list loader */
                $scope.showLoader = true;
                $timeout(function() {
                    $scope.showLoader = false;
                }, 1000)


                /* Clear notifications array */
                notifications.notifications.length = 0;
                notifications.shownNotifications.length = 0;
                console.log(notifications.notifications);
                notifications.shownNotifications = angular.copy(notifications.notifications);
                console.log(notifications.shownNotifications);
                $scope.noNotifications = true;


                /* Reset filters to 'All' default */
                notifications.filters = angular.copy(notifications.resetFilters);


                /* Show toast */
                //$scope.toastTitle = 'TEST';
                $mdToast.show(
                    $mdToast.simple()
                        .content('All notifications cleared')
                        .action('Close')
                        .position('bottom right')
                        .hideDelay(500000)
                )

                notifications.callback();
            }, 

                /* On cancel */
                function() {
                $scope.status = 'Notifications clearance cancelled';
                console.log($scope.status);
            })
        })
    }
}
})

【问题讨论】:

  • 当询问由您的代码引起的问题时,如果您提供人们可以用来重现问题的代码,您将获得更好的答案。该代码应该是……最少 - 使用尽可能少的代码,但仍会产生同样的问题。见How to create a Minimal, Complete, and Verifiable example

标签: javascript angularjs model-view-controller angularjs-directive


【解决方案1】:

基于jsFiddle。问题是您将同一个控制器连接了两次:使用列表作为模板

&lt;div ng-controller="mainController as main"&gt;

在指令中

controller: 'mainController',

Controller 是一个构造函数 - 这意味着通过 ngController 和 'clearItems' 指令连接它,您将创建两个实例。因此,当您在一个指令中更改数据时,它不会反映在第二个指令中。

建议的解决方案是:

  1. clearNotifications指令断开notificationsController控制器
  2. 创建一个函数来清除notificationsController 中的项目列表
  3. 将此函数传递给clearNotifications 指令
  4. 当点击对话框中的按钮时解析/调用clearNotifications指令连接函数

    app.controller('notificationsController', function($scope) {
    
        // ...
    
        main.clearNotifications = function() {
          this.shownNotifications.length = 0;
        };
    })
    
    app.directive('clearNotifications', ['$parse', function($parse) {
        return {
        restrict: 'A',
        scope: {},
        link: function($scope, element, attrs) {
    
          var clearNotificationsFn = dropFn = $parse(attrs.clearNotifications);
          // ...
          $mdDialog.show(confirm).then(function() {
            // ...
            clearNotificationsFn($scope, {$event:event});
          });
    
        }
      }
    }]);
    

然后在您的 HTML 中,您可以将此指令连接到按钮或触发清除通知列表的任何内容,例如

<button clear-notifications="ctrl.clearNotifications()">
  Clear notifications
</button>

【讨论】:

  • 对不起,我忘了把它放在指令注入器中。 $parse 是一个角度服务,你应该将模块定义注入它: `app.directive('clearNotifications', ['$parse', function($parse) {...}]);
  • $event 也不能​​在指令中使用,因为它没有在任何地方注入,如果是的话也没有任何用处
  • 给出的代码不是最终解决方案,而是更好地描述解决方案的帮助。您不需要传递任何 $event,但我的意图是传递 element.click 事件。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-04-22
  • 1970-01-01
  • 2014-08-30
  • 1970-01-01
  • 2014-05-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多