1

Hi All I am super new to firebase and I need some help.

First of all what I'm doing is about a tick sheet. for example a tick sheet contains a list of items which contains logs of the ticks so I designed my data as follows:

Ticksheets:

ticksheets:
   -JbN5ol2jGRtAOZ9ovrO(auto generated id by firebase)
     created_on: 
     description: 
     name: 
     owner: 
   -JbN5ol2jGRtAOZ9ovrO
     created_on: 
     description: 
     name: 
     owner: 

Ticks:

ticks:
   -JbOGA1s3Tl3jtKPQe43 //ticksheet ID
       -JbOHE6wY5CLz1wazNUx //itemID
         Thu Nov 27 2014 01:51:40 GMT 0800 (MYT)
             timestamp:
       -JbhDiX4iDneG34LzEgA // itemID
         Thu Nov 27 2014 01:51:44 GMT 0800 (MYT)
             timestamp:
         Thu Nov 27 2014 01:51:47 GMT 0800 (MYT)
         Thu Nov 27 2014 01:53:48 GMT 0800 (MYT)
         Thu Nov 27 2014 01:53:51 GMT 0800 (MYT)

view:

<ion-view title="{{ticksheet.name}}" class="button-positive">
      <ion-content class="has-header" ng-repeat="ticksheetItem in ticksheetItems">
        <div class="row" ng-repeat="ticksheetItem in ticksheetItems" ng-if="$index%2==0" >
            <div class="col col-50" ng-if="$index<ticksheetItems.length" ng-controller="TickCtrl" ng-click="incrementCount(ticksheetItem.$id,ticksheet.$id)">
                <div class="tick-item" style="background-color: #B7E5B0;">
                    <div class="tick-item-row1 row"> 
                        <i class="icon ion-gear-a font-size-l dark col col-10"></i> &nbsp;
                        <strong class="font-size-m col dark">{{ticksheetItems[$index].name}}</strong>
                    </div>
                    <div class="row">
                        <p class="col col-10" ng-controller="TickCtrl">
                            {{count.test}} // I'd like to put the length of the child here
                        </p>
                        <p class="col dark">
                            {{ticksheetItems[$index].description}}
                        </p>
                    </div>
                </div>
            </div>

            <div class="col col-50" ng-if="($index+1)<ticksheetItems.length">
                <div class="tick-item" style="background-color: #514D4F">
                    <div class="tick-item-row1 row"> 
                        <i class="icon ion-settings font-size-l dark col col-10"></i> &nbsp;
                        <strong class="font-size-m col light">{{ticksheetItems[$index+1].name}}</strong>
                    </div>
                    <div class="row">
                        <p class="col col-10">
                                   // I'd like to put the length of the child here
                        </p>
                        <p class="col item-note">
                            {{ticksheetItems[$index+1].description}}
                        </p>
                    </div>
                </div>
            </div>
        </div>
      </ion-content>
    </ion-view>

in my view I have an ng-repeat for the ticksheetItems which I need to display total amount of ticks so I don't know how can I populate the total count of ticks under that certail ticksheet

controller:

//specific ticksheet ctrl
.controller('TicksheetCtrl', function($scope, $rootScope,$firebase, $stateParams) {
  $scope.baseUrl =  $rootScope.baseUrl+'ticksheets/'+ $rootScope.authData.uid + '/' + $stateParams.ticksheetId;

  var ref = new Firebase($scope.baseUrl)
  var ticksheet = $firebase(ref);
  var ticksheetItems = $firebase (ref.child('ticksheetItems'));
  $scope.ticksheet = ticksheet.$asObject();// parent ticksheet
  $scope.ticksheetItems = ticksheetItems.$asArray();//ticksheet Items  
})

.controller('TickCtrl', function($scope, $rootScope,$firebase, $stateParams) {
  $scope.baseUrl = $rootScope.baseUrl + 'ticks/';

  $scope.incrementCount = function(itemId,ticksheetId){

    $rootScope.show('counting up');

    var ref = new Firebase($scope.baseUrl + ticksheetId + '/' + itemId + '/' + new Date()) //didn't use SERVER TIMESTAMP yet

    // adding ticksheet log to 'ticks' record
    var form = {
      timestamp: Firebase.ServerValue.TIMESTAMP,
    }

    ref.push(form,function(){
      $rootScope.hide();
    });

    var ticks = $firebase(ref.parent());
    var tickCount = $firebase(ref.parent()).$asArray();    

    tickCount.$loaded().then(function(sync) {
      console.log(sync.length); 
      console.log(sync[1]);
      console.log('item count' + itemId, $scope.count.itemId)

      $scope.count.test = (sync.length - 1);
      $rootScope.notify('total count for this item is: ' + (sync.length -1) );     
    });

  }
  //$scope.totalCount = I don't know how to populate {{count}} on my view per ticksheet item
})

Please advise. If I have posted the question broadly or unclearly please comment so that I know what to improve. Thanks a lot!

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
Emil Reña Enriquez
  • 2,929
  • 1
  • 29
  • 32
  • Can you add the relevant markup/code from your view and your controller? – Frank van Puffelen Nov 26 '14 at 19:18
  • @FrankvanPuffelen I've updated the question and included the view and controller. I ommitted some codes that I have added lately though. but for this question I think this suffices. Thanks again! – Emil Reña Enriquez Nov 27 '14 at 03:33
  • I am no AngularJS expert, but I think it has no way of knowing that you updated the data in `tickCount.$loaded().then(function(sync) {`. Can you try calling `$scope.$apply()` after you update `$scope.count.test`? – Frank van Puffelen Nov 27 '14 at 13:25

1 Answers1

4

It looks like Angular doesn't update your view after you've calculated the total. You should consider this article mandatory reading for this topic.

Remember the order in which things (are likely to) happen in your code:

  1. your controller gets invoked
  2. your TicksheetCtrl controller binds Firebase promises to the $scope
  3. you TickCtrl controller adds a listener to one of those promises
  4. the controller function completes
  5. Angular updates the views with the values in $scope

And then at some later point:

  1. the data comes available from Firebase
  2. this invokes your $loaded().then( handler
  3. your handler calculates a value and adds it to the $scope

Note that after step 8, Angular doesn't know to update the views.

The solution is simple:

  1. call $scope.$apply() from you handler to tell Angular to apply your changes to the view

Example

I've set up a minimal example to illustrate this problem: http://jsbin.com/wowoni/1/edit?html,js,output

The view:

<div ng-controller='MainCtrl'>
  <h2>static items (from code)</h2>
  <ul>
    <li ng-repeat='item in static'>{{item}}</li>
  </ul>

  <h2>dynamic items (from Firebase)</h2>
  <ul>
    <li ng-repeat='item in dynamic'>{{item}}</li>
  </ul>
</div>

As you can see, the view contains two lists. The first list will show so-called static items, the second list will show items from Firebase.

The controller:

app.controller('MainCtrl', function(FBURL, $scope) {
  $scope.static = [ 'static1', 'static2', 'static3' ];

  var ref = new Firebase(FBURL);
  ref.on('value', function(snapshot) {
    $scope.dynamic = snapshot.val().items;
    $scope.$apply();
  });
});

The $scope.static items will always show, since they're in a function that Angular knows about. The $scope.dynamic items are added to the scope at a time that Angular isn't aware of, so we need to tell Angular to apply our changes with $scope.$apply(). If you remove that line, you'll see that the dynamic items never show up in the rendered output.

AngularFire takes care of applying any changes that come down from Firebase for you, which is why you don't have to call $scope.$apply() for items that you get using $asObject() or $asArray().

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • I gave you an upvote for helping me out. Not quite sure if this can solve though.. I'll check it . Thanks Frank – Emil Reña Enriquez Nov 28 '14 at 04:07
  • If this doesn't answer your question, then I probably misunderstood your question. In that case I recommend that you spend more time on setting up an MCVE in your question. Read http://stackoverflow.com/help/mcve and as that article says "restart from scratch". – Frank van Puffelen Nov 28 '14 at 12:31
  • I think I got it.. thanks for this.. the answer is related to what you mentioned. its not exactly the answer though.. I will post the answer later. – Emil Reña Enriquez Nov 28 '14 at 16:07