2016-07-05 64 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?

希望這可以幫助其他人。

乾杯!