MapKitJS offers 250,000 free map calls per day at the current time (June 2021). This raises the question for me, what is counted as a call?
Is the call counted when the mapkit.init(...) method is called or when a new map instance is created?
For example, if I create two maps on my website with the methods:
const map1 = new mapkit.Map(container1, { ... } );
const map2 = new mapkit.Map(container2, { ... } );
but only call mapkit.init(...) once, does that still count as only one call or two?
Related
After a night of trial and error I have decided on a much simpler way to explain my issue. Again, I have no JS experience, so I don't really know what I am doing.
I have 5 classes:
game - holds information about my games
classification - holds information about the user classes available in games
game_classifications - creates a one game to many classifications relationship (makes a game have mulitple classes)
mission - holds my mission information
mission_class - creates a one to many relationship between a mission and the classes available for that mission
Using Cloud Code, I want to provide two inputs through my Rest API being missionObjectId and gameObjectId.
The actual steps I need the code to perform are:
Get the two inputs provided {"missionObjectId":"VALUE","gameObjectId":"VALUE"}
Search the game_classifications class for all records where game = gameObjectID
For each returned record, create a new record in mission_class with the following information:
mission_id = missionObjectId
classification = result.classification
Here is an image of the tables:
And here is how I have tried to achieve this:
Parse.Cloud.define("activateMission", async (request) => {
Parse.Cloud.useMasterKey();
const query = new Parse.query('game_classifications');
query.equalTo("gameObjectId", request.params.gameObjectId);
for (let i = 0; i < query.length; i ++) {
const mission_classification = Parse.Object.extend("mission_class");
const missionClass = new mission_classification();
missionClass.set("mission_id", request.params.missionObjectId);
missionClass.set("classification_id", query[i].classificationObjectId);
return missionClass.save();
}
});
Does anyone have any advice or input that might help me achieve this goal?
The current error I am getting is:
Parse.query is not a constructor
Thank you all in advance!
Some problems on your current code:
Parse.Cloud.useMasterKey() does not exist for quite a long time. Use useMasterKey option instead.
It's Parse.Query and not Parse.query.
You need to run query.findAll() command and iterate over it (and not over query).
For performance, move Parse.Object.extend calls to the beginning of the file.
To access the field of an object, use obj.get('fieldName') and not obj.fieldName.
If you return the save operation, it will save the first object, return, and not save the others.
So, the code needs to be something like this:
const mission_classification = Parse.Object.extend("mission_class");
const game = Parse.Object.extend("game");
Parse.Cloud.define("activateMission", async (request) => {
const query = new Parse.Query('game_classifications');
const gameObj = new game();
gameObj.id = request.params.gameObjectId;
query.equalTo("gameObjectId", gameObj);
const queryResults = await query.findAll({useMasterKey: true});
for (let i = 0; i < queryResults.length; i++) {
const missionClass = new mission_classification();
missionClass.set("mission_id", request.params.missionObjectId);
missionClass.set("classification_id", queryResults[i].get('classificationObjectId'));
await missionClass.save(null, { useMasterKey: true });
}
});
I have a component that displays balances for 4 separate tokens. I'd like to have a function like this:
async updateTokenBalance(token, balance) {
balance = await getTokenBalance(token);
balance = balance.value.uiAmount;
}
which I can call like so:
updateTokenBalance(this.a_acc, this.a_balance);
updateTokenBalance(this.b_acc, this.b_balance);
updateTokenBalance(this.c_acc, this.c_balance);
updateTokenBalance(this.d_acc, this.d_balance);
unfortunately this doesn't seem to work. The only way I've gotten it to work so far is by having 4 separate functions:
async updateATokenBalance() {
let balance = await getTokenBalance(this.a_acc);
this.a_balance = balance.value.uiAmount;
}
// the other 3 analogous
in particular, it's the second line of the function where I try to assign the balance to a data property of this.a_balance that breaks if this.a_balance is passed in as arg.
Is there a way to make it work?
If your data come from an API, you should iterate through the incoming object list and run the function for each item with the analogous arguments.
I'm creating laravel/vue.js CRUD app and I everything works fine for now but I'm worried about quality of my queries to database after update data.
I am using getAllData() each time when I update row in the database. Now, when I have a few records in database is not a problem to ask server each time and render new list in vue but in when I will have a few thousands of rows it will make my app slow and heavy.
Now I update database like this:
This is part of my vue.js update function:
updateStatus: function(id){
var index = _.findIndex(this.rows,["id",id]);
if (this.rows[index].pay_status=="waiting"){
axios.put("http://127.0.0.1:8000/api/payments/"+id
,{pay_status:"payed"}).then((response)=>{
this.getAllData();
}
This is my vue.js getAllData function:
getAllData: function(){
axios.get("http://127.0.0.1:8000/api/payments").then((response)=>{
this.rows = response.data;
});
}
and my PaymentsController:
namespace App\Http\Controllers;
use App\Payments;
use App\Suppliers;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Faker\Generator;
class PaymentsController extends Controller
{
public function index()
{
$payments = Payments::with('suppliers')->get();
return response($payments, Response::HTTP_OK);
}
}
my updation function:
public function update(Request $request, $id)
{
$payments = new Payments();
payments::where('id', $id)->update($request->all());
}
Is thare any way to make update in more efficient way, for example get only updated row from database and put it into my existing object with rows? Or maybe i should not worried about it?
Without seeing your logic:
Your controller can return the record:
return response(['payment' => $payment], Response::HTTP_OK);
Your axios method can observe that response and then do a replace on the index (just like you did when getting the index previously)
.then((response) => {
const { payment } = response.data;
this.items[index] = payment;
})
As long as items was instantiated in data as an [] then it's observable.
If you need updated rows for particular time period.
Also, you can do one thing. When user updating the row u can store the unique ID in new table and you can fetch the data through that ID. and then you can delete that ID from new table when you don't need latest updated data.
WHILE UPDATING THE ROW via ID
insert id in new table.
update the record.
if need updated record only >> use back-end conditions as per the
requirement >> Fetch id from new table join with main table.
when you don't need that latest updated record. Delete records from
new table. >> use back-end conditions as per the requirement >>
fetch from main table.
As #Ohgodwhy said, I change my code like this and now it works fine.
update function
public function update(Request $request, $id)
{
$payments = new Payments();
payments::where('id', $id)->update($request->all());
return response(payments::where('id', $id)->get(), Response::HTTP_OK);
}
axios
updateStatus: function(id){
var index = _.findIndex(this.rows,["id",id]);
if (this.rows[index].pay_status=="oczekuje"){
axios.put("http://127.0.0.1:8000/api/payments/"+id,{pay_status:"zapłacono"}).then((response)=>{
this.rows[index].pay_status=response.data[0].pay_status;
this.waitingInvoices = this.countInvoices();
this.toPay = this.calculatePayment();
});
} else if (this.rows[index].pay_status=="zapłacono"){
axios.put("http://127.0.0.1:8000/api/payments/"+id,{pay_status:"oczekuje"}).then((response)=>{
this.rows[index].pay_status=response.data[0].pay_status;
this.waitingInvoices = this.countInvoices();
this.toPay = this.calculatePayment();
});
}
},
I just started developing in Swift, so im totally new to closures. I'm also new how to handle asynchronous API request.
I have read a lot of similar question such as, How to get data to return from NSURLSessionDataTask in Swift and How to use completionHandler Closure with return in Swift?. These helped me, but my problem it a little bit different.
In my function I want to first make a API request to get a JSON payload. With some data in this JSON payload I want to make multiple other API request. In this case, I will for each of API request receive a JSON payload, where I want to store some of the data in my own JSON data structure.
The problem is that, for every multiple API request I make I can only return part of my own JSON data in my CompletionHandler - This is only way to return data when making an API request using a closure, as far as I understand.
So instead of getting multiple completion handlers, when calling my function, I just want to receive a single.
The thing is I dont know to how to completion handling several closures in a function, in this case two closures.
I have posted my code below - I know its quite long and maybe not that clean.
However, the point is that when im updating offers to my storeDict this will be empty, due to the offers dict array is getting its information from inside the second closure. This is shown at the bottom of the function.
func getOffersFromWishList(offerWishList: [String], latitude: Double, longitude: Double, radius: Int, completionHandler: ([NSDictionary] -> Void)) {
var master: [NSDictionary] = []
var nearby_params: NSDictionary = ["r_lat": latitude, "r_lng": longitude, "r_radius": radius]
//println(nearby_params)
var store_id_list: [String] = []
// Get all store_ids for store which are nearby (Radius determines how nearby)
singleton_eta.api("/v2/stores", type: ETARequestTypeGET, parameters: nearby_params, useCache: true, completion: { (response, error, fromCache) -> Void in
if error == nil {
let json = JSON(response)
storeArray = json.arrayValue
//println(storeArray)
for store in storeArray {
var storeDict = [String: AnyObject]()
var metaData = [String: String]()
var offers: [NSDictionary] = []
let name = store["branding"]["name"].stringValue
let store_id = store["id"].stringValue
let street = store["street"].stringValue
let city = store["city"].stringValue
let zip_code = store["zip_code"].stringValue
let dealer_id = store["dealer_id"].stringValue
let logo = store["branding"]["logo"].stringValue
metaData = ["name": name, "store_id": store_id, "street": street, "city": city, "zip_code": zip_code, "dealer_id": dealer_id, "logo": logo]
store_id_list.append(store_id)
//println("Butiks ID: \(store_id)")
var offset = 0
let limit = 100
// Loop through the offers for the specific store id - only possible to request 100 offers each time
// A while loop would be more suitable, but I dont know when to stop, as the length of the offerArray can not be counted as it is cant be accessed outside of the closure.
for x in 1...2 {
var store_params: NSDictionary = ["store_ids:": store_id, "limit": limit, "offset": offset]
println(store_params)
// Get offers for a specific store_id
singleton_eta.api("/v2/offers", type: ETARequestTypeGET, parameters: store_params, useCache: true, completion: { (response, error, fromCache) -> Void in
if error == nil {
offerArray = JSON(response).arrayValue
//println( "TypeName0 = \(_stdlib_getTypeName(offerArray))")
//Loop through the recieved offers
for of in offerArray {
let name = of["branding"]["name"].stringValue
let dealer_id = of["dealer_id"].stringValue
let heading = of["heading"].stringValue
let description = of["description"].stringValue
let price = of["pricing"]["price"].stringValue
let image = of["images"]["view"].stringValue
//println(heading)
// Loop through our offerWishList
for owl in offerWishList {
let headingContainsWish = (heading.lowercaseString as NSString).containsString(owl.lowercaseString)
// Check if offer match with our wish list
if(headingContainsWish) {
// Save neccesary meta data about each offer to a tuple array
var offer = Dictionary<String, String>()
offer = ["name": name, "dealer_id": dealer_id, "heading": heading, "description": description, "price": price, "image": image, "offerWishItem": owl]
offers.append(offer)
}
}
}
}
})
//println(storeDict)
offset = offset + limit + 1
}
storeDict.updateValue(metaData, forKey: "meta_data")
storeDict.updateValue(offers, forKey: "offers") // offers is empty due to its appending inside the closure
master.append(storeDict)
}
completionHandler(master)
}
else {
println(error)
}
})
}
Calling the above function
getOffersFromWishList(offerWishList, latitude, longitude, radius) { (master) -> Void in
println(master)
}
This is what the master will print when calling the function, where offers is empty.
{
"meta_data" = {
city = "Kongens Lyngby";
"dealer_id" = d8adog;
logo = "https://d3ikkoqs9ddhdl.cloudfront.net/img/logo/default/d8adog_3qvn3g8xp.png";
name = "d\U00f8gnNetto";
"store_id" = d2283Zm;
street = "Kollegiebakken 7";
"zip_code" = 2800;
};
offers = (
);
}
{
...
}
So my questions, what is the proper way to return data from the second closure to the first closure inside a function? Or am I doing this in the completely wrong way?
The thing is, I need all this data for a tableview and therefore need all the data at once.
A couple of thoughts:
If there's any possibility of returning all of this in a single request to the server, that might offer better performance. Often, the time required to performing the requests on server is inconsequential in comparison to the network latency. If you can avoid needing to make one request, get a response, and then issue more requests, that would be ideal.
Or perhaps you request the locations within some distance in advance, cache that, and then the "show me deals for nearby locations" might not require these two sets of requests.
(I recognize that neither of these may work for you, but it's something to consider if you can. If you can eliminate consecutive requests and focus on largely concurrent requests, you'll have much better performance.)
Let's assume for a second that the above is not an option, and you're stuck with one request to get the nearby locations and another set to get the deals. Then you have a couple of options:
You can definitely go down the road that you're contemplating with a single callback. You can, for example, issue all of your requests, doing a dispatch_group_enter before you initiate each request, do a dispatch_group_leave upon the completion of each request, and then issue a dispatch_group_notify that will be called when each enter call has been offset by a corresponding leave call. So, build your response object as each request finishes, and only when they're done, call the completion closure.
Another approach would be to have a closure that behaves more like an enumeration closure, one that is called as each site's deals come in. That way, the UI can be updated as things come in, rather than waiting for everything. If you're on a slow network, updating the UI as data comes in may be far more tolerable. (E.g., consider ten requests, each which takes 1 second complete on a slow 3G cellular connection: watching them pop in one per second is far more tolerable than seeing nothing for ten seconds).
Having said that, you may want to abandon closures completely. You could consider a delegate-protocol pattern, where you specify a delegate for your request, and then implement protocol methods for each of the responses you get from the server. That way you can update the UI as new responses come in, rather than holding everything up until the last one comes in. But we're recognizing that there are very different types of responses (one is a list of sites, another is the list deals for a given site, a third would be the "I'm all done" and/or "there was an error), so when it starts to get this complicated, it might be better to define a protocol for this interface, and handle it that way.
I am trying to develop a search filter and making use of the HTML5 history API to reduce the number of requests sent to the server. If the user checks a checkbox to apply a certain filter I am saving that data in the history state, so that when the user unchecks it I am able to load the data back from the history rather than fetching it again from the server.
When the user checks or unchecks a filter I am changing the window URL to match the filter that was set, for instance if the user tries to filter car brands only of a certain category I change the URL like 'cars?filter-brand[]=1'.
But when mutiple filters are applied I have no way of figuring out whether to load the data from the server or to load it from the history.
At the moment I am using the following code.
pushString variable is the new query string that will be created.
var back = [],forward = [];
if(back[back.length-1] === decodeURI(pushString)){ //check last back val against the next URL to be created
back.pop();
forward.push(currentLocation);
history.back();
return true;
}else if(forward[forward.length-1] === decodeURI(pushString)){
forward.pop();
back.push(currentLocation);
history.forward();
return true;
}else{
back.push(currentLocation); //add current win location
}
You can check if your filters are equivalent.
Comparing Objects
This is a simple function that takes two files, and lets you know if they're equivalent (note: not prototype safe for simplicity).
function objEqual(a, b) {
function toStr(o){
var keys = [], values = [];
for (k in o) {
keys.push(k);
values.push(o[k]);
}
keys.sort();
values.sort();
return JSON.stringify(keys)
+ JSON.stringify(values);
}
return toStr(a) === toStr(b);
}
demo
Using the URL
Pass the query part of the URL (window.location.search) to this function. It'll give you an object you can compare to another object using the above function.
function parseURL(url){
var obj = {}, parts = url.split("&");
for (var i=0, part; part = parts[i]; i++) {
var x = part.split("="), k = x[0], v = x[1];
obj[k] = v;
}
return obj;
}
Demo
History API Objects
You can store the objects with the History API.
window.history.pushState(someObject, "", "someURL")
You can get this object using history.state or in a popState handler.
Keeping Track of Things
If you pull out the toStr function from the first section, you can serialize the current filters. You can then store all of the states in an object, and all of the data associated.
When you're pushing a state, you can update your global cache object. This code should be in the handler for the AJAX response.
var key = toStr(parseUrl(location.search));
cache[key] = dataFromTheServer;
Then abstract your AJAX function to check the cache first.
function getFilterResults(filters, callback) {
var cached = cache[toStr(filters)]
if (cached != null) callback(cached);
else doSomeAJAXStuff().then(callback);
}
You can also use localstorage for more persistent caching, however this would require more advanced code, and expiring data.