2016-07-05 67 views
1

我遇到了绑定工厂和控制器的对象和视图的问题。AngularJS工厂对象没有在控制器和视图上更新

我想获取用户选择的图片的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 
     } 
    } 
})(); 

Finnally上视图:

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

每当我改变事实中的值ory,它在视图中不会改变。

在此先感谢!

回答

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控制器知道去获得新的数据。

防爆指令:

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

+0

在我的指令答案中,当我做'vm.overlay = settingsService.overlay'时,它没有通过更新。只有当我将更新后的值作为函数参数传递时(在$ on中),并执行:$ on(“overlaysUpdate”,function(event,overlays){ vm.overlays = overlays; }); ' 我得到更新的值...这是正常的吗? –

+1

@RafaelLourenco这是正确的,除非您不需要通过$ on传递更新后的值,否则只需在回调完成后再设置vm.overlay = settingsService.overlay即可。原始变量vm.overlay不会自动更新,因为这是单例的性质,需要强制更新,无论您是通过传递$ on还是仅在您从$ on接收回调后重置它。 – Ohjay44

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> 

最后我把一个$发出的settingsServiceoverlay更新:

(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?

希望这可以帮助其他人。

干杯!