AngularJS Factory对象未在控制器和视图

时间:2016-07-05 20:59:54

标签: angularjs cordova ionic-framework ngcordova

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

我正在尝试获取用户选择的图片的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>

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

提前致谢!

2 个答案:

答案 0 :(得分:1)

不幸的是,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来更新我的服务和指令。我希望这是有道理的,随时提出任何问题。

答案 1 :(得分:0)

正如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>

最后我在settingsService更新overlay的位置放了$ 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?

希望这也有助于其他人。

干杯!