(Temporarily) Preventing angular from updating view when object changes? - angularjs

I have an object that I'm sending over to a web server to store in the db. Between when I send it and when the operation completes I need to modify it slightly so the server can handle it.
In effect I have the following code:
$scope.o = {...};
$scope.send = function()
{
$scope.sanitize($scope.o);
SomeService.Save($scope.o).then( function() {
$scope.unsanitize($scope.o);
});
}
Sanitize just gets the object ready to send the server and unsanitize puts it back into a form that the view can handle more easily.
The issue I'm having is that between the call to sanitize and unsanitize, there's a few milliseconds of delay (or seconds, depending on how slow my network is at the time). During that time the view is updated and shows the changes that sanitize made. I don't want those changes showing up to the user while the server is doing its thing, though.
Is there a way of temporarily preventing angular from updating changes to a specific object?
I've created a jsfiddle that illustrates the problem here: http://jsfiddle.net/29ze4exp/5/

Sure! Just don't modify the object that is bound to the view. Instead, use a copy.
var copy = angular.copy($scope.o);
$scope.sanitize(copy);
SomeService.Save(copy).then(function() {

Related

using angularjs to refresh view's data automatically when the data in database is changed

is it possible to use angularJs to refresh view's data automatically when the data in database is changed? Please help me how to do it
I made this script, but as you can see the data only refresh if viewData() is triggered.
$scope.viewData = function(){
$http.get("sample.php").then(function(response){
$scope.mine = response.data;
});
}
I want to create page like timeline in twitter which can load new tweets without refreshing the page. Thank you
You can do longpolling like this from Angular side:
setInterval($scope.vievData, 1000);
since setInterval is not monitored by Angular you will have to add the following line in $scope.viewData
$scope.$$phase || $scope.$digest();
immediately after $scope.mine=...
This will refresh $scope.mine every second regardless of the changes in DB, it is a bit crude. To do this only when the values are changed in the database you will probably have to use WebSockets, but that is a bit more complex, both front and back.

AngularFire: How to update scope without syncing to Firebase (i.e. local states, like "loading" or "selected")

I'm new to Firebase and AngularJS (and AngularFire), but am managing to work most things out... however this one's stumping me.
Situation:
I've got a server and a separate frontend. The frontend has NO WRITE PERMISSIONS for Firebase - it can only read it's own data (using a token provided by the server). The server has an API which the frontend utilises to make updates.
For the frontend to request an update to a particular item in a list, it needs to provide that item's Firebase ID to the server (along with whatever other information the API needs). The server will first verify that ID and then use it to update the correct Firebase data.
I've got AngularFire doing a three-way data binding for these actions, which is awesome!
Problem:
Lets say my Firebase structure is as follows:
actions: {
-JFeuuEIFDh: { // Firebase IDs for arrays
label: "One",
.
.
.
},
-JfuDu2JC81: {
"label": "Two",
.
.
.
}
I have the following HTML:
<div ng-controller"SuperController">
<ul>
<!-- key is the Firebase ID for the action, which is
required for my server to know which object to update -->
<li ng-repeat="(key, action) in actions">
<a ng-click="doAction(key, action)">action.label</a>
<!-- **Loading IS NOT and SHOULD NOT be stored in Firebase,**
it's simply a local state which AngularJS should manage -->
<p ng-hide="!action.loading">Loading...</p>
</li>
</ul>
</div>
doAction looks something like this:
$scope.doAction = function(key, item) {
$scope.actions[key].loading = true;
var onComplete = function () {
$scope.actions[key].loading = false;
}
// Calls to the server, etc...
.
.
.
}
I'm using $scope.actions[key].loading to provide a local state so the "Loading..." paragraph will appear when the user initiates doAction, and disappear when the doAction logic completes.
However, because AngularFire has set up a three-way data binding, it tries to save that change to the database, which fails because the client does not have permission to write!
I don't want it to save loading to the database! It's there simply to update that paragraph's ng-hide - it shouldn't be persistent and there's no way this would justify providing write permission to the client.
So what am I supposed to do? I can't think of any way to update the scope without firing off the three-way binding... Am I thinking of this the wrong way?
EDIT
Nested deep in the AngularJS documentation, under $FirebaseObject.$bindTo, was this:
use a variable prefixed with _, which will not be saved to the server, but will trigger $watch().
However when I used $scope.actions[key]._loading instead, the same problem still occurred. There was no apparent difference.
I couldn't find a clean solution to the problem.
use a variable prefixed with _, which will not be saved to the server, but will trigger $watch().
This wasn't actually implemented in code. I was considering submitting an implementation myself but it wasn't as simple as I hoped. Even after toJSON stopped returning _'d variables, it still tried to save the (unchanged) JSON to Firebase, so you'd have to fix it earlier somehow... I didn't go there.
To solve the problem I used AngularFire's $asArray instead of $asObject. The array is READ ONLY. Firebase won't try to sync any changes unless you call special functions. In my case, this works, however in other cases it might not be sufficient.
I had to change a bit my templating to work with an array instead of an object since a numerical key was now being provided instead of the actual key being used in Firebase. I converted the numerical key to the proper one with: actions.$keyAt(parseInt(key)).
It was a mess.. but it'll get me through for now.
I am having same issue. but this seems to fix it.
https://www.firebase.com/docs/web/libraries/angular/api.html#angularfire-firebaseobject-bindtoscope-varname
If $destroy() is emitted by scope (this happens when a controller is > destroyed), then this object is automatically unbound from scope. It can > also be manually unbound using the unbind() method, which is passed into ? > the promise callback.
//Setup synced array as usual
$scope.syncedArray = $firebaseArray(ref);
//call unbind on the variable
$scope.syncedArray.unbind();
//reorder, filter and maniuplate arrays as usual and when done call .bind() on it.

How to use $resource in AngularJS properly for building a client app?

I've been following this tutorial http://draptik.github.io/blog/2013/07/28/restful-crud-with-angularjs/. I implemented a Grails backend with it instead of the Java one in the tutorial.
I've got the data coming back and forth, with one issue. If I create/update/delete a user, I don't see the changes reflected on my user list when I am redirected back. I have to refresh the page to see the updates.
Looking at the network traffic for an edit, it looks like it does a PUT and fires off the GET before the PUT is complete. Assuming this is because $resource returns a promise so things can be done asynchronously. So how do I handle this so that when $location redirects me, my list is up to date?
I'm guessing the options are to wait for the PUT to complete before redirecting/querying for the list, or to somehow manually manage the $scope.users to match the request?
Or maybe this tutorial is just a bad example? Maybe there is a better way to do it (still using $resource)?
Note: I've seen Restangular out there, and I've seen $http with success callbacks, but I would like to understand the situation above.
One way to overcome this issue would be to not redirect to the list page, till you get a callback, and then do a redirect. You can show some busy indicator till that time. The resource call looks like this.
resource.update(config,data,function() { //gets called on success},
function(error) { //gets called on failure});
In real life scenario waiting for the response of update makes sense as you want to handle the error and success scenarios on the same page.
I don't see your code anywhere so i'm just assuming (based on what you wrote and your current problem)
You are probably doing a full (or partial) get each time you changed a user and (re)binding the result to your scope. Doing this in the callback of the resource should actually start the digest cycle angular does to update modified objects. If you had been doing the fetching outside $resource - for example with custom/jquery ajax you would need to execute $scope.$apply()
What i really don't understand you would need to wait for the callback. You already know you added/modified a user. Instead of 'detaching' that user from your scope, modify it, post it to your rest server, then wait for callback, and reinserting it into the scope - why not modify it directly in the list/array you put on your scope?
var users = Users.get(function () {
$scope.users = users.record; // bind the resulting records to the scope
});
$scope.updateUser = function (user) {
resource.update(...); //pseudo
};
Then in your html, you will keep a reference to the currentUser and the div-list will update automaticly.
<div ng-repeat="user in users" ng-click="currentUser=user">{{user.Name}}</div>
<input ng-model="currentUser.Name">
<button ng-click="updateUser(currentUser);">Update</button>
If you don't want to see the update in the list while you type, but only once your callback fires or when you hit the button, would would instead use another ng-model for your input like this:
<input ng-model="tempUser.Name">
And you would then copy the value other in either the updateUser method or in the resource callback like this:
$scope.updateUser = function (user) {
user.Name = $scope.tempUser.Name; // should update automaticly
resource.update(...) // pseudo
}
Hope it helped!

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

Handling the model-update-server response in Backbone.js

The Backbone.js model updates itself - and its views - locally on the page before
passing the data to the server and checking the server's response, so if the
server says "sorry charlie that's no good" the page has already shown the data
as having changed and thus doesn't correctly represent the server-side state of the object. What's the correct/elegant way to handle this on the Backbone.js side when the server returns an error?
If you are directly editing a model and trying to sync it, and also using it elsewhere in your app simultaneously, then that can lead to a world of problems.
In many cases it is better to clone the model for editing, and then when it syncs successfully, apply the clone's attributes back on to the original model.
You can get a cloned model by simply calling:
var clonedModel = originalModel.clone();
And then you can apply the attributes back in a success handler like
originalModel.set(clonedModel.attributes)
How about passing success, error callback functions to the statement where you update the server side state. May be something like this....
this.model.save(
{}, {
success: function() {
/* update the view now */
},
error: function() {
/* handle the error code here */
}
});
Taking it a level higher, you might override the Backbone.sync to globally handle the server-side error codes.
Use
model.save({wait: true});
Source: http://backbonejs.org/#Model-save

Resources