2

Using AngularJS, AngularFire and Firebase, as a new user, I am having trouble with a distributed code base. I am trying to use Factory() often to re-use code and follow best practices for tests. However, I am having trouble adding data to my AngularFire object, and Firebase.

Given the following factory:

angular.module('MyApp').factory("ItemData", ["$firebaseObject", "$firebaseArray", "GetFireBaseObject",
    function($firebaseObject, $firebaseArray, GetFireBaseObject) {
        var ItemsRef = GetFireBaseObject.DataURL('Items/');
        return {
            AllItems: function() {
                return $firebaseArray(ItemsRef);
            },
            OneItem: function(ItemKey) {
                var OneItemRef = ItemsRef.child(ItemKey); 
                return $firebaseObject(OneItemRef);
            }
        };
    }
]);

I can get my item, I can work with the data, etc... However, I cannot seem to add an element to the object, and have it added to Firebase. While the screen will update the quantity when I call the AddQuantity/MinusQuantity, I cannot get this data to link with Firebase and update the records there.

angular.module('MyApp').controller('InventoryCtrl', ["$scope", "StoreData", "ItemData"
    function ($scope, StoreData, ItemData) {

        $scope.StoreList = StoresData.AllStores();
        $scope.SelectedStore = {};     // Store Information
        $scope.ItemList = {};          // Store Item List

        $scope.GetItemsForStore = function() {
            // StoreDate.OneStoreItems returns list of items in this store
            var ItemData = StoreItems.OneStoreItems($scope.SelectedStore.Key);  // $firebaseArray() returned

            for( var i = 0; i < ItemData.length; ++i)
            {
                var Item = ItemData[i];

                // Item Data is master item data (description, base price, ...)
                var OneItem = ItemsData.OneItem(Item.$id);  // Get Master by Key

                Item.Description = OneItem.Description;   // From Master
                Item.UnitPrice = OneItem.UnitPrice;
                Item.Quantity = 0;
                Item.UnitTotal = 0;
            }
            $scope.ItemList = ItemData;
        };

        $scope.AddQuantity = function(item) {
            if( ! item.Quantity ) {
                item.Quantity = 0;
            }
            ++item.Quantity;
        };

        $scope.MinusQuantity = function(item) {
            if( ! item.Quantity ) {
                item.Quantity = 0;
            }
            --item.Quantity;
            if(item.Quantity <= 0) {
                item.Quantity = 0;
            }
        };
    }
]);

Snippet from HTML

            <pre>{{ ItemList | json}}</pre>
            <div>
                <table class="table">
                    <thead>
                        <th>Product Code</th>
                        <th>Description</th>
                        <th>Qty</th>
                        <th>&nbsp;</th>
                        <th>&nbsp;</th>
                        <th>Extended</th>
                    </thead>
                    <tbody>
                        <tr ng-repeat="(Key, item) in ItemList">
                            <td>{{item.$id}}</td>
                            <td>{{item.Description}}</td>
                            <td>{{item.Quantity}}</td>
                            <td><button class="btn btn-success" ng-click="AddQuantity(item)">+</button></td>
                            <td><button class="btn btn-danger" ng-click="MinusQuantity(item)">-</button></td>
                            <td>{{item.UnitPrice | SLS_Currency}}</td>
                            <td>{{item.UnitTotal}}</td>
                        </tr>
                    </tbody>
                </table>
            </div>

I can see the Quantity field added to the ItemList object in the element, but even though I am passing the 'item' element from the ng-repeat with the buttons, which seems to be the proper reference, I do not see the data sync to Firebase.

4
  • You load your $firebaseObject into OneItem, but then modify the fields on Item. var OneItem = ItemData.OneItem(Item.$id);` vs Item.Description = OneItem.Description;. Modify the properties on OneItem and then call $save() on it. Commented May 25, 2015 at 23:50
  • @FrankvanPuffelen I updated the code with comments to better explain what I am trying to do. The data is normalized, and each store may have a different subset of information from the Master list of items. The OneItem call is for the Master item, so I can get description, price, etc... from it, for my working list that I want to update. I do not want to change the master item, but the store item. Commented May 26, 2015 at 16:53
  • 1
    The problem remains the same as far as I can see: you need to call $save on a $firebaseObject somewhere to save your changes. If that's not it, can you set up a jsfiddle/jsbin that reproduces the problem? Commented May 26, 2015 at 17:23
  • @FrankvanPuffelen I will have to try to pull it apart and create one, since I need a Firebase reference etc... Commented May 26, 2015 at 18:26

1 Answer 1

2

I changed the factory to be a service, and I believe this could still be done via the factory, but I had to add the bind functionality from the AngularFire manual as shown. A subset of the code is below to select the record and do an add.

angular.module('MyApp').service("ItemData", ["$firebaseObject", "$firebaseArray", "GetFireBaseObject",
    function($firebaseObject, $firebaseArray, GetFireBaseObject) {
        var ItemRef = GetFireBaseObject.DataURL('Items/');

        this.AddItem = function(Item) {
            var OneItemRef = ItemRef.child(Item.Key);
            OneItemRef.update(Item);
            return $firebaseObject(OneItemRef);
        };

        this.DeleteItem = function(ItemKey) {
            var OneItemRef = ItemRef.child(ItemKey);
            OneItemRef.remove();
        };      

        this.GetAllItems = function() {
            return $firebaseArray(ItemRef);
        };

        this.GetOneItem = function(ItemKey) {
            var OneItemRef = ItemRef.child(ItemKey);
            return $firebaseObject(OneItemRef);
        };
    }
]);

Then the controller will have to do an added bind, which could be possibly done in the service as well:

angular.module('MyApp').controller('ItemCtrl', ["$scope", "ItemData", 
    function ($scope, ItemData) {

        $scope.Items = ItemData.GetAllItems();

        $scope.EditItem = function(Item) {
            var EditItem = ItemData.GetOneItem(Item.Key);
            // Bind here for real time updates - NOTE: Changes with each key
            EditItem.$bindTo($scope, "Item").then(
                function(unbind) {
                    $scope.ItemUnbind = unbind;
                }
            );
            $scope.Item.NewField = "ABC";     // Add extra field to Firebase
        };

        $scope.SaveItem = function(Item) {
            if( ! $scope.ItemEditMode )
            {
                $scope.Item = ItemData.AddItem(Item);
            }
        };
    }
]);

With this change though, any changes (each key press for instance) will be immediately sync'd into the Firebase data.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.