angular resource clears object data after post - angularjs

my angular app clears data after post.
Here is the snippet from controller:
$scope.saveDevice = function() {
var deviceId = $scope.device.id;
if (deviceId) {
$scope.device.$update(function(result) {
$location.path('/devices');
});
} else {
$scope.device.$save().then(function (deviceResult) {
$scope.device.id = deviceResult.deviceId;
$scope.device.$activationCode(function (result) {
$scope.device.activationCode = result.activationCode;
});
});
}
};
When I hit break point at
"$scope.device.$save().then(function (deviceResult) {" the application shows that device is populated with properties from form. But after the post, device is cleared of any properties. Is this normal behaviour? If so, how can I prevent it?

Here I found the answer to my problem:
AngularJS - Prevent Form Clear
Basically:
call class method
Device.save($scope.device) //....
instead of
$scope.device.$save
and it will presist the data you've in $scope.device class.

I'm not sure if this helps, but from the docs. This is too long to put as a comment.
Angular Doc
It is important to realize that invoking a $resource object method immediately returns an empty reference (object or array depending on isArray). Once the data is returned from the server the existing reference is populated with the actual data. This is a useful trick since usually the resource is assigned to a model which is then rendered by the view. Having an empty object results in no rendering, once the data arrives from the server then the object is populated with the data and the view automatically re-renders itself showing the new data. This means that in most cases one never has to write a callback function for the action methods.

Related

How to update page after angularjs ng-repeat loads new data?

I have a table that I'm loading data with dynamically using ng-repeat. When getting a new set of data, it loads fine, the issue is if I try and update the table, the updates to it do not show. I am updating it in the callback of an $http post and AFTER I assign the new data to what the ng-repeat is using so I'm confused on why it isn't working.
Code for further explanation:
$scope.UpdateTable = function (parms) {
$http.post("url", { parm: parms }).then(function (response) {
$scope.data = JSON.parse(response.data.d); // This assigns the new data to what the ng-repeat is using
// Do stuff with the new data in table
$(".jQuerySelector").dowhatever(); // (does not work)
});
}
Can anyone explain why the updates/functions I'm calling after updating the data variable do not get called after the table already updates? I think I need a promise somewhere but I'm not very familiar with them and don't fully understand them yet. The new data I'm getting does not show in the page before the other functions are called when I'm debugging with the Dev Tools.

Angularjs caching vs fetching live data

I have a service I'm using to fetch data for an application.
Since a service is a singleton, I'd like to cache some reference data in the service, but I'm not sure how to get that to happen.
I'm using Strongloop and right now have a function in the Service like this:
function fetchReferenceData() {
return refInfo.find().$promise;
}
I'd like to have a property where I store the reference data.
I could add a property in the code, like
var myRefData;
and then I could edit fetchReferenceData() to check that property, but since the client is expecting a promise back, this won't work:
function fetchReferenceData() {
if (myRefData) { return myRefData; }
else { return refInfo.find().$promise;}
}
What's a good programming pattern to work with this kind of thing?
Do I pass in a function to call in a .then() to set the data in the client?
If the client is expecting a promise, you can use the $q service to create a promise from your cached value.
function fetchReferenceData() {
if (myRefData) { return $q.when(myRefData); }
else { return refInfo.find().$promise;}
}
The client can access it with the standard .then method.
fetchReferenceData().then (function (myRefData) {
//use myRefData
});
Best practices
You need a way to destroy the information in your cache.
You need to avoid calling refInfo.find() again if a query is already in progress.
Update for ngResource objects
Methods from Angular $resource services return references to empty objects.
From the Docs:
It is important to realize that invoking a $resource object method immediately returns an empty reference (object or array depending on isArray). Once the data is returned from the server the existing reference is populated with the actual data. This is a useful trick since usually the resource is assigned to a model which is then rendered by the view. Having an empty object results in no rendering, once the data arrives from the server then the object is populated with the data and the view automatically re-renders itself showing the new data. This means that in most cases one never has to write a callback function for the action methods.
So you can cache the query reference but you need to be aware the data on it will be undefined for a period of time.
The $resource service also adds a $promise property that can be used by clients that accept a promise.
function fetchReferenceData() {
var cache;
return cache = cache || refInfo.find();
}
clientThatNeedsPromise(fetchReferenceData().$promise);

How to go back to the previous view with parameter in ionic?

In a view I have a link to choose a start location like below:
<input type="text" ng-model="placeStart" placeholder="place to start">
<input type="text" ng-model="weight" placeholder="goods weight">
and in the location page, I do choose a place, however, When I use $ionicHistory.goBack(), I could not pass the "place" back to the previous view. I also do not want to use state.go('previous view') to pass the "place", because in that way, I will lost the other input information in the previous view.
Here is :
$ionicHistory.backView().stateId;
don't ignore to include $ionicHistory on controller
There are three options which immediately come to mind. $rootScope, localStorage and using routing not goBack().
If you need the value from one view in another, and they're completely separate controllers etc then you need a way to pass them around.
You could create and then put the value into $rootScope.globals or similar.
You could store the value to localStorage before sending the user back.
You could redirect correctly to a route which allows the values to be included in the url and still show the provious page. For example the same route with and without values set, using - or 0 for not set depending on data type:
/an/example/route/-/-/
/an/example/route/0/0/
/an/example/route/123/456
Update:
There is actually a fourth way where you can send data between controllers using $broadcast and $on. The broadcast happens in the sending controller and the $on listens in the receiving controller(s) so you can send an update to values / an object etc. $on and $broadcast in angular
It depends on your situation but if you don't care to preserve state after a page reload which localStorage would be good for, but rather have the state be remembered just when you're going back (and not necessarily when you later navigate forward back into the view again) then I do this: I make a separate service, just an object that sticks around in which I can inject anywhere and store some variables. In Angular 1 this would be a service object.
angular.module('foo').factory("placeHelper", [
() => {
let _place = null;
class PlaceHelper {
set place(place){
_place = place;
}
get place(){
return _place;
}
reset(){
_place = null;
}
}
let helper = new PlaceHelper();
return helper;
}
]);
Then in your controller that you're going back to, you inject placeHelper and ask it for the place and restore your state via $scope.place = placeHelper.place and when in the UI for that controller someone selects a place, you just store it in the service, placeHelper.place = $scope.place.
I would use localStorage within the service if I wanted to keep the state around after a page refresh.
I don't like polluting $rootScope because it's harder to keep track after you start to have more than a few unrelated methods in there and your properties need to have longer names (or get grouped in objects anyway). It's better for maintainability to encapsulate and separate concerns.
Service variation:
The service could be an object literal instead of a class and you could directly set the properties instead of using methods if you wanted it to be a bit more simple.
angular.module('foo').factory("placeHelper", [
() => {
let helper = {
place: null,
reset(){
this.place = null;
}
};
return helper;
}
]);
I stumbled on the same problem recently. I ended up deciding to use $ionicHistory.currentView() and $ionicHistory.backView() (see documentation here). The former function returns an object associated to the current view, while the latter returns an object associated to the view you will go to after you call $ionicHistory.goBack().
Before calling $ionicHistory.goBack() on your location page you call $ionicHistory.backView() and define a new property to the returned object whose contents is the data you want to propagate to the other view.
On your other view, you change its '$ionicView.enter' event handler so it calls $ionicHistory.currentView(), which retrieves the object with the data you want.

Why doesn't UnderscoreJS's _.extend() method copy AngularJS promises to the extended object?

Example:
$scope.post = Posts.get({id: id});
scope = _.extend({}, $scope);
alert($scope.post.id); // undefined
alert(scope.post.id); // exception - post is not defined
I feel that I'm doing something obviously wrong, but I can't figure out what. I expected it to shallowly copy the post reference to the new object:
alert($scope.post.id); // undefined
alert(scope.post.id); // undefined
$scope.post === scope.post; // true
This is from Angular documentation about ngResource
It is important to realize that invoking a $resource object method
immediately returns an empty reference (object or array depending on
isArray). Once the data is returned from the server the existing
reference is populated with the actual data. This is a useful trick
since usually the resource is assigned to a model which is then
rendered by the view. Having an empty object results in no rendering,
once the data arrives from the server then the object is populated
with the data and the view automatically re-renders itself showing the
new data. This means that in most cases one never has to write a
callback function for the action methods.
At the time when you are trying to extend the scope, your object is not fully there.
I hope that helps...

Update Angular View after resource post

Here is my problem! I use $resource API to post data from the client side to the server side. After the server side successfully updates the database, I kinda hope my data in view will be updated.
I chose to achieve this with:
$scope.magazines = Magazines.query();
$scope.addMagazine = function() {
var magazine = new Magazines({...payload data});
Magazines.save(magazine, function() {
$scope.magazines = Magazines.query();
});
};
Magazines is a defined ngResrouce factory.
This code works fine. My only problem is, whenever I activate this function (through mouseclick), the view flashes (refreshes) once. It is a really really bad user experience.
I wonder if there is any other way to add the new "magazine" to the scope without refreshing the entire $scope.magazines ?
By the way, the api at the backend will add a few properties (like created time, or id to it). Even if I write code to get the last added item (a different factory method I suppose), I'll still have to add it to the $scope.magazines and I don't know how to do that.
Any thought?
Just push the new Magazine onto the existing $scope.magazines (assuming it's an Array)
var magazine = new Magazines({...payload data});
$scope.magazines.push(magazine);

Resources