firebase get data for every child item's child

2019-03-02 13:43发布

问题:

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!

回答1:

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().