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?
希望这对其他人也有帮助。
干杯!
我在绑定工厂对象和控制器及其视图时遇到问题。
我正在尝试获取用户选择的图片的 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?
希望这对其他人也有帮助。
干杯!