Question

I am attempting to build a proof of concept application using AngularJS and Jaydata. I am loosely following the MVC pattern on the AngularJS home page (http://angularjs.org/) under "Wire up a Backend". Instead of Firebase, I'm using WebSQL via Jaydata providers.

I have a WebSQL database called InspecTechDB with two tables, Organizations and Customers. There is a parent/child relationship between the two on OrganizationID. This is from my model:

    $data.Entity.extend('Customer', {
        'CustomerID': { 'key': true, 'type': 'Edm.Guid', 'nullable': false },
        'OrganizationID': { 'type': 'Edm.Guid', 'nullable': false, 'required': true },
        'CustomerName': { 'type': 'Edm.String' },
        'Organization': { 'type': 'Organization', 'inverseProperty': '$$unbound' }
    });
    $data.Entity.extend('Organization', {
        'OrganizationID': { 'key': true, 'type': 'Edm.Guid', 'nullable': false, 'required': true },
        'OrganizationName': { 'type': 'Edm.String' },
        'Customers': { 'type': 'Array', 'elementType': 'Customer', 'inverseProperty': '$$unbound' }
    });
    $data.EntityContext.extend('InspecTechDB', {
        'Customers': { type: $data.EntitySet, elementType: Customer },
        'Organizations': { type: $data.EntitySet, elementType: Organization }
    });

I have 3 template views: OrganizationIndex.html, CustomerIndex.html, and CustomerEdit.html. The CustomerEdit.html is the one I'm having issues with:

<form name="myForm">
    <div class="form-group">
        <label>OrganizationID</label>
        <input type="text" class="form-control" placeholder="OrganizationID" name="OrganizationID" ng-model="customer.OrganizationID" required>
        <span ng-show="myForm.name.$error.required" class="help-inline">
            Required
        </span>
    </div>

    <div class="form-group" ng-class="{error: myForm.name.$invalid}">
        <label>Name</label>
        <input type="text" class="form-control" name="CustomerName" ng-model="customer.CustomerName" required>
        <span ng-show="myForm.name.$error.required" class="help-inline">
            Required
        </span>
    </div>
</form>

I've included my entire js file here:

var app = angular.module('AngularJaydataApp', ['ngRoute', 'jaydata']);
app.config(function ($routeProvider) {
    $routeProvider
      .when('/', {
          controller: 'OrganizationIndex',
          templateUrl: 'OrganizationIndex.html'
      })
      .when('/CustomerIndex/:id', {
          controller: 'CustomerIndex',
          templateUrl: 'CustomerIndex.html'
      })
      .when('/CustomerEdit/:id', {
          controller: 'CustomerEdit',
          templateUrl: 'CustomerEdit.html'
      })
      .otherwise({
          redirectTo: '/'
      });
});

var localDB = new InspecTechDB({
    name: 'local',
    databaseName: 'InspecTech'
});

app.controller('OrganizationIndex', function ($scope, $data){    

    //wait until the localDB is ready, then get the Organizations
    $.when(localDB.onReady())
    .then(function () {
        $scope.inspectechdb = localDB;
        $scope.organizations = localDB.Organizations.toLiveArray();
    });

});

app.controller('CustomerIndex', function ($scope, $data, $routeParams) {

    $.when(localDB.onReady())
        .then(function () {
            $scope.inspectechdb = localDB;
            $scope.Customers = $scope.inspectechdb
                  .Customers
                  .filter('OrganizationID', '==', $routeParams.id)
                  .toLiveArray();
        });

});

app.controller('CustomerEdit', function ($scope, $data, $routeParams) {

    var customerID = $routeParams.id;

    $.when(localDB.onReady())
        .then(function () {
            $scope.inspectechdb = localDB;
            $scope.inspectechdb.Customers.single(function (customer) {
                return customer.CustomerID == this.Id;
            },
            {Id: customerID},
            function (customer) {
                $scope.customer = customer;
                console.dir(customer);
            });
        });

    console.log('this entry s/b after the customer console entry');

});

I can successfully navigate to each of the views and populate the OrganziationList.html template from my database as shown in the above code. I've set the Organization list up so that when I click the Organization entry on my view then the CustomerIndex.html view is loaded and bound to my customer list. This works fine. I've also set it up so that when I click a customer entry on the CustomerIndex view then the CustomerEdit.html view is loaded and here is where I get lost. The view appears just fine, but the form is not bound when the view is loaded, and I understand why (I think). It seems to be b/c angular is binding the form before my $scope.customer is populated. Evidence of this is the console log:

this entry s/b after the customer console entry bind.js:68

Customer

My question is this: Why do the OrganzationList and CustomerList views populate correctly and the CustomerEdit form does not and what can be done about it?

UPDATE For anyone interested, I made it work by modifying the CustomerEdit controller per the accepted answer:

app.controller('CustomerEdit', function ($scope, $data, $routeParams) {

    var customerID = $routeParams.id;

    $.when(localDB.onReady())
    .then(function () {
        $scope.inspectechdb = localDB;
        $scope.inspectechdb.Customers.single(function (customer) {
            return customer.CustomerID == this.Id;
        },
        { Id: customerID },
        function (customer) {
            $scope.$apply(function () {
                $scope.customer = customer;
            });
        });
    });

});
Was it helpful?

Solution

Angular has no idea that it should update the form. When you call tolivearray jaydata manages this for you. Calling single does not. One way of solving it is that you call apply yourself when you updated the scope. A better way would be to pass the entity instead of loading it, since it's already loaded.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top