Parsing json on Angular - angularjs

I have a table made from a JSON, there is a button on every row and when you click it invokes a web service passing the element id. The web services tryes to delete the element from the database, if it can be deleted returns a simple JSON with the attributte 'status' and two possible values 'ERASED' (if deleted) or 'IN_USE' (if not). When I click on the button the web service answers ok ('IN_USE' actually). But when I try to read the 'status' value for show a message (depending if it's 'IN_USE' or 'ERASED') it returns me 'undefined' and don't know why. I've been making some tricks but still don't work. I also did the web service with slim framework 2.
The controller (just the function with troubles):
$scope.show = function (id) {
$http.get('http://10.0.203.73/WS/ws.php/tipusactius/edita/elimina/' + id + '.json').success(function (data) {
$scope.sts = data.status;
$window.alert($scope.sts);
});
if ($scope.sts.status == 'IN_USE') {
$window.alert('Aquest atribut no es pot eliminar perque és en ús');
}
}
There is the web service (it's done with slim framework 2):
$app->get('/tipusactius/edita/elimina/:id.json', function($id){
header("Content-Type: application/json");
$SQL = 'DELETE FROM atributs_actiu WHERE idatributs_actiu = '.$id;
error_log('DELETE STATEMENT: '.$SQL, 0);
$mysqli = getDB();
$r = $mysqli->query($SQL);
error_log(mysqli_error($mysqli));
if(!$r){
$results[] = array( 'status' => 'IN_USE' );
}
else{
$results[] = array( 'status' => 'ERASED' );
}
echo json_encode($results);
});
The web services run ok, but I'm getting an undefined on the console when I try check the status value.
Solved:
There was two mistakes on this case:
1-The funciton is asynchronous, so even I get something from the server the message can be still being 'undefined'
2-I wasn't caching the 'status' value appropiettly.
This is how i did it finally:
$scope.sts[0].status
All this inside $http.get function as Marius Wirtherle said:
Your Problem is probably that the $http Request is executed
asynchronously. So the Request is not finished yet when you do the
$window.alert
Modify your code like this to use wait for the $http Promise to
Resolve:
$scope.show = function(id){
$http.get('http://10.0.203.73/WS/ws.php/tipusactius/edita/elimina/' +
id + '.json')
.then(function(response){ // success callback (.success is deprecated)
$scope.sts = response.data.status;
if ($scope.sts == 'IN_USE') {
$window.alert('Aquest atribut no es pot eliminar perque és en ús');
}
}, function(response){ //error callback
$window.alert(response.statusText);
});
}
Further reading on $http:
https://docs.angularjs.org/api/ng/service/$http

Your Problem is probably that the $http Request is executed asynchronously. So the Request is not finished yet when you do the $window.alert
Modify your code like this to use wait for the $http Promise to Resolve:
$scope.show = function(id){
$http.get('http://10.0.203.73/WS/ws.php/tipusactius/edita/elimina/' + id + '.json')
.then(function(response){ // success callback (.success is deprecated)
$scope.sts = response.data.status;
if ($scope.sts == 'IN_USE') {
$window.alert('Aquest atribut no es pot eliminar perque és en ús');
}
}, function(response){ //error callback
$window.alert(response.statusText);
});
}
Further reading on $http: https://docs.angularjs.org/api/ng/service/$http
(Also i think you have a .status to much in your code. One at line $scope.sts = data.status; and then in if($scope.sts.status == ...). So its basically data.status.status)

Related

kinvey fetching and remove not working (AngularJS)

I have this problem with kinvey backend,
I'm trying to fetch data from my collection but it doesn't work for me. here is my code :
var query = new $kinvey.Query();
query.equalTo('_id', '5909e8084c68b1ef74fa4efc');
var dataStore = $kinvey.DataStore.collection('User1Bases', $kinvey.DataStoreType.Network);
var stream = dataStore.find(query);
stream.subscribe(function onNext(entity) {
// ...
}, function onError(error) {
// ...
}, function onComplete() {
//...
});
Can you help me please
If you let run the code you have posted then consider four things:
Make sure you have Kinvey implemented:
<script src="https://da189i1jfloii.cloudfront.net/js/kinvey-html5-sdk-3.10.2.min.js"></script>
Make sure you have initialized the Kinvey service before:
// Values shown in your Kinvey console
Kinvey.init({
appKey: '<your_appKey>',
appSecret: 'your_appSecret'
});
Make sure you are logged in with a user that has the rights to read your collection (should be fine using the All Users role (default)):
var promise = Kinvey.User.login('<username>', '<password>')
.then(function() {
console.log ("You are logged in");
})
.catch(function(error) {
console.log (error);
});
Output the return result to see whats coming back. To make sure you do the query AFTER successful login, paste you query inside the .then function of login.
I'm not sure if your query is valid unter 3.x since a lot has changed and I'm not working with older Kinvey versions.
So that all together would look like this:
// Initialize Kinvey
Kinvey.init({
appKey: '<your_appKey>',
appSecret: 'your_appSecret'
});
// Login with already registered user
var promise = Kinvey.User.login('<username>', '<password>')
.then(function() {
console.log ("You are logged in");
// Your query
var query = new $kinvey.Query();
query.equalTo('_id', '5909e8084c68b1ef74fa4efc');
var dataStore = $kinvey.DataStore.collection('User1Bases', $kinvey.DataStoreType.Network);
var stream = dataStore.find(query);
stream.subscribe(function onNext(entity) {
// Output of returning result
console.log (entity);
// ...
}, function onError(error) {
// ...
}, function onComplete() {
//...
});
})
.catch(function(error) {
console.log (error);
});
There are now three return sets possible:
Nothing (as you say) -> Something missing/wrong in the code (compare yours with mine)
Empty array: Your query didn't find anything, adapt the search value(s)
One or more entries in the array -> All fine, what you were looking for!
Hope that helps!
When querying by _id there is a built in method: http://devcenter.kinvey.com/angular/guides/datastore#FetchingbyId
Try switching to var stream = dataStore.findById('entity-id');
Also check to make sure you don't have any preFetch or postFetch BL that is interfering with the query.

Satellizer OAuth Unlinking gives 404 error

I'm testing satellizer example with Laravel back end for Facebook, once user links the Facebook account to the app its impossible to unlink it with satellizer, whenever user clicks Facebook Unilink button it gives 404 error,
http://localhost:8000/auth/unlink
404 Not found.
But on Laravel router.
Route::get('auth/unlink/{provider}', ['middleware' => 'auth', 'uses' => 'AuthController#unlink']);
Please help me to fix this bug.
Did you find the solution for this?
After check the below link I end up founding a solution for my issue.
https://github.com/sahat/satellizer/issues/269
Basically in the Satellizer documentation explain that provider and httpOptions was the parameters you can send via the unlink call, however, the options never gets passed as it only retrieves the information from the first parameter which is the provider.
You can see a bit more about the accepted parameters in the piece of code below that is inside of the satellizer.js file.
OAuth.prototype.unlink = function (provider, httpOptions) {
if (httpOptions === void 0) { httpOptions = {}; }
httpOptions.url = httpOptions.url ? httpOptions.url : joinUrl(this.SatellizerConfig.baseUrl, this.SatellizerConfig.unlinkUrl);
httpOptions.data = { provider: provider } || httpOptions.data;
httpOptions.method = httpOptions.method || 'POST';
httpOptions.withCredentials = httpOptions.withCredentials || this.SatellizerConfig.withCredentials;
return this.$http(httpOptions);
};
My not so elegant solution is as below:
html
<button class="btn btn-sm btn-danger float-left" ng-if="user.facebook"
ng-click="unlink({provider:'facebook', options: {'param1':'value','param2':'value2'}})"><i class="ion-social-facebook"></i> Unlink Facebook Account
</button>
I have basically wrapped the information I want to send by the variable provider (renamed to just data) in the JS code below.
//unlink a social login profile from user's profile
$scope.unlink = function (data) {
console.log(data);
$auth.unlink(data)
.then(function () {
toastr.info('You have unlinked a ' + data.provider + ' account');
$scope.getProfile();
})
.catch(function (response) {
toastr.error(response.data ? response.data.message : 'Could not unlink ' + data.provider + ' account', response.status);
});
The JSON sent via view does not look pretty but works:
provider Object
provider "facebook"
options Object
flag "unlink"
view "profile"
userId 236
Nothing of the above resolved the 404 issue but resolve the passing of parameters from the original satellizer unlink function.
The issue with the route happens because Laravel is blocking that route in the file Authenticate.php inside of the function "public function handle($request, Closure $next)"
You can ether route without the middware like this
Route::post('auth/unlink', 'AuthController#unlink');
Route::get('auth/unlink', 'AuthController#unlink');
Route::any('auth/unlink', 'AuthController#unlink');
The above will make sure the call will hit the controller one whay or another. how you are getting the parameters in the controller will depend if you choose post/get/any. Meaning you will retrieve the parameters via Laravel variable $request from
public function unlink(Request $request)
or using the Input facade like this
$input = Input::all();
in here you can do whatever you want with the variable values passed. Now is up to you on the handling.
Note: The satellizer code sets by default the method to POST if no method is passed in the httpOptions as you can see below:
OAuth.prototype.unlink = function (provider, httpOptions) {
if (httpOptions === void 0) { httpOptions = {}; }
httpOptions.url = httpOptions.url ? httpOptions.url : joinUrl(this.SatellizerConfig.baseUrl, this.SatellizerConfig.unlinkUrl);
httpOptions.data = { provider: provider } || httpOptions.data;
httpOptions.method = httpOptions.method || 'POST';
httpOptions.withCredentials = httpOptions.withCredentials || this.SatellizerConfig.withCredentials;
return this.$http(httpOptions);
};
That does not really helps when the code with the Laravel example comes with the route calling the get method not the post and in the js example no options of http is set to get. Meaning you are trying to call get where post is the default therefore the route will never work.
Sorry if I am not more clear as this is my first time trying to put my thinking here and English is not really my first language.
Good luck.

How to roll back changes when there is an error in a promise chain

In my angular app I want to make changes to several locations in my firebase with a mix of transactions and set. I have written a promise chain with a little help. Now I need to handle any errors that may occur.
In the event of an error on any of the promises I would want to roll back any changes made in firebase (the successful promises) and alert the user to the failure.
Current code below
$scope.addNewPost = function() {
var refPosts = new Firebase(FBURL).child('/posts').push();
// Get tags into array for incrementing counters
var tags = $scope.post.tags.split(', ');
var allPromises = [];
// Iterate through tags and set promises for transactions to increment tag count
angular.forEach(tags, function(value, index){
var dfd = $q.defer();
var refTag = new Firebase(FBURL).child('/tags/' + value);
refTag.transaction( function (current_value) {
return current_value + 1;
}, function(error, committed, snapshot) {
if (committed) {
dfd.resolve( snapshot );
} else {
dfd.reject( error );
}
});
allPromises.push( dfd.promise );
});
// Add promise for setting the post data
var dfd = $q.defer();
refPosts.set( $scope.post, function (error) {
if (error) {
dfd.reject(error);
} else {
dfd.resolve('post recorded');
}
});
allPromises.push( dfd.promise );
$q.all( allPromises ).then(
function () {
$scope.reset(); // or redirect to post
},
function (error) {
// error handling goes here how would I
// roll back any data written to firebase
alert('Error: something went wrong your post has not been created.');
}
);
};
So what I need to know is how do I roll back any changes that happen to my firebase data in the event that one of these promises fail. There could be any number of updates happening in firebase. (for example: 3 tags being incremented via transaction and the post data being set)
How would I write the failure function to calculate what was successful and undo it? If this is this even possible.
--------------- sub question from original post has been solved ---------------
Also how do you force errors? I've tried setting a variable like below but it doesn't seem to work, is there something wrong with my .then?
refPosts.set( $scope.post, function (error) {
var forceError = true;
if (forceError) {
dfd.reject(forceError);
} else {
dfd.resolve('post recorded');
}
allPromises.push( dfd.promise );
});
There are two instances of this line, and they are both in the wrong place:
allPromises.push( dfd.promise );
In the first block, it should be in the last statement in the forEach callback, not in the transaction callback.
In the second block, it should be after the call to set(), not in the callback.
The way your code is written now, $q.all() is getting an empty array of promises. That could also be what's interfering with the forceError test you're attempting.

How to send ajax response to Jquery from CakePhp?

I have this script in a view:
<script type="text/javascript">
$(document).ready(function() {
$("#addbrand").click(function() {
$.ajax({
url : '../brands/add',
data : {
name : "test",
shortname : "tst"
},
dataType : 'json',
success : function(html, textStatus) {
alert('Success ' + textStatus + html);
},
error : function(xhr, textStatus, errorThrown) {
alert('An error occurred! ' + errorThrown);
}
});
});
});</script>
And in add controller I have these lines:
... else if($this->request->is('ajax')){
if ($this->Brand->save($this->request->query)) {
// How to send feedback!?
}else{
// How to send feedback!?
}
$this->autoRender = false;
exit();
}
When I click addbrand, Ajax operation runs successfully and a I can see the added row in database, but I don't know how to send an error or success message to the user. I've read several tutorials but none of them were about cakephp2.0 while Everything is changed in 2.x.
I've also read JSON and XML views but unfortunately I didn't understand anything!!!
I need to send a status code. If the status was OK then I ought to to send an array of Strings (brand names actually) and if status is not OK I should send a string that explains why the operation is not completed successfully.
I'd be most grateful if anybody can help me. Thanks
Update:
I changed the code. I used CakeResponse() and now my action is like this:
if($this->RequestHandler->isAjax()){
if ($this->Brand->save($this->request->query)) {
return new CakeResponse(array('body'=> json_encode(array('val'=>'test ok')),'status'=>200));
}else{
return new CakeResponse(array('body'=> json_encode(array('val'=>'test not ok')),'status'=>500));
}
}
Using CakeResponse I can handle the possible responses in Jquery well.
$("#addbrand").click(function() {
$.ajax({
url : '../brands/add',
data : {
name : "test",
shortname : "tst"
},
dataType : 'json',
success : function(data) {
alert("The brand has been saved");
},
error : function(data) {
alert("Eorror occured");
},
complete : function(data) {
alert($.parseJSON(data.responseText).val);
}
});
});
Although it seems to me that everything is working now and I can send several variables through the Ajax between client and server in JSON format, I need to know if it's a standard way of sending Ajax responses in CakePHP or not? Is there any other simpler way for doing this?
The following lines of code do exactly whatever return new CakeResponse(array('body'=> json_encode(array('val'=>'test ok')),'status'=>200)); does in my question:
$this->set('val','test ok');
$this->set('_serialize',array('val'));
$this->response->statusCode(200);
Remember that you need to do two important things:
Add Router::parseExtensions('json'); to App/Config/routs.php.
Add var $components = array("RequestHandler"); to your controller.
I think this way is better because you don't need to return anything. In previous solution we had to return cakeresponse object and this, sits uneasy with the nature of actions.
You should use the JSON views with route extensions:
Firstly you need to set up route extensions. This is generally done with:
Router::parseExtensions('json'); // In App/Config/routes.php
This will enable Router to handle the 'json' extension and to know how to handle a request like:
www.example.com/people/index.json
if($this->RequestHandler->isAjax()){
if ($this->Brand->save($this->request->query)) {
//Logic for success
} else {
//Logic for save failure
}
}
At this point you have the ability to choose between using the data views with the serialize key or using a data view with view files (copyed from the CakeBook):
<?php
// Controller code
class PostsController extends AppController {
public function index() {
$this->set(compact('posts', 'comments'));
}
}
// View code - app/View/Posts/json/index.ctp
foreach ($posts as &$post) {
unset($post['Post']['generated_html']);
}
echo json_encode(compact('posts', 'comments'));
Notice that the view is located under .../Views/Posts/json/...
You can have multiple extensions in the router so you can return and handle all kinds of contents - after all it is all just data representation.
Cheers!

Cakephp jquery debug info inside the ajax response

I have a cakephp code that works with the database to search a given card id number and return the balance. the jquery code looks like this.
function subm(event){
$.ajax({
type: "POST",
//contentType: "application/json; charset=utf-8",
dataType:'json',
url:"\/balances\/balance",
data:$("#button_check_balance").closest("form").serialize(),
cache: false,
beforeSend:function(){
$("#loadingDiv").show(1000);
},
success:function (data, textStatus,xhr) {
$("#loadingDivision").hide(1000);
alert("balance is "+data.balance);
return false;
},
//failure: function(msg){alert(msg);},
error: function(xhr, ajaxOptions, thrownError){
$("#loadingDivision").hide(1000);
alert("readyState: "+xhr.readyState+"\nstatus: "+xhr.status);
console.log(xhr.responseText);
},
/*complete: function(){
alert("complete");
},*/
});
I have the balancesController and balance.ctp files in place and controller logic looks like this.
function balance() {
$message = "";
$error = "";
$this->layout = 'ajax'; //layout should be ajax based on
Configure::write('debug', 0);
//gets the submitted card number
$card_id = $this->data['balances']['cardId']; //entered card id of the emp
if (!empty($this->data)) {
$this->header('Content-Type: application/json');
try {
$card = $this->Card->getBalance($card_id);
} catch (Exception $e) {
$error = "balance not available";
$resp = json_encode(array('error' => $error));
echo $resp;
exit;
}
if ($this->RequestHandler->isAjax()) {
$this->autoRender = $this->layout = false;
$resp = json_encode(array('cardData' => $cardObj);
echo $resp;
exit;
}
}
}
th problem that I have is - when a balance not available error is occurred "I AM GETTING THE CAKE DEBUG INFOMATION IN MY AJAX RESPONSE."
eg - when I try to access xhr object inside error function on $.ajax event
using "xhr.responseText" I am getting the long output consisting of
<pre class="cake-debug">.......... and at the end of this ONLY I get the error that I have encoded into json.
{"error":"error...."}
I have used Configure::write('debug', 1); and Configure::write('debug', 0); without any luck.as u can see I used Configure::write('debug', 0); in the top of my controller function as well..
please advice me resolve this issue. all your input is very highly appreciated.
If you're getting the debug message that means you have an error in your code and you should fix it instead of hiding it. Read the error message (or paste it here) to find out and fix the problem
You're using a throw/catch. Cake usually does not use exceptions to handle errors, unless you've specifically coded your model to throw exceptions, your error state won't be captured. Possibly $card is just returning false.
Please paste your error here, or on pastebin if it's really long.

Resources