AngularJS 工厂对象未在控制器和视图上更新

AngularJS Factory object not being updated on controller and view

我在绑定工厂对象和控制器及其视图时遇到问题。

我正在尝试获取用户选择的图片的 fileUri。到目前为止,一切都很好。问题是我将该文件的值保存到 overlays.dataUrl。但是我在视图中引用它并且它没有更新。 (我检查了一下,这个值实际上保存到 overlays.dataUrl 变量中。

这里是settings.service.js的源代码:

(function () {
    "use strict";
    angular
    .module("cameraApp.core")
    .factory("settingsService", settingsService);

    settingsService.$inject = ["$rootScope", "$cordovaFileTransfer", "$cordovaCamera"];

    function settingsService($rootScope, $cordovaFileTransfer, $cordovaCamera) {

         var overlays = {
             dataUrl: "",
             options: {
                 sourceType: Camera.PictureSourceType.PHOTOLIBRARY,
                 destinationType: Camera.DestinationType.FILE_URI
             }
         };

         var errorMessages = [];

         var service = {
             overlays: overlays,
             selectOverlayFile: selectOverlayFile,
             errorMessages: errorMessages
         };

         return service;

         function selectOverlayFile() {
             $cordovaCamera.getPicture(overlays.options).then(successOverlay, errorOverlay);
         }

         //Callback functions
         function successOverlay(imageUrl) {
        //If user has successfully selected a file
             var extension = "jpg";
             var filename = getCurrentDateFileName();
             $cordovaFileTransfer.download(imageUrl, cordova.file.dataDirectory + filename + '.' + extension, {}, true)
                 .then(function (fileEntry) {
                      overlays.dataUrl = fileEntry.nativeURL;
                 }, function (e) {
                      errorMessages.push(e);
                 });
    }

    function errorOverlay(message) {
        //If user couldn't select a file
        errorMessages.push(message);
        //$rootScope.$apply();
    }
    }
})();

现在控制器:

(function () {
    angular
    .module("cameraApp.settings")
    .controller("SettingsController", SettingsController);

    SettingsController.$inject = ["settingsService"];

    function SettingsController(settingsService) {
        var vm = this;
        vm.settings = settingsService;

        activate();

        //////////////////

        function activate(){
           // Nothing here yet
        }
    }
})();

终于看到了:

<h1>{{vm.settings.overlays.dataUrl}}</h1>
<button id="overlay" class="button"
                ng-click="vm.settings.selectOverlayFile()">
            Browse...
</button>

每当我更改工厂中的值时,它不会在视图中更改。

提前致谢!

不幸的是,angularjs 中的工厂并不意味着用作双向绑定。工厂和服务只是单身人士。它们仅在调用时使用。

出厂价:

app.factory('itemFactory', ['$http', '$rootScope', function($http, $rootScope) {
var service = {};

service.item = null;

service.getItem = function(id) {
    $http.get(baseUrl + "getitem/" + id)
        .then(function successCallback(resp) {
                service.item = resp.data.Data;
                $rootScope.$broadcast("itemready");
        }, function errorCallback(resp) {
            console.log(resp)
        });
};

return service;
}]);

我使用 $broadcast 所以如果我调用 getItem 我的控制器知道去获取新数据。

Ex 指令:

angular.module("itemApp").directive("item", ['itemFactory', '$routeParams', '$location', '$rootScope', '$timeout', function (itemFactory, $routeParams, $location, $rootScope, $timeout) {
return {
    restrict: 'E',
    templateUrl: "components/item.html",
    link: function (scope, elem, attr) {
        scope.item = itemFactory.item;

        scope.changeMade = function(){
           itemFactory.getItem(1);
        }

        scope.$on("itemready", function () {
            scope.item = itemFactory.item;
        })
    }
}

}]);

因此,正如您在上面的代码中看到的那样,任何时候我都需要一个新的 item 我使用 $broadcast$on 来更新我的服务和指令。我希望这是有道理的,请随时提出任何问题。

正如 Ohjay44 所指出的,工厂未在视图上更新。这样做的方法是使用指令(也如 Ohjay44 所说)。要使用 $broadcast$emit$on 并保持封装,我做了 John Papa's Angular Style Guide 推荐的操作:创建了一个工厂(在我的例子中,将其命名为 comms ).

这是新创建的指令 (overlay.directive.js):

(function () {
    angular
    .module('cameraApp.settings')
    .directive('ptrptSettingsOverlaysInfo', settingsOverlaysInfo);

    settingsOverlaysInfo.$inject = ["settingsService", "comms"];

    function settingsOverlaysInfo(settingsService, comms) {

        var directive = {
            restrict: "EA",
            templateUrl: "js/app/settings/overlays.directive.html",
            link: linkFunc,
            controller: "SettingsController",
            controllerAs: "vm",
            bindToController: true // because the scope is isolated
        };

        return directive;

        function linkFunc(scope, element, attrs, vm) {
            vm.overlays = settingsService.overlays;

            comms.on("overlaysUpdate", function (event, overlays) {
                vm.overlays = overlays;
            });
        }
    }
})();

我用 overlay.directive.html 创建了:

<div class="item item-thumbnail-left">
    <img ng-src="{{vm.overlays.dataUrl}}">
    <h2>{{vm.overlays.dataUrl}}</h2>
</div>

最后,我在 overlay 更新的 settingsService 上放置了一个 $emit:

(function () {
"use strict";
angular
.module("cameraApp.core")
.factory("settingsService", settingsService);

settingsService.$inject = ["comms", "$cordovaFileTransfer", "$cordovaCamera"];

function settingsService(comms, $cordovaFileTransfer, $cordovaCamera) {

         var overlays = {
             dataUrl: "",
             options: {
                 sourceType: Camera.PictureSourceType.PHOTOLIBRARY,
                 destinationType: Camera.DestinationType.FILE_URI
             }
         };

         var errorMessages = [];

         var service = {
             overlays: overlays,
             selectOverlayFile: selectOverlayFile,
             errorMessages: errorMessages
         };

         return service;

         function selectOverlayFile() {
             $cordovaCamera.getPicture(overlays.options).then(successOverlay, errorOverlay);
         }

         //Callback functions
         function successOverlay(imageUrl) {
        //If user has successfully selected a file
             var extension = "jpg";
             var filename = getCurrentDateFileName();
             $cordovaFileTransfer.download(imageUrl, cordova.file.dataDirectory + filename + '.' + extension, {}, true)
                 .then(function (fileEntry) {
                      overlays.dataUrl = fileEntry.nativeURL;
                      // New code!!!!
                      comms.emit("overlaysUpdated", overlays);
                 }, function (e) {
                      errorMessages.push(e);
                 });
        }

        function errorOverlay(message) {
            //If user couldn't select a file
            errorMessages.push(message);
            //$rootScope.$apply();
        }
    }
})();

我使用 $emit 而不是广播来防止冒泡,如下所述:What's the correct way to communicate between controllers in AngularJS?

希望这对其他人也有帮助。

干杯!