0

I have a problem with the AngularJS two-way data binding. I'll try to explain the issue as clearly as possible: I have a list of contact names. For each element I have an Edit button. When I click on that button I load the "clicked" full Contact from an Ajax call and then I show a window with some input fields linked to the Contact just retrieved ("phone", "email" etc.). This is the interesting piece of the view:

<div>    
    <div class="contact" data-ng-repeat="contact in contacts">
        <span>{{contact.label}}</span>
        <a href="" class="btn btn-xs btn-default" data-ng-click="openContactModal(contact.ID)">
            Edit
        </a>
    </div>
</div>

The click on the Edit button fires this function (present in the Controller):

var newContact = null;
$scope.openContactModal = function(contactID){  
    newContact = new Contact(contactID);
    newContact.onLoad().then(
        function(){
            //loading OK
            $('#myModal').modal('show');
        },
        function(){
            //loading Error

        }
    );
    $scope.newContact = newContact;
};

The call to new Contact(contactID) loads a contact from the Database with an Ajax call. I open the modal window at the end of the Ajax call (waiting for the AngularJS promise). In the modal, though, all fields are empty even though they are linked to the contact model (newContact.phone, newContact.email etc.). I've already checked that the Ajax call works fine (printing the resulted JSON). I suppose I'm missing something in the two-way data binding issue. The strange fact is that, if I try to fill the empty modal fields, the newContact model reacts well, as if the two-way data binding works well from the view to the model, but not the contrary. Thank you in advance!

EDIT: this is the service that retrieves the contact:

angular.module("app").factory("Contact", ["ContactDBServices", "$q",
    function(ContactDBServices, $q){
        return function(contactID){

            //the contact itself
            var self = this;

            var contactPromise = $q.defer();

            //attributi del contatto
            this.firstName = null;
            this.ID = null;
            this.lastName = null;
            this.phone = null;
            this.fax = null;
            this.mobile = null;
            this.email = null;
            this.web = null;

            //the Ajax call    
            var metacontact = ContactDBServices.find({ID:contactID}, 
                function(){
                    this.ID = contactID;
                    this.firstName = metacontact.contact_name;
                    this.lastName = metacontact.contact_last_name;
                    this.phone = metacontact.contact_phone;
                    this.fax = metacontact.contact_fax;
                    this.mobile = metacontact.contact_mobile;
                    this.email = metacontact.contact_email;
                    this.web = metacontact.contact_web;

                    //!!!THE FOLLOWING PRINTS ARE GOOD!!!!  
                    console.log(this.ID);
                    console.log(this.firstName);
                    console.log(this.lastName);
                    console.log(this.phone);
                    console.log(this.fax);
                    contactPromise.resolve("OK");
                },
                function(){
                    contactPromise.reject("Error");
                }
            );


            this.onLoad = function(){
                return contactPromise.promise;
            };

    }
}]);  

If I print the same values in the controller, though, all that values are undefined:

var newContact = null;
$scope.openContactModal = function(contactID){  
    newContact = new Contact(contactID);
    newContact.onLoad().then(
        function(){

            //!!!!!!!!THE FOLLOWING PRINTS ARE ALL UNDEFINED!!!!
            console.log(newContact.firstName);
            console.log(newContact.lastName);
            console.log(newContact.phone);
            console.log(newContact.fax);

            $('#myModal').modal('show');
        },
        function(){
            //loading Error

        }
    );
    $scope.newContact = newContact;
};

This is strange. It seems a sort of synchronization issue :-/ to be thorough here is an example piece of the modal:

<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
    <div class="modal-dialog modal-sm">
        <div class="modal-content">
            <div class="modal-header">
                <h2>Contact</h2>
            </div>
            <div class="modal-body">
                <label>
                    Name
                    <input class="form-control" id="new_contact_name" data-ng-model="newContact.firstName" placeholder="Name">
                </label>
                <!-- ...and so on -->
            </div>
        </div>
        <div class="modal-footer">
            <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
            <button type="button" class="btn btn-primary" data-dismiss="modal" data-ng-click="createContact()">Crea</button>
        </div>
    </div>
</div>

superpuccio
  • 11,674
  • 8
  • 65
  • 93
  • is `newContact.onLoad()` correct? – dmullings Jun 19 '14 at 14:05
  • 1
    Yes, it is a function that returns an angular promise. The modal is shown properly at the end of the Ajax call and the Json retrieved contains the right values, but that values aren't "two-way data binded" with the view. – superpuccio Jun 19 '14 at 14:48
  • 1
    How is your modal wired? Does its controller share the `$scope` object that you're populating with `newContact`? – Palpatim Jun 19 '14 at 15:19
  • 1
    The html page where the modal is contained has a unique controller called "customerController". The modal shares the $scope with the entire page. – superpuccio Jun 19 '14 at 18:31
  • 1
    I've just edited my question, maybe now is more complete. Thank you for your help. – superpuccio Jun 20 '14 at 07:58
  • Guys thank you, but it's an error of mine, clearly. I'll write an answer to be thorough as soon as possible. – superpuccio Jun 20 '14 at 09:45

1 Answers1

0

Eventually I found the mistake. It was a mistake of mine and it doesn't belong to AngularJS, but to Javascript: you'll note that, in the Contact service, I did:

//the Ajax call    
var metacontact = ContactDBServices.find({ID:contactID}, 
    function(){
        this.ID = contactID;
        this.firstName = metacontact.contact_name;
        this.lastName = metacontact.contact_last_name;
        this.phone = metacontact.contact_phone;
        this.fax = metacontact.contact_fax;
        this.mobile = metacontact.contact_mobile;
        this.email = metacontact.contact_email;
        this.web = metacontact.contact_web;

    },
    function(){
        contactPromise.reject("Error");
    }
);

clearly, writing this. in the callback function, I didn't affect the Contact values, but the function attributes! To solve this issue I had to change the callback this way:

//the Ajax call    
var metacontact = ContactDBServices.find({ID:contactID}, 
    function(){
        self.ID = contactID;
        self.firstName = metacontact.contact_name;
        self.lastName = metacontact.contact_last_name;
        self.phone = metacontact.contact_phone;
        self.fax = metacontact.contact_fax;
        self.mobile = metacontact.contact_mobile;
        self.email = metacontact.contact_email;
        self.web = metacontact.contact_web;

    },
    function(){
        contactPromise.reject("Error");
    }
);

where

var self = this;

outside the callback.

superpuccio
  • 11,674
  • 8
  • 65
  • 93