Zapier.com zipcode autofill city and state - javascript

We are using zapier.com to connect many programs, but one function that I need is to autofill the city and state from a zip code. This is available in zapier.com as setup Code by Zapier Run Javascript. I can't seem to figure this out and any help is much appreciated.
<script type="text/javascript">//<![CDATA[
$(function() {
// IMPORTANT: Fill in your client key
var clientKey; // Deleted for Stack Overflow
var cache = {};
var container = $("#example1");
var errorDiv = container.find("div.text-error");
/** Handle successful response */
function handleResp(data)
{
// Check for error
if (data.error_msg)
errorDiv.text(data.error_msg);
else if ("city" in data)
{
// Set city and state
container.find("input[name='city']").val(data.city);
container.find("input[name='state']").val(data.state);
}
}
// Set up event handlers
container.find("input[name='zipcode']").on("keyup change", function() {
// Get zip code
var zipcode = $(this).val().substring(0, 5);
if (zipcode.length == 5 && /^[0-9]+$/.test(zipcode))
{
// Clear error
errorDiv.empty();
// Check cache
if (zipcode in cache)
{
handleResp(cache[zipcode]);
}
else
{
// Build url
var url = "https://www.zipcodeapi.com/rest/"+clientKey+"/info.json/" + zipcode + "/radians";
// Make AJAX request
$.ajax({
"url": url,
"dataType": "json"
}).done(function(data) {
handleResp(data);
// Store in cache
cache[zipcode] = data;
}).fail(function(data) {
if (data.responseText && (json = $.parseJSON(data.responseText)))
{
// Store in cache
cache[zipcode] = json;
// Check for error
if (json.error_msg)
errorDiv.text(json.error_msg);
}
else
errorDiv.text('Request failed.');
});
}
}
}).trigger("change");
});
//]]></script>

It looks like you're trying to use client-side JavaScript here. This won't work in a Zapier code step because it's meant to be used in a browser (on a webpage). To make an HTTP request in a Zapier code step, you'll want to use fetch (here's some documentation on that).
Alternatively, the simplest way to get the data you need from that API is with a Webhook step:
Add a step to your Zap
Choose Webhooks by Zapier and select the GET action
Set up that step like this. The step will return city/state data which you can use in subsequent steps

There are a couple points of confusion here, the main one being:
Code by Zapier is not run "in the browser" (there is no <script> tags or Jquery) - it is run in something called Node.js.
You'll need to approach the problem completely differently as a result - definitely take a look at the samples found in https://zapier.com/help/code/ and at the Node docs https://nodejs.org/docs/v4.3.2/api/.

Related

Most browsers do not 'remember' the result of Ajax request when going back to page

I have a page with a form that gives a user the option to filter a list of objects (programs) by selecting options. For example, they could select the option architecture to show only the programs which contain that subject. An AJAX-request is sent to the server, which then returns the results. So far, everything works.
My problem: in some browser when someone clicks to go to another page and then goes back to the page where the form is, the results are reset, although the form selection(s) are still visible. In Chrome this is a problem, whereas in Firefox this does not happen. On this page you can see a live example.
My JavaScript AJAX post-request looks like this:
let sendQuery = () => {
let programsList = document.getElementById('programs-list');
axios.post('/programs/getByFilter', filter )
.then(function (response) {
programsList.innerHTML = response.data;
})
.catch(function (error) {
console.log(error);
});
}
And then in PHP (I use Symfony):
/**
* #Route("/getByFilter", name="program_get_by_filter")
*/
public function returnProgramsByFilter(Request $request, SearchHelper $searchHelper)
{
$jsonFilter = $request->getContent();
$filter = json_decode($jsonFilter, true);
// the query is done here.
$programs = $searchHelper->findByFilter($filter);
return $this->render('program/programs_ajax.html.twig', [
'programs' => $programs ]);
}
Now I have looked for similar questions and found this one and this one, but I haven't been able to solve the problem. Initially I tried to send the request as a GET-request instead of a POST-request, but the data I send is JSON and I did not manage to make it work. I am not really sure if that has to do with the JSON or not. My understanding of JS is really poor. Then I tried with a session variable like so:
$jsonFilter = $request->getContent();
$filter = json_decode($jsonFilter, true);
$session->set('filter', $filter);
And then:
if($session->has('filter')){
$programs = $searchHelper->findByFilter($session->get('filter'));
} else {
$programs = $programRepository->findAll();
}
This does not really work either because the original options will be overwritten when going back and making a new selection. Also, with my JS I show the current filters that are being used and the number of results. That's gone too.
Is there a JS solution or should I try to fix this in PHP?
Update:
I have been able to set filter as a cookie every time an ajax call is made by making it a string with JSON.stringify(filter) and then I get it and use it with:
// Getting the cookie, parsing it and running the query.
var filterCookie = getCookie('filter');
if (filterCookie) {
var objectCookieFilter = JSON.parse(filterCookie);
let programsList = document.getElementById('programs-list');
axios
.post('/programs/getByFilter', objectCookieFilter )
.then(function (response) {
programsList.innerHTML = response.data;
})
.catch(function (error) {
console.log(error);
});
}
This will re-run the last query that was set in the cookie. The problem that remains though is that all the filter-badges are set on a change event of the checkboxes and I cannot figure out how to show them based on the cookie (or perhaps some other way?)

Problems with fetch and XMLHttpRequest

The first thing is that I'm a noob and I know it... Maybe you think this is a repeated question but I read a lot of posts about the same question but no one helped.
I'm trying to develop a web application about working orders, clients, providers, etc... I have a Rest API with the proper routes connected to a database (mysql), and the logic with the CRUM methods. I'm still working on the server part and until some days ago everything went fine, since I tested this first with Postman and then with some simple tests and everything is working well.
The thing is I'm trying to develop the logic (the real one) of my application to access to some individual elements of the json object (the API returns an array, but that's not the problem). I need to check and generate the serial number of the working orders with this format 'number/year'. I tried with both fetch() and XMLHttpRequest to access the data and nothing works.... I can't access to the elements of the array because I always have something wrong.
If I try this inside if my tests using fetch() it works but if I try this inside my numeroOT() method I can't, I don't know what else to do so I need help please... I'm going crazy with this thing!!
This is the code that works IN MY TEST:
describe('TEST logica.js', function () {
it('Genero el NÂș de Orden', async () => {
var numeroDeOT = laLogica.numeroOT(); //this is the method of my logic I'm testing and it's suposed to do the thing
//This is the the only code which I could acceed to the json. But this has to go inside the numeroOT() method but only works in the test
//-------------------------------------------
var response = await fetch('http://localhost:3000/ots');
var orden = await response.json();
var laOrden = orden[orden.length-1]; //the last element/json object of the array
var elNumero = laOrden.numero_ot; //the element I want to check and generate
console.log(elNumero);
//The code to check this element and generate the new one goes down here but that's clear
//---------------------------------------------
console.log(numeroDeOT);
expect(numeroDeOT).to.be.a('String'); //this is to check what my method numeroOT() returns. Usually 'undefined'
}) //it
}); //describe
I realized that the two ways I was trying in my code there weren't possible to use them with node (since I'm using node), so I tried this code into my method and it works perfectly and I finally can access to my array of JSON objects!
var options = {
host : 'localhost',
port : 3000,
path : '/ots', // the rest of the url with parameters if needed
method : 'GET' // do GET
};
var request = http.request(options, function (res) {
console.log("request received");
var data = '';
res.on('data', function (chunk) {
data += chunk;
});
res.on('end', function () {
console.log(data);
});
});
request.on('error', function (e) {
console.log(e.message);
});
request.end();

Get Cloudflare's HTTP_CF_IPCOUNTRY header with javascript?

There are many SO questions how to get http headers with javascript, but for some reason they don't show up HTTP_CF_IPCOUNTRY header.
If I try to do with php echo $_SERVER["HTTP_CF_IPCOUNTRY"];, it works, so CF is working just fine.
Is it possible to get this header with javascript?
#Quentin's answer stands correct and holds true for any javascript client trying to access server header's.
However, since this question is specific to Cloudlfare and specific to getting the 2 letter country ISO normally in the HTTP_CF_IPCOUNTRY header, I believe I have a work-around that best befits the question asked.
Below is a code excerpt that I use on my frontend Ember App, sitting behind Cloudflare... and varnish... and fastboot...
function parseTrace(url){
let trace = [];
$.ajax(url,
{
success: function(response){
let lines = response.split('\n');
let keyValue;
lines.forEach(function(line){
keyValue = line.split('=');
trace[keyValue[0]] = decodeURIComponent(keyValue[1] || '');
if(keyValue[0] === 'loc' && trace['loc'] !== 'XX'){
alert(trace['loc']);
}
if(keyValue[0] === 'ip'){
alert(trace['ip']);
}
});
return trace;
},
error: function(){
return trace;
}
}
);
};
let cfTrace = parseTrace('/cdn-cgi/trace');
The performance is really really great, don't be afraid to call this function even before you call other APIs or functions. I have found it to be as quick or sometimes even quicker than retrieving static resources from Cloudflare's cache. You can run a profile on Pingdom to confirm this.
Assuming you are talking about client side JavaScript: no, it isn't possible.
The browser makes an HTTP request to the server.
The server notices what IP address the request came from
The server looks up that IP address in a database and finds the matching country
The server passes that country to PHP
The data never even goes near the browser.
For JavaScript to access it, you would need to read it with server side code and then put it in a response back to the browser.
fetch('https://cloudflare-quic.com/b/headers').then(res=>res.json()).then(data=>{console.log(data.headers['Cf-Ipcountry'])})
Reference:
https://cloudflare-quic.com/b
https://cloudflare-quic.com/b/headers
Useful Links:
https://www.cloudflare.com/cdn-cgi/trace
https://github.com/fawazahmed0/cloudflare-trace-api
Yes you have to hit the server - but it doesn't have to be YOUR server.
I have a shopping cart where pretty much everything is cached by Cloudflare - so I felt it would be stupid to go to MY server to get just the countrycode.
Instead I am using a webworker on Cloudflare (additional charges):
addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request))
})
async function handleRequest(request) {
var countryCode = request.headers.get('CF-IPCountry');
return new Response(
JSON.stringify({ countryCode }),
{ headers: {
"Content-Type": "application/json"
}});
}
You can map this script to a route such as /api/countrycode and then when your client makes an HTTP request it will return essentially instantly (for me it's about 10ms).
/api/countrycode
{
"countryCode": "US"
}
Couple additional things:
You can't use webworkers on all service levels
It would be best to deploy an actual webservice on the same URL as a backup (if webworkers aren't enabled or supported or for during development)
There are charges but they should be neglibible
It seems like there's a new feature where you can map a single path to a single script. That's what I am doing here. I think this used to be an enterprise only feature but it's now available to me so that's great.
Don't forget that it may be T1 for TOR network
Since I wrote this they've exposed more properties on Request.cf - even on lower priced plans:
https://developers.cloudflare.com/workers/runtime-apis/request#incomingrequestcfproperties
You can now get city, region and even longitude and latitude, without having to use a geo lookup database.
I've taken Don Omondi's answer, and converted it to a promise function for ease of use.
function get_country_code() {
return new Promise((resolve, reject) => {
var trace = [];
jQuery.ajax('/cdn-cgi/trace', {
success: function(response) {
var lines = response.split('\n');
var keyValue;
for (var index = 0; index < lines.length; index++) {
const line = lines[index];
keyValue = line.split('=');
trace[keyValue[0]] = decodeURIComponent(keyValue[1] || '');
if (keyValue[0] === 'loc' && trace['loc'] !== 'XX') {
return resolve(trace['loc']);
}
}
},
error: function() {
return reject(trace);
}
});
});
}
usage example
get_country_code().then((country_code) => {
// do something with the variable country_code
}).catch((err) => {
// caught the error, now do something with it
});

Lotus notes automation from browser

I have been trying to automate Lotus Notes mail fillup from a browser interface.
After refering to Richard Schwartz's answer, i came up with this piece of code using the Lotus.NotesSession class.
function SendScriptMail() {
var mToMail = document.getElementById('txtMailId').value
var mSub = document.getElementById('txtSubject').value
var mMsg = document.getElementById('txtContent').value
var Password = "yyy"
alert("1");
var MailFileServer = "xxx.com"
var MailFile = "C:\Program Files\IBM\Lotus\Notes\mail\user.nsf"
alert("2")
var Session;
var Maildb;
var UI;
var NewMail;
var From = "user#xxx.com"
try {
alert("3")
// Create the Activex object for NotesSession
Session = new ActiveXObject("Lotus.NotesSession");
alert("4")
if (Session == null) {
throw ("NoSession");
} else {
Session.Initialize(Password);
// Get mail database
Maildb = Session.GetDatabase(MailFileServer, MailFile);
alert("5")
if (Maildb == null) {
throw ("NoMaildb");
} else {
NewMail = MailDB.CreateDocument();
if (MailDoc == null) {
throw ('NoMailDoc');
} else {
// Populate the fields
NewMail.AppendItemValue("Form", "Memo")
NewMail.AppendItemValue("SendTo", mToMail)
NewMail.AppendItemValue("From", From)
NewMail.AppendItemValue("Subject", mSub)
NewMail.AppendItemValue("Body", mMsg)
NewMail.Save(True, False)
NewMail.Send(False)
}
}
}
} catch (err) {
// feel free to improve error handling...
alert('Error while sending mail');
}
}
But now, alerts 1,2,3 are being trigerrd, and then the counter moves to the catch block. The lotus notes session is not being started.
In a powershell script that I was previously looking at there was a code regsvr32 "$NotesInstallDir\nlsxbe.dll" /s that was used before the Session = new ActiveXObject("Lotus.NotesSession");. Is there something similar in javascript too, if so how do i invoke that dll.
I think I've realised where I am going wrong. According to me, upto alert("5") things are good. But since Lotus.NotesSession doesn't have a CreateDocument() method, it is throwing the error. I am not sure how to create the document and populate the values though.
Since you've chosen to use the Notes.NotesUIWorkspace class, you are working with the Notes client front-end. It's running, and your users see what's happening on the screen. Are you aware that there's a set of back-end classes (rooted in Lotus.NotesSession) instead of Notes.NotesSession and Notes.NotesUIWorkspace) that work directly with Notes database data, without causing the Notes client to grab focus and display everything that you're doing?
Working with the front-end means that in some cases (depending on the version of Notes that you are working with) you're not going to be working directly with the field names that are standard in Notes messages as stored and as seen in the back-end. You're going to be working with names used as temporary inputs in the form that is used to view and edit the message. You can see these names by using Domino Designer to view the Memo form.
Instead of using 'SendTo', try using:
MailDoc.Fieldsettext('EnterSendTo', mToMail)
Regarding the Body field, there's no temporary field involved, however you haven't really explained the difficulty you are having. Do you not know how to display the interface that you want in the browser? Do you not know how to combine different inputs into a single FieldSetText call? Or are you just dissatisfied with the fact that FieldSetText can't do any fancy formatting? In the latter case, to get more formatting capability you may want to switch to using the back-end classes, which give you access to the NotesRichTextItem class, which has more formatting capabilities.

'POST 400 bad request' error when updating parse.com table

I am getting a 'POST 400 bad request' error when trying to update a table on parse.com using JS SDK.
var Gallery = Parse.Object.extend("Gallery");
var gallery = new Gallery();
var activeArtworks = 0;
gallery.save(null, {
success: function(gallery) {
gallery.set("activeArtworks", activeArtworks);
gallery.save();
}
});
Please help!
I can't see how this is any different to the sample code provided by parse here
The sample code you reference creates all of its parameters before setting up the save() method. This is the step you're missing; you need to create the activeArtworks parameter on your gallery instance. Your update is failing because you're trying to update a property that was never created.
I would expect this code to work, though I didn't test it because parse.com requires you to set up an account to run any code, which is silly, and I didn't feel like creating one:
var Gallery = Parse.Object.extend("Gallery");
var gallery = new Gallery();
var activeArtworks = 0;
gallery.activeArtworks = []; // or some more appropriate default if you have one.
gallery.save(null, {
success: function(gallery) {
gallery.set("activeArtworks", activeArtworks);
gallery.save();
}
});
It might also be worth checking if there's any info in the headers of the 400 error (the debug console in your browser will show these in its Network tab). I would expect Parse to give you some sort of information to help you debug issues, and that's the only place it would fit for an HTTP error.
If you had use user.logIn(callback) function with Parse JS, maybe your session invalid. Please check your callback function error code, if error.code==209 (invalid session token), use Parse.User.logOut() and re-login again.
Like this:
if (error.code == 209) {
Parse.User.logOut();
user.logIn(loginCallback);
return;
}
I had this same issue and it was resolved after realising that the data type that I was posting was different to that specified in the columns that I had created.
In my case, I was trying to save an object when I had specified an array when creating the column in the class.

Categories