Creating a transaction in Angular JS - angularjs

I have a function as $scope.submit() in my angular js application. Following is the code.
scope.submit = function () {
var reqDate = dateFilter(scope.first.date, scope.df);
this.formData.locale = scope.optlang.code;
this.formData.active = this.formData.active || false;
this.formData.dateFormat = scope.df;
this.formData.activationDate = reqDate;
if (routeParams.groupId) {
this.formData.groupId = routeParams.groupId;
}
if (routeParams.officeId) {
this.formData.officeId = routeParams.officeId;
}
if (scope.first.submitondate) {
reqDate = dateFilter(scope.first.submitondate, scope.df);
this.formData.submittedOnDate = reqDate;
}
if (scope.first.dateOfBirth) {
this.formData.dateOfBirth = dateFilter(scope.first.dateOfBirth, scope.df);
}
if (!scope.opensavingsproduct) {
this.formData.savingsProductId = null;
}
resourceFactory.clientResource.save(this.formData, function (data) {
scope.newid = data.clientId;
return scope.newid
});
resourceFactory.clientIdenfierResource.save({
clientId: scope.newid
}, this.formData2, function (data) {
location.path('/viewclient/' + data.clientId);
});
};
The first resourceFactory.clientResource.save creates a client and pass the client id. The second resourceFactory.clientIdenfierResource.save creates the identifier like passport number and check if another client with the same passport number exists.
i wanted to roll back first one if the second doesn't finish. Like if we have a transaction,
save 1 = first transaction
save 2 = second transaction
if save 2 has finished then commit rest of the transaction. How can i do it in angular. Please advise.

Related

AngularJS: Passing Promise, yet Cannot read property 'finally' of undefined

In my angular app, I have 2 methods save() and saveTriggers(). saveTriggers() updates all records by calling a web service (C#). I want to make sure that a block of code is executed after all records are updated in saveTriggers() and control is returned to save(). I believe I need to pass something from the saveTriggers() to make finally block execute. I tried various things, nothing works. Using .then() also gives the same error. I am not that good at JS. Can you please guide me.
vm.updatedTriggers = []; // IDs are pushed in
vm.saveTriggers = function () {
if (vm.updatedTriggers.length === 0) {
vm.close();
} else {
vm.saving = true;
vm.save()
.finally(function () { // ERROR - Cannot read property 'finally' of undefined
console.log("Saved all. Closing..."); // Never REACHES here
vm.saving = false;
vm.updated = true;
$uibModalInstance.close(true);
});
}
};
vm.save = function () {
//vm.saving = true;
for (var i = 0; i < vm.updatedTriggers.length; i++) {
var trigger = vm.triggers.find(t => t.id === vm.updatedTriggers[i]);
var input = {
id: trigger.id,
target: trigger.target,
targetInfo: vm.targetData,
event: trigger.event,
eventQuantity: trigger.eventQuantity,
eventQuantityExtra: trigger.eventQuantityExtra
};
rpmService.editDeviceTrigger(input);
/*.finally(function () {
console.log("Updated event"); // Reaches here
vm.updated = true;
return Promise.resolve(2);
});*/ // Commenting this also doesn't help
}
return Promise.resolve(2);
};
rpmService.editDeviceTrigger(input)
public async Task EditDeviceTrigger(EditDeviceTriggerInput input) {
// calls other methods with await
// Doesn't return anything
}
EDIT: Updated Code: I got rid of the error, but the output is not is expected series.
vm.saveTriggers = function () {
vm.saving = true;
vm.save().then
(function success() {
console.log("Returned Result ");
console.log("Saved all. Closing..."); // These lines are executed before the event is upated
vm.saving = false;
$uibModalInstance.close(true);
});
};
vm.save = function () {
var deferred = $q.defer();
for (var i = 0; i < vm.updatedTriggers.length; i++) {
var trigger = vm.triggers.find(t => t.id === vm.updatedTriggers[i]);
var input = {
id: trigger.id,
....
};
rpmService.editDeviceTrigger(input)
.finally(function () {
console.log("Updated event"); // Successfully updates all events
vm.updated = true;
});
}
deferred.resolve();
return deferred.promise;
};
OUTPUT:
Returned Result
Saved all. Closing...
Updated event
EXPECTED OUTPUT:
Updated event
Returned Result
Saved all. Closing...
Thanks.
Usually you dont need $q.defer-related things, but u can do same using it if u want.
Here I guess you just need to collect all your save promises and return new resulting one using $q.all:
vm.save = function () {
const myAwesomePromises = []
for (var i = 0; i < vm.updatedTriggers.length; i++) {
...
const savePromise = rpmService.editDeviceTrigger(input);
savePromise.finally(() => console.log('edit device finally'));// <-- not sure u need this
myAwesomePromises.push(savePromise);
}
return $q.all(myAwesomePromises).finally(() => console.log('All edit device finally'));
};

Call multiple web api using Angular js one by one

I have a scenario in which there is 8 web api's called as :
#1
Sync Local DB from server DB (response will RETURN a List=> myList)
If (myList.Length > 0)
#1.1 Call web Api to Insert/Update Local DB
#2
Sync Server DB from Local DB (Request goes with a List=> myList)
If (myList.Length > 0)
#2.1 Call web Api to Insert/Update in Server DB (Response will RETURN a List=> newList)
If(newList.length > 0)
#2.2 Call web Api to Insert/Update in Local DB
I have two separate process For Head and Head Collection tables which synced with above process. So there is #3 and #4 scenario is also present.
I have call web api in the following manner...
syncHeadDataLogic();
syncHeadCollectionDataLogic();
I need that Head data should be synced first then HeadCollection data synced. But if there is no updated record for head then Head collection executed.
In my scenario my web apis called in any order but i need a order as I have described above. Kindly suggest me how I achieved this.
#Updated
//Sync Head
$scope.initializeController = function () {
if ($scope.online) {
//debugger;
syncHeadDataLogic();
syncHeadCollectionDataLogic();
}
};
function syncHeadDataLogic() {
HeadService.HeadSyncLocalDB(parseInt(localStorage.headRevision, 10), $scope.completeds, $scope.erroe);
};
$scope.SynServerDBCompleted = function (response) {
debugger;
$scope.HeadListForSync = response.HeadList;
var tempHeadCurrencyDetail = [];
if ($scope.HeadListForSync.length > 0) {
angular.forEach($scope.HeadListForSync, function (xx) {
xx.CurrencyId = xx.CurrencyServerId;
xx.Id = xx.HeadServerId;
angular.forEach(xx.HeadCurrencyDetail, function (yy) {
yy.CurrencyId = yy.CurrencyServerId;
yy.HeadId = xx.HeadServerId;
if (yy.Revision == -1)
tempHeadCurrencyDetail.push(yy);
});
xx.HeadCurrencyDetail = tempHeadCurrencyDetail;
});
var postData = { Revision: parseInt(localStorage.headRevision, 10), HeadList: $scope.HeadListForSync };
HeadService.SynServerDB(postData, $scope.completed, $scope.erroe);
}
else {
// alertsService.RenderSuccessMessage("There is no change in data after your last synchronization.");
}
};
$scope.requestErrorwer = function (response) {
debugger;
};
$scope.completed = function (response) {
debugger;
if (response.RevisionNo == localStorage.headRevision) {
syncHeadCollectionDataLogic();
// alertsService.RenderErrorMessage("There is newer version on the server. Please Sync from server first.", "MessageAlert");
}
else {
syncData(response);
}
};
$scope.completeds = function (response) {
debugger;
if (response.RevisionNo == localStorage.headRevision) {
syncHeadCollectionDataLogic();
// alertsService.RenderSuccessMessage("You are already working on the latest version", "MessageAlert");
}
else {
syncData(response);
}
//
var request = new Object();
HeadService.getAllHeadForRevision(request, $scope.SynServerDBCompleted, $scope.requestErrorwer);
};
$scope.erroe = function (response) {
debugger;
// alertsService.RenderErrorMessage("Data Synchronization Failed", "MessageAlert");
};
function syncData(data) {
debugger;
$scope.ReturnedRevisonNo = data.RevisionNo;
if (data.HeadList && data.HeadList.length > 0) {
var postData = { Revision: $scope.ReturnedRevisonNo, HeadList: data.HeadList, HeadRevision: $scope.ReturnedRevisonNo };
HeadService.AddUpdateHeadAfterSync(postData, $scope.cmpSync, $scope.Error);
}
else {
syncHeadCollectionDataLogic();
}
};
$scope.cmpSync = function (response) {
debugger;
localStorage.headRevision = $scope.ReturnedRevisonNo;;
alertsService.RenderSuccessMessage("The synchronization has been completed successfully.");
syncHeadCollectionDataLogic();
};
$scope.Error = function (response) {
debugger;
// alertsService.RenderErrorMessage(response.ReturnMessage);
// alertsService.SetValidationErrors($scope, response.ValidationErrors);
};
////////////Sync End
//Sync Head Collection
function syncHeadCollectionDataLogic() {
HeadService.HeadSyncLocalCollectionDB(parseInt(localStorage.headCollectionRevision, 10), $scope.completedCollections, $scope.erroeCollection);
};
$scope.SynServerDBCompletedCollection = function (response) {
$scope.HeadCollectionListForSync = response.HeadCollectionList;
if ($scope.HeadCollectionListForSync.length > 0) {
angular.forEach($scope.HeadCollectionListForSync, function (value, index) {
value.Id = value.HeadCollectionServerId;
angular.forEach(value.HeadCollectionDetails, function (v) {
v.CommittedCurrencyId = v.CommittedCurrencyServerId;
v.HeadId = v.HeadServerId;
v.WeightId = v.WeightServerId;
v.HeadCollectionId = value.HeadCollectionServerId; //change
angular.forEach(v.HeadCollectionAmountDetails, function (xx) {
xx.CurrencyId = xx.CurrencyServerId;
});
});
});
var postData = { Revision: parseInt(localStorage.headCollectionRevision, 10), HeadCollectionList: $scope.HeadCollectionListForSync };
HeadService.SynServerCollectionDB(postData, $scope.completedCollection, $scope.erroeCollection);
}
else {
// alertsService.RenderSuccessMessage("There is no change in data after your last synchronization.");
}
};
$scope.requestErrorwerCollection = function (response) {
};
$scope.completedCollection = function (response) {
if (response.RevisionNo == localStorage.headCollectionRevision) {
// alertsService.RenderErrorMessage("There is newer version on the server. Please Sync from server first.", "MessageAlert");
}
else {
syncDataCollection(response);
}
};
$scope.completedCollections = function (response) {
if (response.RevisionNo == localStorage.headCollectionRevision) {
// alertsService.RenderSuccessMessage("You are already working on the latest version", "MessageAlert");
}
else {
syncDataCollection(response);
}
var request = new Object();
HeadService.getAllHeadCollectionForRevision(request, $scope.SynServerDBCompletedCollection, $scope.requestErrorwerCollection);
};
$scope.erroeCollection = function (response) {
// alertsService.RenderErrorMessage("Data Synchronization Failed", "MessageAlert");
};
function syncDataCollection(data) {
$scope.ReturnedRevisonNo = data.RevisionNo;
if (data.HeadCollectionList && data.HeadCollectionList.length > 0) {
var postData = { Revision: $scope.ReturnedRevisonNo, HeadCollectionList: data.HeadCollectionList, HeadRevision: $scope.ReturnedRevisonNo };
HeadService.AddUpdateaHeadCollectionAfterSync(postData, $scope.cmpSyncCollection, $scope.ErrorCollection);
}
};
$scope.cmpSyncCollection = function (response) {
localStorage.headCollectionRevision = $scope.ReturnedRevisonNo;;
alertsService.RenderSuccessMessage("The synchronization has been completed successfully.");
$scope.initializeController();
};
$scope.ErrorCollection = function (response) {
// alertsService.RenderErrorMessage(response.ReturnMessage);
// alertsService.SetValidationErrors($scope, response.ValidationErrors);
}
//End
I need that Head data should be synced first then HeadCollection data synced. But if there is no updated record for head then Head collection executed.
What you need is chained promises. Try this (I'm giving you pseudocode for now):
HeadService.HeadData
|-----------------|
HeadCollection(headDataResult)
|------------------|
finalHandler(headCollectionResult)
|------------------|
HeadService.HeadData()
.then(HeadService.HeadCollection) // return or throw Err if headDataResult is empty
.then(finalHandler);
Here, the order of execution of the promises will be predictable, and sequential. Also, each promise will be returned the resolved value of the previous promise
AngularJS as you can see in the documentation here, uses Promises out of the box with the $http injectable. You can define a factory like so:
// Factory code
.factory("SampleFactory", function SampleFactory($http) {
var sampleFactoryObject = {};
sampleFactoryObject.getSomething = function() {
return $http.get('/someUrl');
}
sampleFactoryObject.getSomething.then(function resolveHandler(res) {
return res;
},
function rejectHandler(err) {
throw new Error(err);
});
sampleFactoryObject.getSomethingElse = function() {
return $http.get('/someOtherUrl');
}
sampleFactoryObject.getSomethingElse.then(function resolveHandler(res) {
return res;
},
function rejectHandler(err) {
throw new Error(err);
});
return sampleFactoryObject;
});
// Controller code
.controller('myController', function myController(SampleFactory) {
SampleFactory.getSomething()
.then(SampleFactory.getSomethingElse())
.then(finalHandler);
var finalHandler = function(resultOfGetSomethingElse) {
console.log(resultOfGetSomethingElse);
}
});

Singleton JS Object in Angular Service

I am trying to add methods to an Object's protoype, which will be used in a singleton service and will be initiated only once when the service is created.
angular
.module('app.steps')
.factory('stepsService', stepsService);
stepsService.$inject = [];
/* #ngInject */
function stepsService() {
var steps = new Steps(1,3);
function Steps(current_step, total_steps) {
this.c_step = current_step;
this.t_step = total_steps;
}
Steps.prototype = {
addSteps: function (num) {
this.c_step += num;
},
setLastStep: function () {
this.lastStep = this.c_step = this.t_step;
}
};
var service = {
steps: steps
};
return service;
}
My problem is that although the object is created and initiated successfully, the methods are not there.
What is missing?
As mentioned in the comments, var steps = new Steps(1,3); should be after Steps.prototype = {....}

binding to service variable, doesnt refresh (service changes the var frequently)

In my Service i have the vars i want to display and the getters for it:
var docsLoaded = 0;
var docsToLoad = null;
pouchService.getDocsLoaded = function () {
return docsLoaded;
};
pouchService.getDocsToLoad = function () {
return docsToLoad;
};
While the service is syncing, i want to count the synced docs
pouchService.syncNow = function () {
var foundLastSeq = false;
docsLoaded = 0;
docsToLoad = null;
remoteDB.info().then(function (remoteInfo) {
function findOutDiff(localPosition) {
docsToLoad = (remoteInfo.update_seq - localPosition) + 1;
console.log("docs to load: " + docsToLoad);
}
// start Sync progress
sync = localDB.sync(remoteDB, {live: false})
.on('change', function (info) {
console.log('AI change: ');
console.log(info);
if (info.direction === 'pull') {
if (foundLastSeq === false) {
foundLastSeq = true;
findOutDiff(info.change.last_seq);
}
}
console.log(docsLoaded + " from " + docsToLoad);
docsLoaded++;
})
In my HTML i want to display the progress like this:
{{pouchService.getDocsLoaded()}} from {{pouchService.getDocsToLoad()}}
Now i get sometimes a value from getDocsLoaded, but mostly its zero. When I cancel the Syncprogress i get the value where it's stopped.
So i get the value before it really starts and when it's over, but i want it during the sync progress. (on the console my my progressinfos are working as expected)
Any ideas?
The problem is in applying scope. Jim wrote a nice article about this problem:
jimhoskins.com/2012/12/17/angularjs-and-apply.html
Solved it:
$rootScope.$apply(function () {
docsLoaded++;
});

accessing items in firebase

I'm trying to learn firebase/angularjs by extending an app to use firebase as the backend.
My forge looks like this
.
In my program I have binded firebaseio.com/projects to $scope.projects.
How do I access the children?
Why doesn't $scope.projects.getIndex() return the keys to the children?
I know the items are in $scope.projects because I can see them if I do console.log($scope.projects)
app.js
angular.module('todo', ['ionic', 'firebase'])
/**
* The Projects factory handles saving and loading projects
* from localStorage, and also lets us save and load the
* last active project index.
*/
.factory('Projects', function() {
return {
all: function () {
var projectString = window.localStorage['projects'];
if(projectString) {
return angular.fromJson(projectString);
}
return [];
},
// just saves all the projects everytime
save: function(projects) {
window.localStorage['projects'] = angular.toJson(projects);
},
newProject: function(projectTitle) {
// Add a new project
return {
title: projectTitle,
tasks: []
};
},
getLastActiveIndex: function () {
return parseInt(window.localStorage['lastActiveProject']) || 0;
},
setLastActiveIndex: function (index) {
window.localStorage['lastActiveProject'] = index;
}
}
})
.controller('TodoCtrl', function($scope, $timeout, $ionicModal, Projects, $firebase) {
// Load or initialize projects
//$scope.projects = Projects.all();
var projectsUrl = "https://ionic-guide-harry.firebaseio.com/projects";
var projectRef = new Firebase(projectsUrl);
$scope.projects = $firebase(projectRef);
$scope.projects.$on("loaded", function() {
var keys = $scope.projects.$getIndex();
console.log($scope.projects.$child('-JGTmBu4aeToOSGmgCo1'));
// Grab the last active, or the first project
$scope.activeProject = $scope.projects.$child("" + keys[0]);
});
// A utility function for creating a new project
// with the given projectTitle
var createProject = function(projectTitle) {
var newProject = Projects.newProject(projectTitle);
$scope.projects.$add(newProject);
Projects.save($scope.projects);
$scope.selectProject(newProject, $scope.projects.length-1);
};
// Called to create a new project
$scope.newProject = function() {
var projectTitle = prompt('Project name');
if(projectTitle) {
createProject(projectTitle);
}
};
// Called to select the given project
$scope.selectProject = function(project, index) {
$scope.activeProject = project;
Projects.setLastActiveIndex(index);
$scope.sideMenuController.close();
};
// Create our modal
$ionicModal.fromTemplateUrl('new-task.html', function(modal) {
$scope.taskModal = modal;
}, {
scope: $scope
});
$scope.createTask = function(task) {
if(!$scope.activeProject || !task) {
return;
}
console.log($scope.activeProject.task);
$scope.activeProject.task.$add({
title: task.title
});
$scope.taskModal.hide();
// Inefficient, but save all the projects
Projects.save($scope.projects);
task.title = "";
};
$scope.newTask = function() {
$scope.taskModal.show();
};
$scope.closeNewTask = function() {
$scope.taskModal.hide();
};
$scope.toggleProjects = function() {
$scope.sideMenuController.toggleLeft();
};
// Try to create the first project, make sure to defer
// this by using $timeout so everything is initialized
// properly
$timeout(function() {
if($scope.projects.length == 0) {
while(true) {
var projectTitle = prompt('Your first project title:');
if(projectTitle) {
createProject(projectTitle);
break;
}
}
}
});
});
I'm interested in the objects at the bottom
console.log($scope.projects)
Update
After digging around it seems I may be accessing the data incorrectly. https://www.firebase.com/docs/reading-data.html
Here's my new approach
// Load or initialize projects
//$scope.projects = Projects.all();
var projectsUrl = "https://ionic-guide-harry.firebaseio.com/projects";
var projectRef = new Firebase(projectsUrl);
projectRef.on('value', function(snapshot) {
if(snapshot.val() === null) {
console.log('location does not exist');
} else {
console.log(snapshot.val()['-JGTdgGAfq7dqBpSk2ls']);
}
});
$scope.projects = $firebase(projectRef);
$scope.projects.$on("loaded", function() {
// Grab the last active, or the first project
$scope.activeProject = $scope.projects.$child("a");
});
I'm still not sure how to traverse the keys programmatically but I feel I'm getting close
It's an object containing more objects, loop it with for in:
for (var key in $scope.projects) {
if ($scope.projects.hasOwnProperty(key)) {
console.log("The key is: " + key);
console.log("The value is: " + $scope.projects[key]);
}
}
ok so val() returns an object. In order to traverse all the children of projects I do
// Load or initialize projects
//$scope.projects = Projects.all();
var projectsUrl = "https://ionic-guide-harry.firebaseio.com/projects";
var projectRef = new Firebase(projectsUrl);
projectRef.on('value', function(snapshot) {
if(snapshot.val() === null) {
console.log('location does not exist');
} else {
var keys = Object.keys(snapshot.val());
console.log(snapshot.val()[keys[0]]);
}
});
$scope.projects = $firebase(projectRef);
$scope.projects.$on("loaded", function() {
// Grab the last active, or the first project
$scope.activeProject = $scope.projects.$child("a");
});
Note the var keys = Object.keys() gets all the keys at firebaseio.com/projects then you can get the first child by doing snapshot.val()[keys[0])

Resources