Lingbo Tang Lingbo Tang - 3 months ago 89
AngularJS Question

ion-toggle ng-change does not trigger properly with controller + service structure

I've created a list of toggles to select bluetooth devices and connect it, and I've created a controller.js and service.js for them. However, the

ng-change
only triggers when ion-toggles first loaded in view, and were not triggering for changes afterwards.

Here is my snippet of
setting.html
:

<ion-toggle ng-repeat="item in devicesList"
ng-model="item.checked"
ng-change="connectDevice(devicesList)">
{{ item.address }}
</ion-toggle>


and here is my
settingController.js
:

(function () {
'use strict';

angular.module('i18n.setting').controller('SettingController', SettingController);
SettingController.$inject = ['$scope','SettingService'];

function SettingController($scope, SettingService) {
$scope.devicesList = [];
$scope.scanDevices = SettingService.scanDevices($scope.devicesList);
$scope.connectDevice = SettingService.connectDevice($scope.devicesList);
};

})();


and here is my
settingService.js
:

(function(){
'use strict';

angular.module('i18n.setting').service('SettingService', SettingService);

SettingService.$inject = [];
function SettingService(){
var self = this;

this.scanDevices = function(devicesCollection) {
window.bluetoothSerial.discoverUnpaired(function(devices) {
console.log("in discoverUnpaired callback, setting page");
devices.forEach(function(device) {
console.log(device.name);
device.checked = false;
devicesCollection.push(device);
});

}, function(error) {
console.log("in discoverUnpaired error function");
console.log(error);
});
};

this.connectDevice = function(devicesCollection) {
console.log(devicesCollection);
console.log("In connectDevice");
for (var i =0; i<devicesCollection.length; i++)
{
console.log(devicesCollection[i].id + " " + devicesCollection[i].checked);
if (devicesCollection[i].checked == true)
{
console.log(devicesCollection[i].name);
window.bluetoothSerial.connect(devicesCollection[i].address,
function(data) {console.log("This device is"+macaddress); console.log(data);},
function(error) {console.log(error);});
}
}
};
}
})();


And if I define this function directly in
settingController.js
, it's working properly and can detect every change of the toggle. Also, I noticed that my
scanDevices
function will be triggered even if I don't click the button. I don't know why is it. Will there be someone tell me what cause is it? Any help, thanks

Answer

The controller should put the service functions on the scope; not invocations of the service functions.

(function () {
    'use strict';

    angular.module('i18n.setting').controller('SettingController', SettingController);
    SettingController.$inject = ['$scope','SettingService'];

    function SettingController($scope, SettingService) {
        $scope.devicesList = [];
        //$scope.scanDevices = SettingService.scanDevices($scope.devicesList);
        $scope.scanDevices = SettingService.scanDevices;
        //$scope.connectDevice = SettingService.connectDevice($scope.devicesList);
        $scope.connectDevice = SettingService.connectDevice;
    };

})();

Since the scanDevices function has no return statement, scanDevices($scope.deviceList) returns undefined. Thus $scope.scanDevices was getting set to undefined.


Update

Can you also explain why scanDevices get invoked before I press the Scan button?

Which was bind to:

<button class="button button-stable"
        ng-click="scanDevices(devicesList)">Scan Devices
</button>

By binding an invocation of the function to the scope variable instead of the function itself:

//ERRONEOUS
$scope.scanDevices = SettingService.scanDevices($scope.devicesList);

//CORRECT
$scope.scanDevices = SettingService.scanDevices;

The expression SettingService.scanDevices($scope.devicesList) invokes the function before the button is clicked. And assigns undefined to the $scope.scanDevices variable.

Comments