Angular: How to $broadcast from Factory?

前端 未结 4 1108
没有蜡笔的小新
没有蜡笔的小新 2021-01-20 16:59

I have a list of items and I need to get a message (saying Item added!) in the navbar whenever a new item is added.

The function addItem() (ng-click on the Add Item

相关标签:
4条回答
  • 2021-01-20 17:38

    You can inject $rootScope into your factory and use $broadcast from there.

    angular.module('MyApp').factory('ItemFactory', ["$rootScope", function($rootScope){
    
        var items = [
            'Item 1', 
            'Item 2', 
            'Item 3'
        ];
    
        return {
            getItem : function() {
                return items;
            },
            addItem : function(item){
                items.push(item);
                // $broadcast
                $rootScope.$broadcast('itemAdded', 'Item added!');
            },
            removeItem : function($index){
                items.splice($index, 1);
            }
        };
    

    }]);

    0 讨论(0)
  • 2021-01-20 17:48

    You not injected $scope to factory, and you cant actually, use $rootScope instead

    0 讨论(0)
  • 2021-01-20 17:53

    Here is a clean solution for you.

    See it working in this plunker

    Let me explain how all of this works.

    Your message looks like this :

    <span ng-if="alertItemAdded.recentAdd">Item added !</span>
    

    It will show only when "alterITemAdded.recenAdd" is true. You'll use this to make the message disapear if you need.

    You factory look like this now :

    angular.module('MyApp').service('ItemService', function(){
    
        var service = {};
    
        //I'll always wrap my data in a sub object.
        service.notification = {};
    
        service.notification.recentAdd=false;
    
        service.items = {};
    
        service.items.list = [
            'Item 1', 
            'Item 2', 
            'Item 3'
        ];
    
        service.items.addItem = function(item){
              service.items.list.push(item);
              service.notification.recentAdd=true;
              console.log(service);
        }
    
        service.items.removeItem = function($index){
              service.items.list.splice($index, 1);
        }
    
        return service;
    
    });
    

    I'm using service instead of factory. But there is almost no difference, it's just a matter of taste.

    Here is your controllers

    angular.module('MyApp').controller('MainCtrl', function($scope, ItemService){
    
        $scope.text = "Text from the Main Controller";
    
    });
    
    angular.module('MyApp').controller('NavCtrl', function($scope, ItemService){
    
        //IMPORTANT POINT : I bind it the sub object. Not to the value. To access the value i'll use $scope.alterItemAdded.recentAdd
        $scope.alertItemAdded = ItemService.notification;
        //I don't have to redeclare the function. I just bind it to the service function.
        $scope.addItem = ItemService.items.addItem;
    });
    
    angular.module('MyApp').controller('ContentCtrl', function($scope, ItemService){
    
        $scope.items = ItemService.items.list;
    
        $scope.addItem = ItemService.items.addItem;
    
        $scope.removeItem = function($index){
            ItemService.items.removeItem($index);
        }
    
    });
    

    Important point :

    I always bind my vars to a sub object. Why ? In fact if i did $scope.alertItemAdded = ItemService.notifications.recentAdd

    When i do something like this in my service

     service.notifications.recentAdd = true;
    

    It will create a new variable and put the reference into service.notifications.recentAdd. The $scope.alertItemAdded was bind to the previous reference and wont see the update.

    Doing this :

    $scope.alterItemAdded = ItemService.notification
    

    And using the value in the ng-if clause or anything else. I prevent the reference link to break. If i do in the service

    service.notification.recentAdd = true
    

    I'll create a new var with a new reference for "recentAdd" but i keep the same reference for "notification". The binding in the controller will be keep and the value recentAdd will be updated in the view.

    If you have more question feel free to ask.

    0 讨论(0)
  • 2021-01-20 17:58

    $broadcast goes from top to bottom so you should use $rootScope to perform a $broadcast to all $scope elements below it.

    • Inject $rootScope in your factory

    • $rootScope.$broadcast('itemAdded, 'Item added!')

    0 讨论(0)
提交回复
热议问题