Set up Three-way data binding in angularjs with angularfire

AngularFire takes it a notch further by introducing three-way data binding, whereby it is able to detect local changes, so we don’t even have to call $save(). We just have to call $bindTo() on a synchronized object and any changes in the DOM are pushed to Angular and finally to Firebase. Conversely, any changes to the data get pushed to Angular and finally to the DOM.

So let’s see it in action. The code for this example is very similar to the one we used in the synchronized arrays example, with a few changes. Here’s the modified app.js file:

app.config(function ($routeProvider) {
  $routeProvider
    .when('/', {
      templateUrl: 'main.html'
    })
    .when('/buildings', {
      templateUrl: 'building/buildings.tpl.html',
      controller: 'BuildingsCtrl'
    })
    .when('/buildings/:buildingIndex', {
      templateUrl: 'building/building.tpl.html',
      controller: 'BuildingCtrl'
    })
    .otherwise({
      redirectTo: '/'
    });
});
(dunebook\three-way-binding\app.js)

 

Notice here how we are configuring the second route with /buildings/:buildingIndex. :buildingIndex is the variable part of the URL.

The following code is part of the template file which constructs this variable URL:

<tr ng-repeat="(id, building) in buildings">
<td>
<a href="#/buildings/{{id}}">{{building.buildingNumber}}</a>
</td>
<td>{{building.buildingName}}</td>
</tr>

(dunebook\three-way-binding\building\buildings.tpl.html)

When showing the buildings using ng-repeat, we pass {{id}} to href to construct the dynamic URL. The service is pretty straightforward:

app.factory("buildingSvc", ['FIREBASE_URI', '$firebaseArray', '$firebaseObject',
  function(FIREBASE_URI, $firebaseArray, $firebaseObject) {
    var buildingsUri = FIREBASE_URI + '/buildings';
    var buildingsRef = new Firebase(buildingsUri);
    var buildings = $firebaseArray(buildingsRef);

    var getBuildings = function () {
      return buildings;
    };

    var getBuilding = function (index) {
      var key = buildings.$keyAt(index);
      var buildingRef = buildingsRef.child(key);
      return $firebaseObject(buildingRef);
    };

    return {
      getBuildings: getBuildings,
      getBuilding: getBuilding
    }
}]);
(dunebook\three-way-binding\building\buildings.svc.js)

 

The only interesting part is the getBuilding function, which takes a building index, gets its key, and creates a Firebase reference for the relative path of that particular building by calling the child function and passing in the key. Then we create a synchronized object for that building using $firebaseObject. BuildingsCtrl is very straightforward, so here’s the maybe more interesting BuildingCtrl:

app.controller('BuildingCtrl', ['$scope', '$routeParams', 'buildingSvc',
  function ($scope, $routeParams, buildingSvc) {

    var hasAnError = false;

    $scope.hasError = function () {
      return hasAnError;
    };

    if ($routeParams.buildingIndex !== null) {
      var index = parseInt($routeParams.buildingIndex);

      if (!isNaN(index)) {
        // create a three-way binding to our building as $scope.building
        buildingSvc.getBuilding(index).$bindTo($scope, "building");
      }
      else {
        hasAnError = true;
      }
    }
  }
]);

(dunebook\three-way-binding\building\building.ctl.js)

The $routeParams service is injected in the controller. It allows us to retrieve the current set of route parameters. Since we had specified :buildingIndex as a route parameter (while setting up our routes), we retrieve it using $routeParams.buildingIndex. The buildingSvc service is also injected and the index (of the building) is passed to this service, which returns a synchronized object to us. Finally, we bind the returned synchronized object to $scope using the $bindTo method. The first argument to this method is $scope and the second is the name of the variable which we want to appear on $scope. Since the value of the second argument here is building, $scope.building is available to the view(s):

<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">Update building</h3>
</div>
<div class="panel-body">
<form>
<div class="form-group">
<label for="number">Building Number</label>
<input type="number" class="form-control" id="number"
  ng-model="building.buildingNumber" placeholder="Enter building number">
</div>
<div class="form-group">
<label for="name">Building Name</label>
<input type="text" class="form-control" id="name"
  ng-model="building.buildingName" placeholder="Enter building name">
</div>
</form>
</div>
</div>

(dunebook\three-way-binding\building\buildings.tpl.html)

When you click on any of the building number links on the existing buildings page, you’ll see the data for that building reflected in the two input textboxes on the update building page. Also, notice that there is no Submit button for this form and we are not even calling $save() anywhere. Now these textboxes are bound directly to Firebase and sync their changes with Firebase automatically. So, if you make any changes to the data, that data will automatically be saved to Firebase.

Note

Although three-way data bindings are extremely convenient, we should be careful while using these with deeply-nested data structures. For performance reasons, their use should be limited to synchronizing key-value pairs which don’t get changed by too many users.

Deven Rathore

Deven is an Entrepreneur, and Full-stack developer, Constantly learning and experiencing new things. He currently runs CodeSource.io and Dunebook.com.

Published by
Deven Rathore
Tags: angularjs

Recent Posts

Are There any Similarities Between Web Design and Art?

You may be surprised at how many of the same skills are involved!  Let’s get…

1 day ago

Tips on Increasing your organic traffic on WordPress

Introduction  As more and more people are using online services nowadays, most of the business…

2 days ago

Five Reasons You Should Start a Social Media Campaign

Small businesses need all the advertisements they can get. Traditional avenues for advertising, such as…

3 days ago

Top 10 SEO Writing Tips for Beginners 2021

Search Engine Optimization. It’s complicated, to say the least. Search engines, like Google, are constantly…

2 weeks ago

Should you become a freelancer in 2021? Pros and Cons

Freelancing and working from home was long considered idyllic by many, but the global pandemic…

2 weeks ago

The Leading Renewable Energy Trends in 2021

The past year saw slowdowns in the ongoing shift toward renewable energy in many countries…

2 weeks ago