1

I'm a beginner to angularjs. In my NFC project, I want to be able to GET from the server data based on a changing patientId.

However, I am not able to see my $watch execute correctly, even though I see that the patientId changes each time I scan a new NFC tag.

var nfc = angular.module('NfcCtrl', ['PatientRecordsService'])

nfc.controller('NfcCtrl', function($scope,  NfcService, PatientRecordsService) {
    $scope.tag = NfcService.tag;
    $scope.patientId = NfcService.patientId
    $scope.$watch(function() {
        return NfcService.patientId;
    }, function() {
        console.log("Inside watch");

        PatientRecordsService.getPatientRecords(NfcService.patientId)
        .then(
            function(response) {
                $scope.patientRecords = response
            },
            function(httpError) {
                throw httpError.status + " : " +
                    httpError.data;
            });
    }, true);
    $scope.clear = function() {
        NfcService.clearTag();
    };
});

nfc.factory('NfcService', function($rootScope, $ionicPlatform, $filter) {

    var tag = {};
    var patientId = {};

    $ionicPlatform.ready(function() {
        nfc.addNdefListener(function(nfcEvent) {
            console.log(JSON.stringify(nfcEvent.tag, null, 4));
            $rootScope.$apply(function(){
                angular.copy(nfcEvent.tag, tag);
                patientId = $filter('decodePayload')(tag.ndefMessage[0]);
            });
            console.log("PatientId: ", patientId);
        }, function() {
            console.log("Listening for NDEF Tags.");
        }, function(reason) {
            alert("Error adding NFC Listener " + reason);
        });
    });

    return {
        tag: tag,

        patientId: patientId,

        clearTag: function () {
            angular.copy({}, this.tag);
        }
    };

});

Not sure what I'm missing here - please enlighten me!

Update Per rakslice's recommendation, I created an object to hold my data inside the factory, and now the html (with some server side delay) correctly displays the updated values when a new NFC tag is scanned.

var nfc = angular.module('NfcCtrl', ['PatientRecordsService'])

nfc.controller('NfcCtrl', function($scope,  NfcService) {
    $scope.tagData = NfcService.tagData;
    $scope.clear = function() {
        NfcService.clearTag();
    };
});

nfc.factory('NfcService', function($rootScope, $ionicPlatform, $filter, PatientRecordsServi\
ce) {

    var tagData = {
        tag: null,
        patientId: null,
        patientRecords: []
    };

    $ionicPlatform.ready(function() {
        nfc.addNdefListener(function(nfcEvent) {
            //console.log(JSON.stringify(nfcEvent.tag, null, 4));
            $rootScope.$apply(function() {
                tagData.tag = nfcEvent.tag;
                tagData.patientId = $filter('decodePayload')(tagData.tag.ndefMessage[0]);
                PatientRecordsService.getPatientRecords(tagData.patientId)
                    .then(
                        function(response) {
                            tagData.patientRecords = response
                        },
                        function(httpError) {
                            throw httpError.status + " : " +
                                httpError.data;
                        });
            });
            console.log("Tag: ", tagData.tag);
            console.log("PatientId: ", tagData.patientId);
        }, function() {
            console.log("Listening for NDEF Tags.");
        }, function(reason) {
            alert("Error adding NFC Listener " + reason);
        })
    });

    return {
        tagData: tagData,
        clearTag: function() {
            angular.copy({}, this.tagData);
        }
    };
});
Jason Choi
  • 113
  • 1
  • 1
  • 7

1 Answers1

0

Your code doesn't update the patientId value in the returned NfcService, only the local variable patientId inside the factory function.

Try saving a reference to the object you're returning in the factory function as in a local variable and use that to update the patientId.

For instance, change the creation of the object to put it in a local variable:

var nfcService = {
        tag: tag,

        patientId: patientId,

        clearTag: function () {
            angular.copy({}, this.tag);
        }
    };

...

return nfcService

and then change the patientId update to change the value in the object through the variable.

nfcService.patientId = $filter('decodePayload')(tag.ndefMessage[0]);

Update:

The basic fact about JavaScript that you need to understand is that when you assign one variable to another, if the first variable had a primitive data value the second variable gets a copy of that value, so changing the first variable doesn't affect the second variable after that, but if the first variable had an object reference the second variable gets pointed at that same object that the first variable is pointed at, and changing the object in the first variable after that will affect what you see through the second variable, since it's looking at the same object.

A quick experiment in the browser JavaScript console should give you the idea:

> var a = 1;
> a
1
> var b = a;
> b
1
> a = 5;
> a
5
> b
1

vs.

> var a = {foo: 1}
> var b = a
> a.foo = 5
> a.foo
5
> b.foo
5
rakslice
  • 8,742
  • 4
  • 53
  • 57
  • I'll give this a try, but I don't understand then how the `tag` variable gets updated successfully (at least this is what I see when I use it in an html page) – Jason Choi Apr 17 '16 at 04:16
  • Unlike `patientId`, which you're assigning a new value to, with `tag` you're not assigning a new value to the variable, you're using `angular.copy()` on it, which changes the object that it is pointing to. Since that's the same object that the `tag` in the returned `NfcService` is pointing to, code using that `NfcService` will see the change. This is just the regular old JavaScript primitive data vs. object reference behaviour: http://stackoverflow.com/a/13266769/60422 – rakslice Apr 17 '16 at 05:05
  • 1
    Thanks for the explanation. By creating a object and moving http GET requests into the factory, I was able to eliminate the need for `$watch` in the controller entirely. – Jason Choi Apr 18 '16 at 06:19