I'm a newbee to JS , JSON and AJAX. I'm using it to develop a simple apps in my SAP env. I'm bit struck in converting the AJAX response to java array. What is have in the code is:
function addTable()
{
var urls = new Array();
$(document).ready(function ()
{
var params = getURLParam().split('?');
$.post("GetBayDetails.htm", {url: getURLParam(), params: params[1]})
.done(function (data)
{
var url = $.parseJSON(data);
urls.push(JSON.parse(url));
$.each(url, function (i, v)
{
push.urls[i] = v.bay;
});
});
});
alert(urls[2]);
}
but if I loop through "URLS" I do not see any value appended to the array. Please can anyone provide some help to get this fixed?
Try this. My changes are:
Use the "json" dataType argument to $.post so it parses the response automatically.
There's no need to use $(document).ready() inside a function that you call on demand. This is only needed when performing initial actions that have to wait for the DOM to be loaded.
It's not necessary to call JSON.parse(url), as this is already parsed.
The correct way to add to the urls array is urls.push(v.bay).
The preferred way to initialize an array is with [], not new Array().
alert(urls[2]) needs to be in the .done() function. Otherwise you're alerting before the AJAX call has completed.
function addTable() {
var urls = [];
var params = getURLParam().split('?');
$.post("GetBayDetails.htm", {url: getURLParam(), params: params[1]}, "json")
.done(function (url) {
$.each(url, function (i, v) {
urls.push(v.bay);
});
alert(urls[2]);
});
}
DEMO
Related
There are two ways I can GET a REST resource by ID:
GET /users/1
GET /users/1,2
The first returns a single object like {id:1,name:"John"} while the second returns an array like [{id:1,name:"John"},{id:2,name:"Jill"}].
Please, no arguments about whether or not this is legit REST; just accept that a service has this and I need to work with it.
angular's $resource actually intelligently handles it from the request side:
User.get({users:['1','2']})
transforms into
GET /users/1,2
But it doesn't handle the response well. It expects a single object. If I change the definition to isArray:true, then it fails on a single request GET /users/1
How do I get it to intelligently handle both?
EDIT: I did some weird hacking to get it to work, but would prefer a native method:
factory('Resource',['$resource','_',function ($resource,_) {
return function(url,params,methods){
var defaults = {
getSingle: {method: 'get', isArray:false},
getMultiple: {method: 'get', isArray:true}
}, resource = $resource(url,params,angular.extend(defaults,methods)), urlParams = {};
_.each(url.split(/\W/), function(param){
if (param && (new RegExp("(^|[^\\\\]):" + param + "\\W").test(url))) {
urlParams[param] = true;
}
});
// do not override if they did
if (!(methods||{}).get) {
resource.get = function (params,success,error) {
// look for multiples
var isMultiple = false;
_.each(params,function (val,key) {
if (key && urlParams[key] && angular.isArray(val)) {
isMultiple = true;
return(false);
}
});
return this[isMultiple?"getMultiple":"getSingle"](params,success,error);
};
}
return(resource);
};
}]).
The normal convention is to create a Resource.get() method for single objects, and a Resource.query() method for arrays of them.
I had a similar issue with the WP-API when trying to do a PUT request to a post. Currently that API returns an object representing the post if everything went okay, but if there is an error (eg the authorization credentials don't match) then it returns an array of errors. So I was getting the error Error: [$resource:badcfg] Error in resource configuration. Expected response to contain an object but got an array.
I managed to find a solution by using the transformResponse property on my custom action object. I define a function which inspects the response and then if it is an array, it converts the array into an object. This seems to work okay, and seems a bit less complex than the solution you posted in your update:
var wpPost = $resource(PATH_TO_WORDPRESS_API + 'posts/:id', {},
{
'update': {
method: 'PUT',
params: {id: '#id'},
transformResponse: function(data) {
var response = angular.fromJson(data);
if (response.length) {
// the response is an array, so convert it into an object
var object = {};
for( var i = 0; i < response.length; i ++) {
object[i] = response[i];
}
return object;
} else {
return response;
}
}
}
});
I'm using staticFilesLoader with partialLoader wich is working really good! So the concept of addPart(home) method in partialLoader says that you do not need to load all the translate table.
Starting for that point. I'm gonna use a rest service now and my question is How to send to the rest service the parameter for just retrieving me the table translate for my specific section, in this example home.
Source Code from angular translate
function $translateUrlLoader($q, $http) {
'use strict';
return function (options) {
if (!options || !options.url) {
throw new Error('Couldn\'t use urlLoader since no url is given!');
}
var requestParams = {};
requestParams[options.queryParameter || 'lang'] = options.key;
return $http(angular.extend({
url: options.url,
params: requestParams,
method: 'GET'
}, options.$http))
.then(function(result) {
return result.data;
}, function () {
return $q.reject(options.key);
});
};
}
The code above doesn't have any extra parameter.
NOTE: Maybe in the specific case of urlLoader with partialLoader you should request all the table translate from the REST and only manage the parts in the frontend. Please tell me about this note if makes any sense.
Problem description
Im using the angular resource to get data from my server. I've extended it a bit to make sure all of my resources have security headers.
Problem is that on the second get request and on, my get requests are sent with limit=0, and only the first get request is sent correctly (with limit=12).
Code part
This is my base resource factory (for making sure all resource contain the keys and everything):
app.factory('SecuredFactory', function($resource){
var DEFAULT_ACTIONS = {
'get': {method:'GET'},
'query': {method:'GET', isArray:true},
};
var DEFAULT_PARAMS = {
'limit': 12,
'format': 'json'
};
for(var key in DEFAULT_ACTIONS){
DEFAULT_ACTIONS[key]['headers'] = <headers object>;
}
var securedResource = function(url, paramDefaults, actions){
for (var attrname in actions) {
DEFAULT_ACTIONS[attrname] = actions[attrname];
}
for (var attrname in paramDefaults) {
DEFAULT_PARAMS[attrname] = paramDefaults[attrname];
}
var defaultResource = $resource(url, DEFAULT_PARAMS, DEFAULT_ACTIONS);
return defaultResource;
};
return securedResource;
});
And this is an example of how I creat a specific factory out of the secured one:
app.factory('QuestionFactory', function(SecuredFactory, Constants){
var url = Constants.SERVER_URL + 'question/';
var Task = SecuredFactory(url);
return Task;
});
And this is finally how I use it, for example:
// filtering example (not important for this matter):
var filtering = {author: "Daniel"};
var contents = [];
var resource = QuestionFactory;
resource.get(filtering, function (res) {
// success fetching
$scope.contents = $scope.contents.concat(res['objects']);
}
// failed fetching
, function (err) {
}
);
The requests
first request:
question?format=json&limit=12&offset=0
second request and on:
question?format=json&limit=0&offset=0
My problem was that the DEFAULT_PARAMS variable was declared as global. I didn't realize that invoking the secured factory with {limit: 0} will override the global, therefore changing the limit to 0 for ALL of my resources.
Changing the securedFactory to a service and moving the "globals" into the returned function solved it. Had to add new ofcourse before every securedService call.
Hi I'am trying a simple example of using a controller and a factory to get some data back to the view but for some reason I can't print it.
I managed to get the ajax call to work.
If I type the
$scope.sampleStyles = [{ sample: 'text here', text : 'dasdas'}
and don't use the ajax call it works
UPDATE: if I add an alert before assigning to my scope it works (ajax has time to do his thing)
anyone know how to overcome that?
CODE:
var packageApp = angular.module("packageApp", []);
packageApp.controller("MyController", function($scope, myFactory){
$scope.sampleStyles = [];
function init(){
$scope.sampleStyles = myFactory.getSampleStyles();
}
init();
});
packageApp.factory('myFactory', function($http, $log){
var factory = {};
var sampleStyles = [];
var tempData = {};
factory.update = function(){
$.ajax({
type: 'POST',
url: '/account/fetch-sample-styles',
data: {
source: 'ajax'
},
success: function(data, textStatus, XMLHttpRequest){
tempData = data;
}
});
alert(tempData);
sampleStyles = tempData;
}
factory.getSampleStyles = function(){
factory.update();
return sampleStyles;
};
return factory;
});
Are you using the AngularJs $http service? If so it will return a promise which you then operate on. Here is more on promises from the AngularJs docs.
My guess is, you are using an ajax.get(...) with a success callback defined inside. The problem is probably due to the success callback not belonging to the "AngularJs world."
To fix this, you need to tell AngularJs that its scope has changed. Use the $[Root]scope.$apply() function, and have the scope injected into your service as a dependency.
Something like this inside the factory:
$.ajax({
url: "/api/some/end/:point",
...
success: function(data) {
$scope.$apply(function() {
$scope.sampleStyles = data; // etc
});
}
});
I strongly recommend that you look into the $http service, it makes the above code much nicer, and is designed to play nice with the $scope.
$http.get("/api/end/point").then(function(response) {
// response.data points at the page data sent back, assuming that your
// api endpoint sends back JSON of the likes of
// { status: "SUCCESS", styles: [...] }
$scope.sampleStyles = response.data.styles;
});
EDIT:
Now that you posted some code, it seems like the root of your issue is based on the fact that the ajax get is an async call. Why are you even messing with using a temporary variable? Why not the following?
factory.update = function(){
$.ajax({
type: 'POST',
url: '/account/fetch-sample-styles',
data: {
source: 'ajax'
},
success: function(data, textStatus, XMLHttpRequest){
sampleStyles = data;
}
});
}
If you really wanted to make the $.ajax call blocking, you can set async: false in the $.ajax properties.
EDIT 2:
Fixed some broken links, sorry I am a SO newb :(
I've got several resource classes that look like this:
.factory('SettingsResource', function (DefaultResource) {
var endpoint = '/settings';
var params = {};
var options = {};
return new DefaultResource(endpoint, params, options);
}
All the resource classes use DefaultResource as a "base":
.factory('DefaultResource', function ($resource, UserResource) {
var baseURL = 'rest',
baseParams = {
currentRole: function () {
return "Admin";
}
},
baseOptions = {
}
return function (endpoint, params, options) {
...
// Code ommited
};
}
As you can see there's a default parameter called 'currentRole' which I need to append to every request.
Currently the parameter is hard coded, but I should actually get it from an http call, e.g. like this:
currentRole: function () {
$resource.get('rest/currentRole').$then(function (response) {
return response.data;
});
}
I already tried using a Provider and trying to make the http call within the config function. But obviously one is not allowed to do this (only providers can be injected, I cannot use $resource.get within the config-function).
Has anyone a clue how I could do this? Basically: how can I add dynamic, asynchronously loaded default parameters to a resource?
I'd really appreciate your help!
Michael