I want the following loop to go through every instance of matchCenterItem, yet for some reason, it pings ebay using the properties of only the first instance. The console logs at the end of the function however, loop through all instances and log their respective properties.
Parse.Cloud.define("MatchCenterTest", function(request, response) {
var matchCenterItem = Parse.Object.extend("matchCenterItem");
var query = new Parse.Query(matchCenterItem);
var promises = [];
query.limit(10);
query.find().then(function(results) {
for (i=0; i<results.length; i++) {
url = 'http://svcs.ebay.com/services/search/FindingService/v1';
promises.push(Parse.Cloud.httpRequest({
url: url,
params: {
'OPERATION-NAME' : 'findItemsByKeywords',
'SERVICE-VERSION' : '1.12.0',
'SECURITY-APPNAME' : '*App ID goes here*',
'GLOBAL-ID' : 'EBAY-US',
'RESPONSE-DATA-FORMAT' : 'JSON',
'REST-PAYLOAD&sortOrder' : 'BestMatch',
'paginationInput.entriesPerPage' : '3',
'outputSelector=AspectHistogram&itemFilter(0).name=Condition&itemFilter(0).value(0)' : results[i].get('itemCondition'),
'itemFilter(1).name=MaxPrice&itemFilter(1).value' : results[i].get('maxPrice'),
'itemFilter(1).paramName=Currency&itemFilter(1).paramValue' : 'USD',
'itemFilter(2).name=MinPrice&itemFilter(2).value' : results[i].get('minPrice'),
'itemFilter(2).paramName=Currency&itemFilter(2).paramValue' : 'USD',
//'itemFilter(3).name=LocatedIn&itemFilter(3).Value' : request.params.itemLocation,
'itemFilter(3).name=ListingType&itemFilter(3).value' : 'FixedPrice',
'keywords' : results[i].get('searchTerm'),
},
// success: function (httpResponse) {
// // parses results
// var httpresponse = JSON.parse(httpResponse.text);
// response.success(httpresponse);
// console.log('MatchCenter Pinged eBay dude!');
// },
// error: function (httpResponse) {
// console.log('error!!!');
// response.error('Request failed with response code ' + httpResponse.status);
// }
}));
console.log(results[i].get('itemCondition'));
console.log(results[i].get('maxPrice'));
console.log(results[i].get('minPrice'));
console.log(results[i].get('searchTerm'));
}
});
Parse.Promise.when(promises).then(function(results) {
var httpresponse = JSON.parse(httpResponse.text);
response.success(httpresponse);
}, function(err) {
console.log('error!!!');
});
});
This is because the http request is asynchronous, and you're calling response.success in the completion handler for the first (and all) requests. Use the promise syntax and only complete when they are done. Simplified concept:
var promises = [];
for (...) {
promises.push(Parse.Cloud.httpRequest({...})); // no success/error params
}
Parse.Promise.when(promises).then(function(results) {
response.success(...);
}, function(err) {
});
Related
I've been trying to crack my problem for quite some time however no matter what I do I can't figure this out. Currently, following the docs from TinyMCE, this code is provided by them.
/* This represents a database of users on the server */
var userDb = {};
userNames.map(function(fullName) {
var name = fullName.toLowerCase().replace(/ /g, '');
var description = descriptions[Math.floor(descriptions.length * Math.random())];
var image = 'https://s3.amazonaws.com/uifaces/faces/twitter/' + images[Math.floor(images.length * Math.random())] + '/128.jpg';
return {
id: name,
name: name,
fullName: fullName,
description: description,
image: image
};
}).forEach(function(user) {
userDb[user.id] = user;
});
/* This represents getting the complete list of users from the server with only basic details */
var fetchUsers = function() {
return new Promise(function(resolve, _reject) {
/* simulate a server delay */
setTimeout(function() {
var users = Object.keys(userDb).map(function(id) {
return {
id: id,
name: userDb[id].name,
};
});
resolve(users);
}, 500);
});
};
/* This represents requesting all the details of a single user from the server database */
var fetchUser = function(id) {
return new Promise(function(resolve, reject) {
/* simulate a server delay */
setTimeout(function() {
if (Object.prototype.hasOwnProperty.call(userDb, id)) {
resolve(userDb[id]);
}
reject('unknown user id "' + id + '"');
}, 300);
});
};
return {
fetchUsers: fetchUsers,
fetchUser: fetchUser
};
})();
/* These are "local" caches of the data returned from the fake server */
var usersRequest = null;
var userRequest = {};
var mentions_fetch = function(query, success) {
/* Fetch your full user list from somewhere */
if (usersRequest === null) {
usersRequest = fakeServer.fetchUsers();
}
usersRequest.then(function(users) {
/* query.term is the text the user typed after the '#' */
users = users.filter(function(user) {
return user.name.indexOf(query.term.toLowerCase()) !== -1;
});
users = users.slice(0, 10);
/* Where the user object must contain the properties `id` and `name`
but you could additionally include anything else you deem useful. */
success(users);
});
};
When I try to change the fake server to get data from my actual server through an API route, however, I get .filter is not a function error. So I figured I would use the Object. values() method, but that doesn't return anything and the console log shows up empty.
This is my logic in my controller (I'm using Laravel btw)
public function getUsers(Request $request) {
$user = User::all();
return $user;
}
The filter problem happens when I change this line :
if (usersRequest === null) {
usersRequest = fakeServer.fetchUsers();
}
To my API call like this:
if (usersRequest === null) {
usersRequest = fetch('api/users/mention');
}
My API response is as follows:
[{id: 1, name: "John", email: "john#doe.com", email_verified_at: null,…},…]
0: {id: 1, name: "John", email: "john#doe.com", email_verified_at: null,…}
1: {id: 2, name: "Admin", email: "vi#example.com", email_verified_at: "2021-02-07 12:01:18",…}
2: {id: 3, name: "Admin2", email: "di#example", email_verified_at: "2021-02-07 12:01:46",…}
Figured it out! After painstakingly trying and trying, I managed to find a solution.
Wrap the tinymce script in a function, I wrapped mine in a function called function tinyMCE()
before the function, run an ajax api call
var usergetNames = [];
$.ajax({
url: '/api/users/mention',
method: 'get',
dataType: 'json',
contentType: 'application/json',
success: function (data) {
usergetNames = data;
tinyMCE();
},
error: function (ex) {
alert(ex.responseText);
}
});
In tinyMCE, replace var userNames line with this
var userNames = usergetNames;
You can get the rest of the code for tinymce mentions in their official documentation page.
function getList() {
SubCategoryService.getAllList().then(function (response) {
$scope.subCategoryList = response.data;
$scope.subCategoryDetailsList = [];
var subCategoryDetails = [];
for(var i=0; i < $scope.subCategoryList.length; i++) {
var subCategoryListData = $scope.subCategoryList[i];
var subcategory = {
'id' : subCategoryListData.id,
'category' : '',
'name' : subCategoryListData.name,
'created_on' : subCategoryListData.created_on,
'modified_on' : subCategoryListData.modified_on,
'is_deleted' : subCategoryListData.is_deleted,
'is_active' : subCategoryListData.is_active,
'image_name' : subCategoryListData.image_name,
'image_path' : subCategoryListData.image_path
}
CategoryService.getCategoryById(subCategoryListData.category_id).then(function(response1) {
console.log(response1.data);
subcategory.category = response1.data;
}, function(error) {
swal("Error", error.data, "error");
})
subCategoryDetails.push(subcategory);
}
console.log(JSON.stringify(subCategoryDetails));
}, function (error) {
swal("Error", "Something went wrong", "error");
});
}
CategoryService:
this.getCategoryById = function(id) {
return $http({
url: globalUrl.baseurl + 'category/getCategoryById/' + id,
method: 'GET'
})
}
in the above code i am tring to fetch data from CategoryService service and it successfully return the data within the CategoryService.getCategoryById function. Now i am trying to assign returned value by service to subcategory.category which is present in controller. but my problem is it is not updateing the value in subcategory.category.
my guess is:
you are pushing the new variabile inside the array BEFORE the API call is executed (because of the js callback), can you try something like:
CategoryService.getCategoryById(subCategoryListData.category_id)
.then(function(response1) {
console.log(response1.data);
subcategory.category = response1.data;
// PUSHING AFTER API RETURNS THE VALUE
subCategoryDetails.push(subcategory);
}, function(error) {
swal("Error", error.data, "error");
})
// subCategoryDetails.push(subcategory);
I tried components methods in vue js. My code like this.
const Thread = Vue.component('threadpage', function(resolve) {
$.get('templates/thread.html').done(function(template) {
resolve({
template: template,
data: function() {
return {
data: {
title: "Data Table",
count: this.GetData
}
};
},
methods: {
GetData: function() {
var data = {
username : "newshubid",
data : {
page : 0,
length : 10,
schedule : "desc"
}
};
var args = {"data" : JSON.stringify(data)};
var params = $.param(args);
var url = "http://example-url";
var result;
DoXhr(url, params, function(response){
result = JSON.parse(response).data;
console.log("load 1", result);
});
setTimeout(function () {
console.log("load 2", result);
return result;
}, 1000);
}
},
created: function(){
this.GetData();
}
});
});
});
But, when I trying to use {{ data.count }} in template. Not showing result what i want. Even I tried return result in GetData.
Whats my problem ? And how to access data from methods ? Please help me, i'm a beginner. Thanks
See the edited code and comments I added below.
You tried to return the result by using return in the function from setTimeout, which won't help you return value from GetData.
Instead, You can just set the value in the callback function of your ajax request.
const Thread = Vue.component('threadpage', function(resolve) {
$.get('templates/thread.html').done(function(template) {
resolve({
template: template,
data: function() {
return {
data: {
title: "Data Table",
// NOTE just set an init value to count, it will be refreshed when the function in "created" invoked.
count: /* this.GetData */ {}
}
};
},
methods: {
GetData: function() {
var data = {
username : "newshubid",
data : {
page : 0,
length : 10,
schedule : "desc"
}
};
var args = {"data" : JSON.stringify(data)};
var params = $.param(args);
var url = "http://example-url";
var result;
var vm = this;
DoXhr(url, params, function(response){
result = JSON.parse(response).data;
// NOTE set data.count to responsed result in callback function directly.
vm.data.count = result;
});
// NOTE I think you don't need code below anymore.
// setTimeout(function () {
// console.log("load 2", result);
// return result;
// }, 1000);
}
},
created: function(){
this.GetData();
}
});
});
});
I am using Parse to create a WebApp and I am trying to get an instance of an object Productwith this code:
getProduct: function() {
var productClass = Parse.Object.extend("Product");
var query = new Parse.Query(productClass);
var result = query.get(productId, {
success: function(object) {
console.log(object.get("productName"));
},
error: function(object, error) {
...
}
});
return result;
}
I get a:
result.get is not a function
Printing the object only, I realized that I do not get a Product, I get this in the console (Safari):
[Log] Object (views.js, line 269)
_rejected: false
_rejectedCallbacks: Array[0]
_resolved: true
_resolvedCallbacks: Array[0]
_result: Arguments[1]
__proto__: Object
I tried many ways, but I am not able to retrieve a Product object and its attributes. What am I doing wrong?
EDIT
I am adding my Products View:
window.app.Products = Parse.View.extend({
template: _.template($('#products-template').html()),
el: $('body'),
content: $('#content'),
...
initialize: function() {
_.bindAll(this, 'render');
this.render();
},
render: function () {
$(this.content).html(this.template);
return this;
},
...
getUser: function() {
return Parse.User.current();
},
getUserProduct: function() {
var promise = new Parse.Promise();
var productClass = Parse.Object.extend("Product");
var query = new Parse.Query(productClass);
query.equalTo("objectId", this.getUser().get("product").id);
query.first().then(function(result) {
if(result){
// If result was defined, the object with this objectID was found
promise.resolve(result);
} else {
console.log("Product was not found");
promise.resolve(null);
}
}, function(error){
console.error("Error searching for Product. Error: " + error);
promise.error(error);
});
return promise;
},
setProduct: function() {
this.getUserProduct().then(function(result) {
if(result){
console.log(result.get("productName"));
var productName = result.get("productName");
} else {
console.log("Could not set Product");
}
}, function(error){
console.log("Error: " + error);
});
}
});
I was trying by having a list of parameters and updating them like:
info: {
user: '...',
product: '...'
}
Then passing it to the template:
$(this.content).html(this.template(this.info));
But I am not able to update product.
As I wrote this, I realised that you really aren't saving all that much code by pulling the product search into it's own method. My hope is that it will at least demonstrate to you how to create and call your own custom async methods. For example you may have a query which is much more complex than the current query, or it may perform multiple queries before finding the desired response, in which case it would make sense to pull it into it's own method.
Get Product Async Method
This method retrieves the Product with the given objectID
var getProduct = function(productId) {
var promise = new Parse.Promise();
var Product = Parse.Object.extend("Product");
var query = new Parse.Query(Product);
query.equalTo("objectId",productId);
query.first().then(function(result){
if(result){
// If result was defined, the object with this objectID was found
promise.resolve(result);
} else {
console.log("Product ID: " + productId + " was not found");
promise.resolve(null);
}
}, function(error){
console.error("Error searching for Product with id: " + productId + " Error: " + error);
promise.error(error);
});
return promise;
}
Calling Method
An example of a simple method which calls the above method.
var myMethod = function(){
var productID = "12345678";
getProduct(productID).then(function(result){
if(result){
console.log(result.get("productName"));
var productName = result.get("productName");
var productPrice = result.get("productPrice");
// Now that you have some relevant information about your product
// you could render it out to an Express template, or use this
// value in a calculation etc.
} else {
console.log("Product with objectId: " + productID + " was not found");
}
}, function(error){
console.log("Error: " + error);
});
}
Notes
As these methods are asynchronous, there is no real data being
returned in the 'return value' (the method returns a promise).
Instead we return the relevant data as a result of the promise (where
you see promise.resolve(XXX))
It doesn't make any sense to have a
mutable global variable in this Node.js style architecture.
I think I'm writing my promise incorrectly and I couldn't figure out why it is caching data. What happens is that let's say I'm logged in as scott. When application starts, it will connect to an endpoint to grab listing of device names and device mapping. It works fine at this moment.
When I logout and I don't refresh the browser and I log in as a different user, the device names that scott retrieved on the same browser tab, it is seen by the newly logged in user. However, I can see from my Chrome's network tab that the endpoint got called and it received the correct listing of device names.
So I thought of adding destroyDeviceListing function in my factory hoping I'll be able to clear the values. This function gets called during logout. However, it didn't help. Below is my factory
app.factory('DeviceFactory', ['$q','User', 'DeviceAPI', function($q, User, DeviceAPI) {
var deferredLoad = $q.defer();
var isLoaded = deferredLoad.promise;
var _deviceCollection = { deviceIds : undefined };
isLoaded.then(function(data) {
_deviceCollection.deviceIds = data;
return _deviceCollection;
});
return {
destroyDeviceListing : function() {
_deviceCollection.deviceIds = undefined;
deferredLoad.resolve(_deviceCollection.deviceIds);
},
getDeviceIdListing : function() {
return isLoaded;
},
getDeviceIdMapping : function(deviceIdsEndpoint) {
var deferred = $q.defer();
var userData = User.getUserData();
// REST endpoint call using Restangular library
RestAPI.setBaseUrl(deviceIdsEndpoint);
RestAPI.setDefaultRequestParams( { userresourceid : userData.resourceId, tokenresourceid : userData.tokenResourceId, token: userData.bearerToken });
RestAPI.one('devices').customGET('', { 'token' : userData.bearerToken })
.then(function(res) {
_deviceCollection.deviceIds = _.chain(res)
.filter(function(data) {
return data.devPrefix != 'iphone'
})
.map(function(item) {
return {
devPrefix : item.devPrefix,
name : item.attributes[item.devPrefix + '.dyn.prop.name'].toUpperCase(),
}
})
.value();
deferredLoad.resolve(_deviceCollection.deviceIds);
var deviceIdMapping = _.chain(_deviceCollection.deviceIds)
.groupBy('deviceId')
.value();
deferred.resolve(deviceIdMapping);
});
return deferred.promise;
}
}
}])
and below is an extract from my controller, shortened and cleaned version
.controller('DeviceController', ['DeviceFactory'], function(DeviceFactory) {
var deviceIdMappingLoader = DeviceFactory.getDeviceIdMapping('http://10.5.1.7/v1');
deviceIdMappingLoader.then(function(res) {
$scope.deviceIdMapping = res;
var deviceIdListingLoader = DeviceFactory.getDeviceIdListing();
deviceIdListingLoader.then(function(data) {
$scope.deviceIDCollection = data;
})
})
})
Well, you've only got a single var deferredLoad per your whole application. As a promise does represent only one single asynchronous result, the deferred can also be resolved only once. You would need to create a new deferred for each request - although you shouldn't need to create a deferred at all, you can just use the promise that you already have.
If you don't want any caching, you should not have global deferredLoad, isLoaded and _deviceCollection variables in your module. Just do
app.factory('DeviceFactory', ['$q','User', 'DeviceAPI', function($q, User, DeviceAPI) {
function getDevices(deviceIdsEndpoint) {
var userData = User.getUserData();
// REST endpoint call using Restangular library
RestAPI.setBaseUrl(deviceIdsEndpoint);
RestAPI.setDefaultRequestParams( { userresourceid : userData.resourceId, tokenresourceid : userData.tokenResourceId, token: userData.bearerToken });
return RestAPI.one('devices').customGET('', { 'token' : userData.bearerToken })
.then(function(res) {
return _.chain(res)
.filter(function(data) {
return data.devPrefix != 'iphone'
})
.map(function(item) {
return {
devPrefix : item.devPrefix,
name : item.attributes[item.devPrefix + '.dyn.prop.name'].toUpperCase(),
};
})
.value();
});
}
return {
destroyDeviceListing : function() {
// no caching - nothing there to be destroyed
},
getDeviceIdListing : function(deviceIdsEndpoint) {
return getDevices(deviceIdsEndpoint)
.then(function(data) {
return { deviceIds: data };
});
},
getDeviceIdMapping : function(deviceIdsEndpoint) {
return this.getDeviceIdListing(deviceIdsEndpoint)
.then(function(deviceIds) {
return _.chain(deviceIds)
.groupBy('deviceId')
.value();
});
}
};
}])
Now, to add caching you'd just create a global promise variable and store the promise there once the request is created:
var deviceCollectionPromise = null;
…
return {
destroyDeviceListing : function() {
// if nothing is cached:
if (!deviceCollectionPromise) return;
// the collection that is stored (or still fetched!)
deviceCollectionPromise.then(function(collection) {
// …is invalidated. Notice that mutating the result of a promise
// is a bad idea in general, but might be necessary here:
collection.deviceIds = undefined;
});
// empty the cache:
deviceCollectionPromise = null;
},
getDeviceIdListing : function(deviceIdsEndpoint) {
if (!deviceCollectionPromise)
deviceCollectionPromise = getDevices(deviceIdsEndpoint)
.then(function(data) {
return { deviceIds: data };
});
return deviceCollectionPromise;
},
…
};