I have a service with the following:
.service('TasksService', function ($http) {
return $http.jsonp('http://blabla/json/?callback=JSON_CALLBACK');
});
My controller:
.controller("TasksCtrl", function ($scope, TasksService) {
TasksService.then(function (TasksService) {
$scope.Tasks = TasksService;
});
});
This shows list with many items.
But I have another service and another controller. I change an item there and when I save and post data to database and I get back to initial list, I still see the old listed items. I must refresh the browser to see what I have edited.
In the second controller I have save function with this:
$scope.saveTask = function () {
$http.post('http://blabla', $scope.Task.data).then(function (data) {
// This shows the very first state with all the listed items
$state.go('tasks');
});
};
When I save the changes and state.go() shows me the first screen I do not know why the data is not with the new changes from the service returned data. It seems like the screen is just changed but the new data is not returned from the service. Any ideas how to fix this?
I got it working. I changed my service and controller. In my service I returned an object with another method and then I changed my controller also to use the returned method.
The service:
.service('TasksService', function ($http) {
return {
getTasks: function() {
return $http.jsonp('http://blabla/json/?callback=JSON_CALLBACK');
}
};
});
And the controller:
.controller("TasksCtrl", function ($scope, TasksService) {
TasksService.getTasks().then(function (data) {
$scope.Tasks = data;
});
});
Now it is working and I see the items list the new saved and returned data. Thank you!
All you need is to reflect the changed data into your html
Angular has a method for this
$scope.$apply();
This method works both with parameters as well as without parameters.
Hope this helps.
Related
I have a controller that looks something like this:
(function () {
"use strict";
angular.module("app")
.controller("postsController", postsController);
function postsController($scope, $http, $uibModal, PostService) {
var vm = this;
$scope.posts = [];
PostService.getPosts()
.then(function (p) {
$scope.posts = p.data;
}, function (error) {
vm.errorMessage = "Failed to load data: " + error;
});
$scope.$watchCollection('posts', function(newPosts, oldPosts) {
PostService.getPosts();
});
}
})();
The original data is pulled from the service and the posts array is populated properly. However, I am have trouble having the view refreshed if data in the array has changed. Either nothing happens on the view, or I am seeing an infinite loop with the $watch.
Any help is greatly appreciated.
Why get infinite loop:
$scope.$watchCollection('posts',function(){...}) watched your post array, when you refresh your view and post changed, watch listener triggered.
Then listener do PostService.getPosts();, resolve with $scope.posts = p.data;, this also change the post ( more: post been set back to data from backend, that's why nothing changed in your view), then watch listener triggered again. Then do PostService.getPosts(); again, then again and again.
So you get a infinite loop.
I have an angular project. I am making an html/angular form - getting the data from a stored procedure via $http get in a service in angular. Now I want to databind some of the drop down lists in my filter that's in this html form. I have the data in a view which I made models for and added to the entity framework. How should I make calls to this breeze in angular? Code example please? in service or in controller?
------here's what i've tried--------------
what am I doing wrong here? (may be a few things...i'm new to angular. Then I just want to be able to somehow call this function populatestyleddl in my ng-model or something....
.factory('sellingService', ['$filter', '$http', function ($filter, $http) {
function PopulateStyleDDL() {
return breeze.EntityQuery.fromEntityNavigation('v_Style')
.using(context.manager).execute();
};
//check if above function is legal
function SalesStatus(filter) {
console.log(breeze);
return $http({
method: 'GET',
url: '/Services/SalesStatus',
params: { filter.itemStyle }
}).then(function (result)
{ return result.data; })
}
return {
SalesStatus: SalesStatus
};
}]);
--------------------------------here's what i have now.....
ok, here is what i've got now. this is happening in a js file where all my breeze calls are. Can you confirm if my syntax here is right and how my function syntaxically should look in my factory (and also how my syntax should look in my controller...)
function GetStyles() { return breeze.EntityQuery .from("v_Style") .using(manager) .execute(); }
#LisaSolomon, regarding your syntax:
function GetStyles() {
return breeze.EntityQuery
.from("v_Style")
.using(manager)
.execute();
}
Looks good with the information I have. If it's not working I'd make sure:
The controller has a properly-defined v_Style action, and
The manager is defined and has the correct service name
So, assuming that is correct, you will need to add it to your returned object so that it is available in your controller:
return {
SalesStatus: SalesStatus,
GetStyles: GetStyles
};
Then to use it in your controller, you will need to reference the .then() of the promise
$scope.styles = '';
sellingService.GetStyles().then(function(data) {
$scope.styles = data.results;
}).catch(function(err) {
// error processing
});
Any error messages you're getting would be helpful. If there's any chance you could show controller and view code so we could build a fiddle, that would be great, too.
I am writing a small Angular web application and have run into problems when it comes to loading the data. I am using Firebase as datasource and found the AngularFire project which sounded nice. However, I am having trouble controlling the way the data is being displayed.
At first I tried using the regular implicit synchronization by doing:
angularFire(ref, $scope, 'items');
It worked fine and all the data was displayed when I used the model $items in my view. However, when the data is arriving from the Firebase data source it is not formatted in a way that the view supports, so I need to do some additional structural changes to the data before it is displayed. Problem is, I won't know when the data has been fully loaded. I tried assigning a $watch to the $items, but it was called too early.
So, I moved on and tried to use the angularfireCollection instead:
$scope.items = angularFireCollection(new Firebase(url), optionalCallbackOnInitialLoad);
The documentation isn't quite clear what the "optionalCallbackOnInitialLoad" does and when it is called, but trying to access the first item in the $items collection will throw an error ("Uncaught TypeError: Cannot read property '0' of undefined").
I tried adding a button and in the button's click handler I logged the content of the first item in the $items, and it worked:
console.log($scope.items[0]);
There it was! The first object from my Firebase was displayed without any errors ... only problem is that I had to click a button to get there.
So, does anyone know how I can know when all the data has been loaded and then assign it to a $scope variable to be displayed in my view? Or is there another way?
My controller:
app.controller('MyController', ['$scope', 'angularFireCollection',
function MyController($scope, angularFireCollection) {
$scope.start = function()
{
var ref = new Firebase('https://url.firebaseio.com/days');
console.log("start");
console.log("before load?");
$scope.items = angularFireCollection(ref, function()
{
console.log("loaded?");
console.log($scope.items[0]); //undefined
});
console.log("start() out");
};
$scope.start();
//wait for changes
$scope.$watch('items', function() {
console.log("items watch");
console.log($scope.items[0]); //undefined
});
$scope.testData = function()
{
console.log($scope.items[0].properties); //not undefined
};
}
]);
My view:
<button ng-click="testData()">Is the data loaded yet?</button>
Thanks in advance!
So, does anyone know how I can know when all the data has been loaded
and then assign it to a $scope variable to be displayed in my view? Or
is there another way?
Remember that all Firebase calls are asynchronous. Many of your problems are occurring because you're trying to access elements that don't exist yet. The reason the button click worked for you is because you clicked the button (and accessed the elements) after they had been successfully loaded.
In the case of the optionalCallbackOnInitialLoad, this is a function that will be executed once the initial load of the angularFireCollection is finished. As the name implies, it's optional, meaning that you don't have to provide a callback function if you don't want to.
You can either use this and specify a function to be executed after it's loaded, or you can use $q promises or another promise library of your liking. I'm partial to kriskowal's Q myself. I'd suggest reading up a bit on asynchronous JavaScript so you get a deeper understanding of some of these issues.
Be wary that this:
$scope.items = angularFireCollection(ref, function()
{
console.log("loaded?");
console.log($scope.items[0]); //undefined
});
does correctly specify a callback function, but $scope.items doesn't get assigned until after you've ran the callback. So, it still won't exist.
If you just want to see when $scope.items has been loaded, you could try something like this:
$scope.$watch('items', function (items) {
console.log(items)
});
In my project I needed to know too when the data has been loaded. I used the following approach (implicit bindings):
$scope.auctionsDiscoveryPromise = angularFire(firebaseReference.getInstance() + "/auctionlist", $scope, 'auctionlist', []);
$scope.auctionsDiscoveryPromise.then(function() {
console.log("AuctionsDiscoverController auctionsDiscoveryPromise resolved");
$timeout(function() {
$scope.$broadcast("AUCTION_INIT");
}, 500);
}, function() {
console.error("AuctionsDiscoverController auctionsDiscoveryPromise rejected");
});
When the $scope.auctionsDiscoveryPromise promise has been resolved I'm broadcasting an event AUCTION_INIT which is being listened in my directives. I use a short timeout just in case some services or directives haven't been initialized yet.
I'm using this if it would help anyone:
function getAll(items) {
var deferred = $q.defer();
var dataRef = new Firebase(baseUrl + items);
var returnData = angularFireCollection(dataRef, function(data){
deferred.resolve(data.val());
});
return deferred.promise;
}
I have looked, and assume this is simple, but just couldn't figure out the API documentation for this.
Assume I have a controller that pulls data when first called (I'm leaving out a ton, of course):
myCtrl = function ($scope, Data) {
$scope.data = [];
data_promise = Data.getData(); //a $http service
data_promise.success(function (data) {
$scope.data = data;
});
}
That works great, and when the page loads I get $scope.data populated exactly as I need it. However, of course, the user may wish to update the data. Assume a simple service "Data.save()" called when a server clicks a "save" button on a form:
myApp.factory('Data', function ($http) {
save: function (data) {
$http({
method: 'POST',
url: 'someURL',
data: data,
}).success(function(){
//something here that might trigger the controller to refresh
});
};
});
What would I put in the success callback that might re-instantiate the controller so that it has the most up-to-date data from the server? Currently I am having to refresh the page to get the updated data. I am not worried right now about minimizing server calls by cashing results and changes. I just need to get this to work first.
Thanks!
You do not need to refresh. Simply change the updated data in the ControllerScope.
This should work.
myApp.factory('Data', function ($http) {
save: function (data, $scope) {
$http({
method: 'POST',
url: 'someURL',
data: data,
}).success(function(){
$scope.data = newData;
//something here that might trigger the controller to refresh
});
};
});
// in your controller
Data.save(data, $scope);
But: You shouldn't do this way. This looks messy. Use services or events which you watch to wait for the changes comming back from the service.
OK, although I am sure there is a better answer I have one for me. Essentially I am taking the important parts of the controller and placing them in the success callback. In order to keep it from looking messy, I have wrapped all the parts of the controller that need be updated in a named function.
myCtrl = function ($scope, Data, $q) {
// Binding the Data
var updateAll;
updateAll = function () {
$scope.data1 = [];
$scope.data2 = [];
$scope.data3 = [];
$scope.data4 = [];
service_promise1 = Data.getData1(); //a $http service
service_promise2 = Data.getData2();
service_promise3 = Data.getData3();
service_promise4 = Data.getData4();
$q.all([service_promise1,service_promise2,service_promise3,service_promise4])
.then(function([service1,service2,service3,service]){
$scope.data1 = service1 + service2 //I know this isn't valid Javascript
// just for illustration purposes
$scope.data2 = service2 - service1 + service 3
//etc...
});
};
updateAll();
//Form Section
$("#myForm').dialog({
buttons: {
Save: function () {
Data.save(data).success(function(){
updateAll();
});
}
}
});
}
Breaking this down, I have wrapped all the assignments to scope objects that rely on services into the updateAll function and invoke it on instantiation of the myCtrl. In the form that updates the data I call the updateAll() function upon success of the Data.save() function.
Not exactly brain surgery, I'll admit, but I had gotten confused with $scope.$apply() and thinking about just calling myCtrl(). That somehow seemed like the "Angular" way, but neither worked. I guess the controller function gets run only once on page refresh and there is no Angular way to call it again.
I use AngularJS on the client side to display some informations that'll get pushed through a NodeJS-Server. The data will be held in a service factory.
I want to watch this data through the angular watch function.
The problem i run into, is the following. watch runs through the factory only once and stops.
And if the server pushes changed data it won't update the view?
Here is some code snippet.
.factory('clientStorage', ['socket', function (socket){
var that = {};
//basis data
that.basisData = {};
that.getBasisData = function () {
socket.on('sendBasis', function (basis) {
console.log('ich hoffe doch');
that.basisData = basis;
console.log(that.basisData);
});
console.log(that.basisData);
return that.basisData;
};
return that;
}]);
I don't know why this happens?
Anybody there who may help?
Greetings
Henrik
Try this in your controller:
$scope.$watch( function() { return clientStorage.basisData; }, function(clientData) {
$scope.data = clientData;
});
Where $scope.data is the data you are trying to update.