0

I've got this code:

factory

app.factory('Items', function($firebase,FIREBASE_URL) {
    var ref = new Firebase(FIREBASE_URL);
    var items = $firebase(ref.child('items')).$asArray();
    var Item = {
        all: function () {
          return items;
        },
        create: function (item) {
          return items.$add(item);
        },
        get: function (itemId) {
          return $firebase(ref.child('items').child(itemId)).$asObject();
        },
        update: function (itemId, item) {
          return $firebase(ref.child('items').child(itemId)).update(item);
        },
        delete: function (item) {
          return items.$remove(item);
        }
    };
    return Item;
});

route

app.config(function($stateProvider) {
    $stateProvider      
        .state('items_update', {
            url: '/items/update/:id',
            templateUrl: 'views/items/form.html',
            controller:'ItemsUpdateController',
            resolve:{
                item:function(Items,$stateParams){
                    return Items.get($stateParams.id);
                }
            }
        })
});

controller

app.controller('ItemsUpdateController', function ($scope, item, $state) {
    $scope.item = item;
    console.log($scope.item.url);
    $scope.add = function() {
        Items.update($scope.item).then(function () {
            $state.transitionTo('items');
        });
    }
});

why console.log($scope.item.url); give me undefined ?

but in the view I've got all the data

html

<form class="form-horizontal" role="form" name="form" data-ng-submit="add()">
    <div class="form-group">
        <input type="text" name="title" tabindex="1" class="form-control" placeholder="{{ 'items.form.title' | translate }}" data-ng-model="item.title" required="required" data-ng-minlength="3" data-ng-maxlength="25" user-feedback />
    </div>
    <div class="form-group">
        <input type="text" name="ingredients" tabindex="2" class="form-control" placeholder="{{ 'items.form.ingredients' | translate }}" data-ng-model="item.ingredients" required="required" ng-pattern="/^\w(\s*,?\s*\w)*$/" user-feedback />
    </div>
    <div class="form-group">
        <input type="text" name="price" tabindex="3" class="form-control" placeholder="{{ 'items.form.price' | translate }}" data-ng-model="item.price" required="required" data-smart-float user-feedback />  
    </div>
    <div class="form-group">
        <button type="button" tabindex="4" class="btn btn-default btn-lg" item="item" data-uploader>{{ 'items.form.upload' | translate }}</button>
        <input type="text" name="url" style="display:none;" required="required" data-ng-model="item.url" />
    </div>
    <div class="form-group form-no-required clearfix">
        <div class="pull-right">
            <button type="submit" tabindex="5" class="btn btn-primary" data-ng-disabled="form.$invalid">{{ 'items.form.submit' | translate }}</button>
        </div>
    </div>
</form>

ENDS UP

as in the @Frank van Puffelen comment I worked it out with:

app.controller('ItemsUpdateController', function($scope, item, $state) {
    item.$loaded().then(function(data) {
        $scope.item = data;  
        console.log($scope.item.url);
    });
    $scope.add = function() {
        Items.update($scope.item).then(function() {
            $state.transitionTo('items');
        });
    }
});
Whisher
  • 31,320
  • 32
  • 120
  • 201
  • 1
    This is because by the time your `console.log($scope.item.url);` runs, the data hasn't been loaded from Firebase yet. Angular listens for a notification from Firebase/AngularFire to know when the data has loaded and then updates the view. Also see http://stackoverflow.com/questions/26395912/angularfire-why-cant-i-loop-over-array-returned-by-asarray/26403301#26403301 and http://stackoverflow.com/questions/26268446/trying-to-get-child-records-from-firebase/26277382#26277382. – Frank van Puffelen Oct 29 '14 at 18:24
  • +1 thanks a ton :) usually the promise is done by resolve in ui-router so angularfire doesn't use promise like restangular ? – Whisher Oct 29 '14 at 20:28
  • 1
    AngularFire most definitely uses promises. They just resolve seem to later than you may be used to, likely because the data has to come down from the Firebase server. If you want to wait for the AngularFire promise, do `$scope.item.$loaded().then(function(item) { console.log(item.url); })`. In general: don't waste time trying to make asynchronous code synchronous, work with its async nature and put your functionality behind promises/inside callbacks. – Frank van Puffelen Oct 29 '14 at 20:32
  • @Frank van Puffelen mmm look at the code there is the way when user can click to update a not loaded item so do think is a good idea to put the add function inside $loaded block ? – Whisher Oct 29 '14 at 20:47

1 Answers1

4

This is because by the time your console.log($scope.item.url); runs, the data hasn't been loaded from Firebase yet. Angular listens for a notification from Firebase/AngularFire to know when the data has loaded and then updates the view.

Also see angularfire - why can't I loop over array returned by $asArray? and Trying to get child records from Firebase.

Community
  • 1
  • 1
Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807