2016-07-05 14 views
1

Ich bin mit einem Problem mit der Bindung eines Objekts einer Fabrik und eines Controllers und es ist Sicht.AngularJS Factory-Objekt wird nicht auf Controller und Ansicht aktualisiert

Ich versuche, die DateiUri eines vom Benutzer ausgewählten Bildes zu erhalten. So weit, ist es gut. Das Problem ist, dass ich den Wert dieser Datei auf overlays.dataUrl speichern werde. Aber ich verweise es auf die Ansicht und es wird nicht aktualisiert. (I geprüft und der Wert wird gespeichert tatsächlich auf die overlays.dataUrl Variable

Hier geht den Quellcode 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(); 
    } 
    } 
})(); 

nun den Controller:

(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 
     } 
    } 
})(); 

Zu guter Letzt muss auf der Ansicht:

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

Immer wenn ich den Wert in der Tat ändern Oder, es ändert sich nicht in der Ansicht.

Vielen Dank im Voraus!

Antwort

1

Leider sind Factories in angularjs nicht dazu gedacht, als Zweiwege-Bindungen verwendet zu werden. Fabriken und Dienstleistungen sind nur Singletons. Sie sind nur dort zu verwenden, wenn sie angerufen werden.

Ex Factory:

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; 
}]); 

Ich benutze die $broadcast so, wenn ich getItem mein Controller nennen kennt die neuen Daten holen.

Ex-Richtlinie:

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; 
     }) 
    } 
} 

}]); 

So wie können Sie in meinem obigen Code jederzeit sehen, ich brauche eine frisches item Ich benutze $broadcast und $on zu meinen Dienst und Richtlinie zu aktualisieren. Ich hoffe, dass dies sinnvoll ist, zögern Sie nicht, Fragen zu stellen.

+0

Auf meine Antwort in der Direktive, wenn ich 'vm.overlay = settingsService.overlay' mache es nicht das aktualisierte. Nur wenn ich den aktualisierten Wert als Funktionsargument übergebe (im '$ on'), und mache: ' $ on ("overlaysUpdate", Funktion (Ereignis, Overlays) { vm.overlays = Overlays; }); ' Ich bekomme den aktualisierten Wert ... Ist das normal? –

+1

@RafaelLourenco das ist korrekt, außer Sie müssen den aktualisierten Wert nicht durch Ihre $ on übergeben, wenn Sie nicht möchten, alternativ können Sie einfach vm.overlay = settingsService.overlay erneut einstellen, sobald der Rückruf abgeschlossen ist. Die Originalvariable vm.overlay wird nicht automatisch aktualisiert, da dies die Natur von Singletons ist und gezwungen werden muss, zu aktualisieren, ob Sie das tun, indem Sie $ on übergeben oder nur zurücksetzen, sobald Sie einen Rückruf von $ on erhalten. – Ohjay44

0

Wie von Ohjay44 hingewiesen, ist die Fabrik nicht auf der Ansicht aktualisiert. Der Weg dazu ist eine Direktive (wie Ohjay44 sagte). Um $broadcast, $emit und $on zu verwenden und die Einkapselung zu behalten, tat ich, was von John Papa's Angular Style Guide empfohlen wird: eine Fabrik (in meinem Fall eine nannte es comms).

geht hier die neu erstellte Richtlinie (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; 
      }); 
     } 
    } 
})(); 

I erstellt overlay.directive.html mit:

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

Und schließlich habe ich ein $ auf den settingsService emittieren, wo die overlay aktualisiert:

(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(); 
     } 
    } 
})(); 

Ich habe ein $ emit statt einer Broadcast verwendet, um das Blubbern zu verhindern, wie hier erklärt: What's the correct way to communicate between controllers in AngularJS?

Hoffe das hilft auch jemand anderem.

Prost!

Verwandte Themen