Accessing object values passed to function using AngularJS - javascript

I have a view with a form that asks a user for some details e.g. id, name and surname. To that effect, I have a person object created in a service as below to save the users information.
var personObject = angular.module("personObject", []);
personObject.service("PersonObject", function () {
var Person = {
id: "",
name: "",
surname: ""
};
return {
getPerson: function () {
return Person;
}
};
});
When the user completes the form the values for id, name and surname are set in the Person. This is working as intended and I can view the details back using get() in the views controller.
I then pass the person object to another service that should insert the user details in a SQLite database table. From my views controller I save the details to Database in my $scope.save function.
var formDetails = angular.module("formDetailsController", []);
formDetails.controller("FormDetailsController", function ($scope, UpdatePerson, PersonObject) {
var init = function () {
document.addEventListener("deviceready", onDeviceReady, false);
};
init();
function onDeviceReady() {
};
// Save details to database
$scope.save = function () {
var update = UpdatePerson.update(PersonObject.getPerson()); // Get the person object with user defined values and pass to UpdatePerson service
update.then(
function (success) {
// ToDo
}, function (fail) {
alert(fail.message);
});
};
});
My UpdatePerson service should insert the person object values to a SQLite table. The table is working as intended and have been tested with some hard coded values. My update() function looks as follows (full code given). I am unable to access the person object values however.
var update = angular.module("updatePerson", []);
update.service("UpdatePerson", function ($q, Database) {
// Initialise variables
var db = Database.init(); // Working
var updated = "";
var myFunctions = {
update: function (MyPerson) {
alert("MyPerson + // Returns [object Object]
"\n" + MyPerson.id + // Returns nothing
"\n" + MyPerson.name + // Returns nothing
"\n" + MyPerson.surname // Returns nothing);
var deferred = $q.defer();
var sql = 'INSERT OR IGNORE INTO tb_person (id, name, surname) VALUES (' + MyPerson.id + ', "' + MyPerson.name + '", "' + MyPerson.surname + '")';
var success = function (tx, results) {
deferred.resolve({ updated: true });
}
var error = function (tx, err) {
deferred.reject({
updated: false, message: 'An error has occured});
}
db.transaction(function (tx) {
tx.executeSql(sql, [], success, error);
});
return deferred.promise;
},
}
return myFunctions;
});
I am unable to access the values for my Person object in my update() function as above to insert into the table. It return a blank (not NULL or undefined) - just blank. How do I access the objects values?

I think you are missing declarations
.factory('Service1',['Service2', function (service2,$q, $timeout) {
var sendDataToOtherService= function (data) {
service2.updateData(data[0]);
return true;
}
return {
sendDataToOtherService:sendDataToOtherService
};
}])
.factory('Service2', function ($q, $timeout) {
var updateData= function (data) {
alert(data.name);
return true;
}
return {
updateData:updateData
};
});
Have a look at demo Link
http://plnkr.co/edit/oz7BA6rTW8vYuIHOYBxL?p=preview

Related

mvc asp can't update using query from my view

I am trying to have save changes on my script and I just need an update from my table. So far if I clicked the button, the alert success will not pop and can't see any error either. I also tried to verify to my table if the changes is made but the result is nothing happened
Here is the call function from my save button:
<script>
var op = '';
var op_dif = '';
$('#btnSave').click(function () {
op = $('#op').val();
op_dif = $('#op_difficulty').val();
alert(op + " " + op_dif); // I can see the value here
$.post("/Home/UpdateOP", {
'data': JSON.stringify([{
'op': op,
'opDiff': Op_dif
}])
}, function (data) {
var resp = JSON.parse(data);
if (resp["status"] == "SUCCESS") {
alert('Data has been successfully updated');
location.reload();
}
else {
alert('Error!!');
}
});
});
</script>
My view where my update query is located:
public string UpdateOpsDiff(operation[] ops)
{
string res = "";
foreach(var op in ops)
{
string updatetQuery = "update sys.OP_difficulty set op_difficulty = #diff where op = #op;";
MySqlCommand updateCommand = new MySqlCommand(updatetQuery);
updateCommand.Connection = myConnection;
updateCommand.Parameters.AddWithValue("#diff", op.op_dif);
updateCommand.Parameters.AddWithValue("#op", op.op);
myConnection.Open();
int updatedRowNum = 0;
try
{
updatedRowNum = updateCommand.ExecuteNonQuery();
}
catch(MySqlException)
{
updatedRowNum = updateCommand.ExecuteNonQuery();
}
finally
{
myConnection.Close();
}
res = "{status:SUCCESS, updatedRowNum:" + updatedRowNum + "}";
}
return res;
}
Controller where it reads the view query:
public string UpdateOp()
{
string data = Request.Form["data"];
IQA sys = new MysqlSys();
try
{
var rows = JsonConvert.DeserializeObject<operation[]>(data);
return sys.UpdateOpsDiff(rows);
}
catch (JsonSerializationException je)
{
Console.WriteLine(je.Message);
return "{status:'DATA_FORMAT_ERROR'}";
}
}
Is there any missing items that I need. It already working using the query from my controller but this time I need to store my query from my view.
Any suggestions or comments. TIA
Since you're using AJAX callback, you should change return type to ActionResult and mark the action method with [HttpPost] attribute, also you should use return Content() or return Json() depending on returned type from UpdateOpsDiff() (string or object, respectively). Here is an example of proper setup:
[HttpPost]
public ActionResult UpdateOp(string data)
{
IQA sys = new MysqlSys();
try
{
var rows = JsonConvert.DeserializeObject<operation[]>(data);
string result = sys.UpdateOpsDiff(rows);
// return JSON-formatted string should use 'Content()', see https://stackoverflow.com/q/9777731
return Content(result, "application/json");
}
catch (JsonSerializationException je)
{
// do something
return Json(new { status = "DATA_FORMAT_ERROR"});
}
}
Then set the AJAX callback to pass JSON string into action method mentioned above:
$('#btnSave').click(function () {
op = $('#op').val();
op_dif = $('#op_difficulty').val();
var values = { op: op, opDiff: op_dif };
$.post("/Home/UpdateOP", { data: JSON.stringify(values) }, function (data) {
var resp = JSON.parse(data);
if (resp["status"] == "SUCCESS") {
alert('Data has been successfully updated');
location.reload();
}
else {
alert('Error!!');
}
});
});
Note:
The JSON-formatted string should be presented in key-value pairs to be returned as content, as shown in example below:
res = string.Format(#"{""status"": ""SUCCESS"", ""updatedRowNum"": ""{0}""}", updatedRowNum);

Controller is executing before the factroy is giving result [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 7 years ago.
with reference to this answer How do I return the response from an asynchronous call? how could i implement this one in my secanrio.
I am trying to do caching with use of sqlite using cordova sqlite plugin but my problem is my controller executes before my factory completes its execution. I am pasting my controller code and my factory code. I had put alert for knowing the sequence of execution. My ideal alert sequence is 1,2,3,4,5,6 but when i am executing the code i am getting alert sequence like 1,5,6,2,3,4. I am pasting my controller and factory code below.
angular.module('foo').controller('PriceListController',["$scope","$http","$stateParams","CURD","$q","DB", function($scope,$http,$stateParams,CURD,$q,DB) {
$scope.brand_id=Number($stateParams.id);
$scope.process=true;
$scope.pricelists=[];
$scope.getBrandDocs= function(){
var parameters=new Array(2);
parameters[0]=$scope.brand_id
parameters[1]=1;
CURD.exc_query("select * from brand_docs where brand_id=? AND type=?",parameters)
.then(function(price_lists) {
alert("2");
$scope.inter_pricelist=price_lists;
console.log("Records from query call:"+JSON.stringify( $scope.inter_pricelist));
$scope.deferred = $q.defer();
if ($scope.inter_pricelist){
console.log("Found data inside cache", JSON.stringify($scope.inter_pricelist));
$scope.deferred.resolve($scope.inter_pricelist);
// alert(JSON.stringify( $scope.inter_pricelist));
alert("3");
}
else{
$http.get('http://foo.com?brand='+ $scope.brand_id +'&type=price_list')
.success(function(data) {
//alert("http call");
console.log("Received data via HTTP",JSON.stringify(data));
angular.forEach(data.data.info, function(value, key) {
var sql = "INSERT OR REPLACE INTO brand_docs(id, brand_id, name, file_url,type) VALUES (?, ?, ?, ?, ?)";
var parameters=new Array(5);
parameters[0]=value.id;
parameters[1]=value.brand_id;
parameters[2]=value.name;
parameters[3]=value.file_url;
parameters[4]=value.type;
var result=DB.query(sql,parameters);
});
$scope.deferred.resolve(data.data.info);
})
.error(function() {
console.log("Error while making HTTP call.");
$scope.deferred.reject();
});
}
return ($scope.deferred.promise).then(function(pricelists){
alert("4");
return pricelists;
},function(){});
},function(){});
alert("5");
};
$scope.pricelists=$scope.getBrandDocs();
alert("6");
}]);
// This is factory code i am pasting
angular.module('foo').factory('DB', function($q, DB_CONFIG,$cordovaSQLite) {
var self = this;
self.db = null;
self.init = function() {
try{
self.db = window.sqlitePlugin.openDatabase(DB_CONFIG.name, '1.0', 'database', -1);
angular.forEach(DB_CONFIG.tables, function(table) {
var columns = [];
angular.forEach(table.columns, function(column) {
columns.push(column.name + ' ' + column.type);
});
var query = 'CREATE TABLE IF NOT EXISTS ' + table.name + ' (' + columns.join(',') + ')';
self.query(query);
console.log('Table ' + table.name + ' initialized');
});
}
catch(err){
}
};
self.query = function(query, bindings) {
bindings = typeof bindings !== 'undefined' ? bindings : [];
console.log("Query:"+query+" bindings:"+ bindings);
var deferred = $q.defer();
self.db.transaction(function(transaction) {
transaction.executeSql(query, bindings, function(transaction, result) {
console.log("Query sucessfull :"+ query);
console.log("Result of Query:"+ JSON.stringify(result));
deferred.resolve(result);
}, function(transaction, error) {
console.log("Error:"+ JSON.stringify(error));
deferred.reject(error);
});
});
return deferred.promise;
};
self.fetchAll = function(result) {
var output = [];
for (var i = 0; i < result.rows.length; i++) {
output.push(result.rows.item(i));
}
//console.log("RECORDS:" +JSON.stringify(output));
return output;
};
self.fetch = function(result) {
return result.rows.item(0);
};
return self;
})
.factory('CURD', function(DB) {
var self = this;
self.all = function(table_name) {
return DB.query('SELECT * FROM '+table_name)
.then(function(result){
return DB.fetchAll(result);
});
};
self.exc_query = function(query,parameters) {
return DB.query(query,parameters)
.then(function(result){
return DB.fetchAll(result);
});
};
self.getById = function(id,table_name) {
return DB.query('SELECT * FROM '+table_name +' WHERE id = ?', [id])
.then(function(result){
return DB.fetch(result);
});
};
return self;
});
The query completes asynchronously. By that I mean that when you call CURD.exec_query(), the query is queued and as soon as it is queued, your method continues to execute at "return ($scope.deferred.promise).then(function(pricelists){". That's why 4, 5, 6 show up before 2 and 3. Once the query completes, again, asynchronously, the ".then()" method is called, which is when 2 and 3 are alerted.
Note that getBrandDocs() is going to return BEFORE then .then() method is called. What you could do is have your .then() method emit an event that is asynchronously picked up in the calling code which would in turn execute the 4, 5, and 6 steps.

Using Promises in AngularJS for chaining in two different controllers

I have a provider for my REST-Services named MyRestServices:
app.provider('MyRestServices', function() {
this.baseUrl = null;
this.setBaseUrl = function(_baseUrl) {
this.baseUrl = _baseUrl;
};
this.$get = ['$http', function($http) {
var _baseUrl = this.baseUrl;
function getMyData() {
return $http.get(_baseUrl + 'data1/?token=' + token + '&key=' + key);
}
function preGetTokenAndKey() {
return $http.get(_baseUrl + 'keyAndToken/');
}
return {
getMyData: getMyData,
preGetTokenAndKey: preGetTokenAndKey
};
}];
});
I configure it before calling the first REST service.
app.config(function(MyRestServicesProvider) {
MyRestServicesProvider.setBaseUrl('https://www.test.com/rest/');
});
And then I have a HeadCtrl controller which should call preGetTokenAndKey to get key and token which is needed for some other REST calls like getMyData.
app.controller('HeadCtrl', function (MyRestServices) {
MyRestServices.preGetTokenAndKey().success(function(data) {
var key = data.dataSection.key;
var token = data.dataSection.token;
});
});
My problem is I want to call getMyData from another controller, but I need key and token to make this call.
So I need to wait until preGetTokenAndKey was successful and I have to provide the two values to the MyRestServices provider.
How can I solve these problems?
It sounds like a better solution would be to chain them within your service itself. You'd setup your own promise within preGetTokenAndKey, which gets resolved by the $http call. Subsequent calls to preGetTokenAndKey() would just return the already resolved data w/o making additional $http calls.
So something along the lines of the following should get you started:
app.provider('MyRestServices', function() {
this.baseUrl = null;
this.setBaseUrl = function(_baseUrl) {
this.baseUrl = _baseUrl;
};
this.$get = ['$http', function($http) {
var _baseUrl = this.baseUrl;
var _tokenAndKey = {};
function getMyData() {
return preGetTokenAndKey().then(function (data) {
return $http.get(_baseUrl + 'data1/?token=' + data.dataSection.token + '&key=' + data.dataSection.key);
});
}
function preGetTokenAndKey() {
if(!_tokenAndKey.set) {
_tokenAndKey.deferred = $http.get(_baseUrl + 'keyAndToken/').then(function(data) {
_tokenAndKey.set = true;
return data;
});
}
return _tokenAndKey.deferred.promise;
}
return {
getMyData: getMyData,
preGetTokenAndKey: preGetTokenAndKey
};
}];
});
My problem is I want to call getMyData from another controller,
If so, you can use $broadcast to notify other controller that async call resolved and you have key/token
app.controller('HeadCtrl', function($rootScope, MyRestServices) {
MyRestServices.preGetTokenAndKey().success(function(data) {
var key = data.dataSection.key;
var token = data.dataSection.token;
$rootScope.$broadcast("getMyDataTrigger", {key: key,token: token});
});
});
In other controller implement listener:
$rootScope.$on("getMyDataTrigger", function(event, data){
if(data){
MyRestServices.getMyData(data.key, data.token);
// ...
}
});
Just override getMyData:
function getMyData(key, token) {
return $http.get(_baseUrl + 'data1/?token=' + token + '&key=' + key);
}

Trying to get an async DB request to work in Angular, "Cannot call method then of undefined"

I'm building a PhoneGap app using AngularJS + an SQLite database. I am having a classic "How does asynchronous work" Angular problem with a database query, getting error "Cannot call method then of undefined". I am hoping someone can help me to see the error of my ways.
Here's my query function. Every alert() in here returns meaningful data indicating that the transaction itself is successful:
.factory('SQLService', ['$q', '$rootScope', 'phonegapReady',
function ($q, $rootScope, phonegapReady) {
function search(query) {
alert("Search running with " + query);
var promise = db.transaction(function(transaction) {
var str = "SELECT category, id, chapter, header, snippet(guidelines, '<b>', '</b>', '...', '-1', '-24' ) AS snip FROM guidelines WHERE content MATCH '" + query + "*';";
transaction.executeSql(str,[], function(transaction, result) {
var resultObj = {},
responses = [];
if (result != null && result.rows != null) {
for (var i = 0; i < result.rows.length; i++) {
resultObj = result.rows.item(i);
alert(resultObj.category); //gives a meaningful value from the DB
responses.push(resultObj);
}
} else {
//default content
}
},defaultNullHandler,defaultErrorHandler);
alert("End of transaction");
});
// Attempting to return the promise to the controller
alert("Return promise"); //this alert happens
return promise;
}
return {
openDB : openDB,
search: search
};
}]);
And in my controller, which gives the "Cannot call method then of undefined" error:
$scope.search = function(query) {
SQLService.search(query).then(function(d) {
console.log("Search THEN"); //never runs
$scope.responses = d; //is never defined
});
}
Thanks to the accepted answer, here is the full working code.
Service
function search(query) {
var deferred = $q.defer();
db.transaction(function(transaction) {
var str = "SELECT category, id, chapter, header, snippet(guidelines, '<b>', '</b>', '...', '-1', '-24' ) AS snip FROM guidelines WHERE content MATCH '" + query + "*';";
transaction.executeSql(str,[], function(transaction, result) {
var resultObj = {},
responses = [];
if (result != null && result.rows != null) {
for (var i = 0; i < result.rows.length; i++) {
resultObj = result.rows.item(i);
responses.push(resultObj);
}
} else {
resultObj.snip = "No results for " + query;
responses.push(resultObj)
}
deferred.resolve(responses); //at the end of processing the responses
},defaultNullHandler,defaultErrorHandler);
});
// Return the promise to the controller
return deferred.promise;
}
Controller
$scope.search = function(query) {
SQLService.search(query).then(function(d) {
$scope.responses = d;
});
}
I can then access the responses in the template using $scope.responses.
The question here is: what does db.transaction return.
From the way you're using it, I'm guessing it's some 3rd-party code that doesn't return a promise.
Assuming that you're using it correctly (your alert shows the right results), you need to actualy use $q to get the promise working.
Something like this:
function search(query) {
// Set up the $q deferred object.
var deferred = $q.defer();
db.transaction(function(transaction) {
transaction.executeSql(str, [], function(transaction, result) {
// do whatever you need to do to the result
var results = parseDataFrom(result);
// resolve the promise with the results
deferred.resolve(results);
}, nullHandler, errorHandler);
});
// Return the deferred's promise.
return deferred.promise;
}
Now, in your controller, the SQLService.search method will return a promise that should get resolved with the results of your DB call.
You can resolve multiple promises. Pass the array of queries as args
function methodThatChainsPromises(args,tx){
var deferred = $q.defer();
var chain = args.map(function(arg){
var innerDeferred = $q.defer();
tx.executeSql(arg,[],
function(){
console.log("Success Query");
innerDeferred.resolve(true);
},function(){
console.log("Error Query");
innerDeferred.reject();
}
);
return innerDeferred.promise;
});
$q.all(chain)
.then(
function(results) {
deferred.resolve(true)
console.log("deffered resollve"+JSON.stringify(results));
},
function(errors) {
deferred.reject(errors);
console.log("deffered rejected");
});
return deferred.promise;
}

jQuery getting jSon data but not returning/assigning value

I am using jQuery to call a controller, the controller is returning a value. the jQuery is getting the value however it is not setting it to my variable and returning it. what am I doing wrong here?
GetDepartmentID is called with a value of 1. It goes to the controler, the controller returns the departmentID which is 1.
console.log("Inside-DepartmentID " + data) in the console this shows 1 so I know the data is being returns from the controller.
I then assign data to departmentID. Return it. Then my outer function tries to console.log the return and it is undefined. I don't get it.
The .change function calls the GetdepartmentID(1);
function GetDepartmentID(functionID) {
var departmentID;
jQuery.getJSON("/MasterList/GetDepartmentID/" + functionID, null, function (data) {
console.log("Inside-DepartmentID " + data)
departmentID = data;
});
return departmentID;
}
jQuery('#functionID').change(function () {
var functionID = jQuery(this);
//console.log(functionID.val());
var value = GetDepartmentID(functionID.val());
console.log("test " + value);
//GetOwnerList(value);
});
You can try this way to process the data returned back from AJAX call.
function processResults(departmentID)
{
console.log("test " + departmentID);
GetOwnerList(departmentID);
// Someother code.
}
function GetDepartmentID(functionID, callBack) {
jQuery.getJSON("/MasterList/GetDepartmentID/" + functionID, null, function (data) {
console.log("Inside-DepartmentID " + data)
callBack(data); //Invoke the callBackhandler with the data
});
}
jQuery(function(){
jQuery('#functionID').change(function () {
var functionID = jQuery(this);
//console.log(functionID.val());
GetDepartmentID(functionID.val(), processResults); // pass function as reference to be called back on ajax success.
});
});
Or just do this way: This is as good as putting all your subsequent processing code inside your getJSON handler.
function processResults(data)
{
//handle the data here.
}
function GetDepartmentID(functionID) {
jQuery.getJSON("/MasterList/GetDepartmentID/" + functionID, null, processResults);
}
jQuery(function(){
jQuery('#functionID').change(function () {
var functionID = jQuery(this);
//console.log(functionID.val());
GetDepartmentID(functionID.val()); // pass function as reference to be called back on ajax success.
});
});

Categories